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

关于如何在 Golang 中实现抽象类

  •  
  •   LoremIpSum · 2022-06-13 01:48:25 +08:00 · 3243 次点击
    这是一个创建于 899 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设现在我们定义了一个接口I,有两个方法Foo,Bar, 结构体Parent实现了 Foo,而Bar作为抽象方法由子类实现, 示例代码如下:

    package main
    
    type I interface {
    	Foo()
    	Bar() 
    }
    
    type Parent struct {
    	I
    }
    
    func (p *Parent) Foo() {
    	p.Bar()
    }
    
    
    
    type Child struct {
    	Parent
    }
    
    func (c *Child) Bar() {
    	fmt.Println("Child.Bar()")
    }
    
    func main() {
    	c := &Child{
    		Parent: Parent{},
    	}
    	c.I = c // 如果注释掉这几句会提示空指针异常
    	c.Foo()
    }
    
    

    输出如下:

    Child.Bar()
    

    问题: 1.上面的代码实现了类似Java风格的抽象类,但是在main方法中的这句代码没看懂c.I = c,这句代码的本质是做了什么事情?为什么c.I = c就会报空指针异常

    11 条回复    2022-06-14 09:38:42 +08:00
    doomfirst
        1
    doomfirst  
       2022-06-13 02:18:19 +08:00
    你不觉得你为了在 go 实现 java 的抽象类 写的很别扭么?
    akaHenry
        2
    akaHenry  
       2022-06-13 02:57:18 +08:00   ❤️ 7
    不要用 Java 的思维来写 Go.

    理解好 Go Interface 接口使用. 就够了.

    之所以只有 Java 语言, 特别爱强调设计模式, 是 Java 的设计缺陷, 才需要显式打补丁(不是优点, 不要搞反了).

    其他语言, 设计模式, 早就融入语言本身的设计.

    Go Interface, 是面向接口编程的典范. 非常漂亮. 兼顾优雅 /简洁 /易用.

    理解 Go 很简单. 核心就 2 点. 面向接口(interface) + 面向队列(channel) 编程. (沙雕泛型 generic, 先跳过)

    面向接口(interface) = 面向动作(action), 数据和操作分离. 聚焦对操作(action)作抽象. 以操作为主, 数据来适配操作.

    面向队列(channel) = MQ(kafka) = 生产者 /消费者模型. 你可以把 go channel, 当成内置的 kafka 来理解, 使用方式也一样.

    so. go 的精华, 只有这么多. 剩下的部分, 都是裁剪 c 语言. (垃圾泛型除外)
    rrfeng
        3
    rrfeng  
       2022-06-13 09:03:13 +08:00 via Android
    你把 I 放到 parent 里是个什么意思。。。。
    Hyvi
        4
    Hyvi  
       2022-06-13 09:22:28 +08:00 via iPhone
    你把内嵌结构体理解成继承 /接口实现了。看看 embeded struct
    HiShan
        5
    HiShan  
       2022-06-13 09:54:34 +08:00
    本质上是让 Parent 继承 I 接口的具体实现,从而实现调用到子类的实现。。不过这样写实在是太奇怪了。。。
    PS:go 设计的只有简单与漂亮\简单不沾边
    HiShan
        6
    HiShan  
       2022-06-13 09:55:28 +08:00
    @HiShan 漂亮\优雅
    fo0o7hU2tr6v6TCe
        7
    fo0o7hU2tr6v6TCe  
       2022-06-13 09:57:24 +08:00
    近几年新出来的一些语言,不要参考 java 来学习
    LoremIpSum
        8
    LoremIpSum  
    OP
       2022-06-13 09:58:34 +08:00
    @rrfeng 这样写可以实现这功能,但是底层原理不知道为什么
    akaHenry
        9
    akaHenry  
       2022-06-13 10:47:55 +08:00   ❤️ 1
    多说一句. Go 和 Rust 等更现代的语言设计, 都是重视 组合 /嵌套 > 类继承.

    Go 的 接口(interface) 设计, 都是 `组合` 的方式来扩展功能.

    不要被 `类继承` 束缚思维. `类继承`, 是糟糕的东西.

    不要总是想定义很大的类 struct (数据+方法过多).

    尽量切分小类. 标准化操作 = 抽象接口方法(interface).

    另外, go struct{}, 可以作为命名空间 namespace 使用 = 裸类(没数据, 只有方法).

    小模块, 搭积木, 自由组合. 可以写出非常干净 /清晰的代码.
    akaHenry
        10
    akaHenry  
       2022-06-13 10:50:35 +08:00
    理性状态: 接口设计(interface) 和 数据(data), 应该是正交的.

    推荐读 go-micro 这个项目源码来学习如何写 go + 设计大型框架系统.

    go-micro 的代码写的非常非常漂亮.
    mengdodo
        11
    mengdodo  
       2022-06-14 09:38:42 +08:00
    不要用设计模式去包裹 go, 那不是它
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1596 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:04 · PVG 01:04 · LAX 09:04 · JFK 12:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.