关于 Golang 和 Python 设计数据结构思维的区别 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Lighthughjiajin
V2EX    程序员

关于 Golang 和 Python 设计数据结构思维的区别

  •  
  •   Lighthughjiajin 2023-05-17 21:13:38 +08:00 1949 次点击
    这是一个创建于 957 天前的主题,其中的信息可能已经有所发展或是发生改变。
    from abc import ABC, abstractmethod class Device(ABC): @abstractmethod def fn(self): raise NotImplementedError def sync(self): print("Start Sync ...") self.fn() print("Start Done.") class PC(Device): def fn(self): print("PC Device fn!!!") class Router(Device): def fn(self): print("Router Device sync") def start_sync(d: Device): d.sync() if __name__ == '__main__': p = PC() r = Router() start_sync(p) # Run p.fn() start_sync(r) # Run r.fn() 

    请熟悉 Go 的大佬指导下,在 Go 中如何用接口与结构体实现类似的功能?(子类只需要重写 fn 方法,在 start_sync 处调用基类的 sync 时,能调用到子类重写后的 fn 方法)

    11 条回复    2023-05-18 00:33:27 +08:00
    dushixiang
        1
    dushixiang  
       2023-05-17 21:20:15 +08:00
    golang 不支持方法重载。

    https://go.dev/doc/faq#overloading

    > 为什么 Go 不支持方法和运算符的重载?
    > 如果方法分派也不需要进行类型匹配,则它会得到简化。使用其他语言的经验告诉我们,具有相同名称但不同签名的各种方法偶尔有用,但在实践中也可能令人困惑和脆弱。仅按名称匹配并要求类型一致是 Go 类型系统中的一个主要简化决策。

    > 关于运算符重载,它似乎比绝对要求更方便。同样,没有它,事情会更简单。
    Alias4ck
        2
    Alias4ck  
       2023-05-17 21:29:44 +08:00
    语言的转换 你问 chatgpt 可能一下就搞定了
    Contextualist
        4
    Contextualist  
       2023-05-17 22:06:51 +08:00   1
    Go 的 interface 和 struct 那一套鼓励的是组合 (composition) 而不是继承,所以像 PC 和 Router 这种实现具体功能的类是会被作为 Device 这种实现公共方法的类的**一部分**,就是 Device 包裹住 PC 或 Router 。下面是我个人认为的对应 Go 的地道解决办法: https://go.dev/play/p/wio55S6HtdK
    lesismal
        5
    lesismal  
       2023-05-17 22:14:20 +08:00
    Lighthughjiajin
        6
    Lighthughjiajin  
    OP
       2023-05-17 22:16:44 +08:00
    @Contextualist 终于看到比较地道的写法,是我想了解的。
    还有一点疑问,在这场景下,IDevice, Device 结构体、接口的命名有什么约定吗?
    Lighthughjiajin
        7
    Lighthughjiajin  
    OP
       2023-05-17 22:20:39 +08:00
    @Contextualist 这个写法下,有个缺点,Router 无法重写 Device 的 sync 方法,类似于以下 Python 代码
    ```
    from abc import ABC, abstractmethod


    class Device(ABC):

    @abstractmethod
    def fn(self):
    raise NotImplementedError

    def sync(self):
    print("Start Sync ...")
    self.fn()
    print("Start Done.")


    class PC(Device):

    def fn(self):
    print("PC sync")


    class Router(Device):

    def fn(self):
    print("Router Device sync")

    def sync(self):
    print("Router 重写了 sync")
    super().sync()
    print("Router sync ...")


    def start_sync(d: Device):
    d.sync()


    if __name__ == '__main__':
    r = Router()
    start_sync(r) # Run r.fn()
    start_sync(PC())

    ```
    Contextualist
        8
    Contextualist  
       2023-05-17 22:47:54 +08:00
    @Lighthughjiajin 嗯对,为了清晰对应你的例子我尽量沿用了你的命名。Go 里的 Interface 一般都是“动词 + er”来命名。假设我把 fn 重命名为 act ,那接口就叫 Actor 或者 DeviceActor ,对应的实现叫 PCActor 和 RouterActor 。

    关于你提到的无法重写 sync 方法的问题,这意味着在你的业务逻辑里 sync 并不是只有一个实现,那就应该也把它列进接口里。根据不同情况,可以开一个新的 interface ,也可以加进 IDevice 。
    - 开一个新的 interface 那就可以实现一个 type DefaultSyncer struct{},只是初始化 Device 时得传两个值
    - 加进 IDevice 就是强制要求每一个具体实现都要实现 sync
    Lighthughjiajin
        9
    Lighthughjiajin  
    OP
       2023-05-17 23:33:07 +08:00
    @Contextualist 感谢大佬,我整理了一下。
    https://go.dev/play/p/Z5Hl57w5XdF
    看看我理解的对吗?
    Contextualist
        10
    Contextualist  
       2023-05-18 00:23:39 +08:00
    @Lighthughjiajin 免大佬。基本没问题,就是注意一下依赖关系,Syncer 单方面依赖 Actor ,22 行是没必要的。

    不过这个玩具例子有点过于复杂了,但愿你在实际应用中不会经常遇到这种情况。
    Lighthughjiajin
        11
    Lighthugjiajin  
    OP
       2023-05-18 00:33:27 +08:00 via iPhone
    我写的是组合多个结构体来满足函数的 Device 接口参数要求,我看你写的是组合多个结构体来调用 sync ,也就是最终都是同一个类型,就是一个结构体。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5163 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 05:50 PVG 13:50 LAX 21:50 JFK 00:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86