V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
fujianjian
V2EX  ›  Go 编程语言

请教下用这种方式解决 import cycle 有什么弊端吗?

  •  
  •   fujianjian · 2022-07-30 08:02:31 +08:00 · 1757 次点击
    这是一个创建于 851 天前的主题,其中的信息可能已经有所发展或是发生改变。
    package a
    
    import (
    	"fmt"
    	"cc/c"
    )
    
    func Out() {
    	fmt.Println(c.GetB())
    }
    
    func GetA() string {
    	return "a"
    }
    
    
    func init() {
    	c.GetA = GetA
    }
    
    package b
    
    import (
    	"fmt"
    	"cc/c"
    )
    
    func Out() {
    	fmt.Println(c.GetA())
    }
    
    func GetB() string{
    	return "b"
    }
    
    func init() {
    	c.GetB = GetB
    }
    
    package c
    
    var GetA func()string
    var GetB func()string
    

    就是 a 和 b 在 init 的时候, 向 c 注册, c 不引任何包, 这样的做有什么问题吗?

    sadfQED2
        1
    sadfQED2  
       2022-07-30 10:16:31 +08:00 via Android
    你这个难道能编译通过? GetA 不是一个函数吗,你怎么能给函数赋值?
    jinliming2
        2
    jinliming2  
       2022-07-30 11:08:27 +08:00 via iPhone
    @sadfQED2 GetA 看着是个函数指针啊?😯
    janxin
        3
    janxin  
       2022-07-30 14:02:44 +08:00 via iPhone
    可以是可以,但是你未来很难保证你的这个包只有函数和基本类型吧
    fujianjian
        4
    fujianjian  
    OP
       2022-07-30 15:28:51 +08:00
    @janxin 是的, 但是包里有几个方法很难再拆包了, 社交的业务代码比较杂乱, 暂时采取这种丑陋的方式
    mauve
        6
    mauve  
       2022-07-31 20:03:31 +08:00
    也许不用写这么复杂,这不就是个全局变量吗?
    用全局变量解决 import cycle 好吗?不好
    fujianjian
        7
    fujianjian  
    OP
       2022-07-31 22:19:22 +08:00
    @katsusan 我上面写的办法应该跟 cockroachdb 的 Dependency injection 的方案是类似的 :)
    fujianjian
        8
    fujianjian  
    OP
       2022-07-31 22:20:25 +08:00
    @mauve 所以也一直觉得比较丑陋, 但是更好的办法也还没找到
    mauve
        9
    mauve  
       2022-08-01 01:00:10 +08:00
    我想到的三种做法,越往后的越好
    1. 包下拆分子包,a 引入 a 下的子包 c ,b 作为与 a 同级别包也引入 a 包下的子包 c ; c 内尽量保持简洁不额外依赖,很多 model 包会这么做
    2. 使用 wire 或者类似依赖注入的方案 ,https://github.com/google/wire ,wire 将所有依赖按照 hierarchy 汇总成一个 Application ,向面向对象一样,方法调用时尽量调用 Method 而不是 Function
    3. 在 2. 的基础上拆分业务逻辑,面向接口编程,向 5 楼发的一样,将一些类似的业务逻辑提取成 Interface ,a 包 b 包皆依赖于 c 包中的 Interface ,而不必关心相互是否实现

    另外,还是尽量避免使用 init 吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3441 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 18ms · UTC 11:19 · PVG 19:19 · LAX 03:19 · JFK 06:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.