【问题标题】:If type T2 is based on type T1, is there any sort of "inheritance" from T1 to T2?如果 T2 类型基于 T1 类型,那么从 T1 到 T2 是否存在某种“继承”?
【发布时间】:2011-09-22 23:21:25
【问题描述】:

如果type T2基于type T1,除了共享相同的数据字段之外,T1T2之间有什么关系吗?

包主 导入“fmt” 类型 T1 结构 { s 字符串 } func (v *T1) F1() 字符串 { 返回 v.s } T2 T1 型 func (v *T2) F2() 字符串 { 返回 v.s } 功能主要(){ 变量 t1 = T1{“xyz”} var t2 = T2{“pdq”} s0 := t2.F1() // 错误 - 预期正常 s1 := ((*T1)(&t2)).F1() // 好的 - 预期的 s2 := ((*T2)(&t1)).F2() // 好的 - 不是预期的 fmt.Println(s0, s1, s2) }

我这里理解不够

  1. 希望T2 会继承T1 的方法,但事实并非如此。

  2. 原以为 T2 可能会被强制转换为 T1,因为它是从 T1 派生的

  3. 很惊讶T1 可以被强制转换为T2,但事实就是如此。

  4. T1T2 之间的关系似乎是完全对称的——我找不到任何破坏对称性的东西,尽管事实上一个实际上是从另一个派生的——或者这是一种错觉?

【问题讨论】:

    标签: types go


    【解决方案1】:
    s2 := ((*T2)(&t1)).F2()         // ok - not expected
    

    之所以有效,是因为您将其转换为类型T2,因此它允许F2。所以它有望工作。然后在您的T2 对象t1 上调用F2 函数,该对象返回t1.s

    s0 := t2.F1()                   // error - expected ok
    

    对于这个,我不能肯定地告诉你,但也只能告诉你我的合理想法:

    F1 是 T1 类型的方法。由于 t2 不是 T1 类型,因此您不能在 t2 上调用 F1。因此,正如您所指出的,只有数据字段是共享的,而不是这些类型的方法。

    另请参阅Go for C++ programmers,其中指出:

    方法是在命名类型上定义的。如果将值转换为不同的类型,则新值将具有新类型的方法,而不是旧类型的方法。

    【讨论】:

      【解决方案2】:

      我可以解释为什么T2 没有T1 的方法。想象一下,您需要以两种不同的方式对T 类型的一些数据进行排序。一种方法是默认方法,因此您在T 中实现LenLessSwap 方法。您可以调用sort.Sort(data) 并以默认方式对数据进行排序。但是如何对数据进行不同的排序呢?

      您编写type SortDifferently T 并实现SortDifferently 类型的LenLessSwap 方法。如果 SortDifferently 拥有 T 的所有方法,你就不能这样做,因为 Go 没有方法覆盖。但是如果没有继承,您现在可以编写 sort.Sort((SortDifferently)data) 来以不同的方式对数据进行排序。

      这是一种 Go 的做事方式。不太容易习惯。

      【讨论】:

      • “Go 没有方法覆盖”——我想这可以解释。
      • 问题是 Go 确实 有方法阴影。如果您使用type SortDifferently struct { T },它会将所有方法从T 转发到SortDifferently,并且仍然允许您使用专门编写在SortDifferently 上的方法来隐藏这些名称。您仍然可以调用T 版本,即使在阴影方法中也是如此。我真的不知道他们为什么在 type SortDifferently T 案例中不允许这样做。
      【解决方案3】:

      不确定它是否会对您有所帮助,但请查看例如 "Go for C++ programmers" 中描述的“匿名字段”,在“接口”部分下——看起来它们提供了一些看起来像子类的东西。

      但无论如何,通过阅读有关 Go 的教程,我产生了一个想法,即 Go 的作者明确希望程序员避免构建继承链,而是使用嵌入/委托。

      【讨论】:

        【解决方案4】:

        Go 不支持面向对象的类型继承。

        Is Go an object-oriented language?

        Why is there no type inheritance?

        方法绑定到一个特定类型。

        method declaration 绑定一个 方法的标识符。方法是 据说绑定到基本类型和 仅在选择器中可见 那种类型。

        您可以在 T1T2 类型之间使用 convert

        x 可以是converted 来输入 T [当] x 的类型和T 有 相同的底层类型。

        例如,

        package main
        
        import (
            "fmt"
        )
        
        type T1 struct{ i int }
        
        func (t T1) String() string { return "T1" }
        
        type T2 T1
        
        func (t T2) String() string { return "T2" }
        
        func main() {
            t1 := T1{1}
            t2 := T2{2}
            fmt.Println(t1, t2)
            c1 := T1(t2)
            c2 := T2(t1)
            fmt.Println(c1, c2)
            t1 = T1(c2)
            t2 = T2(c1)
            fmt.Println(t1, t2)
        }
        
        Output:
        T1 T2
        T1 T2
        T1 T2
        

        【讨论】:

        • 所以当你说type T2 T1时,发生的事情是T1的结构被复制为T2的结构,并且它们具有相同的结构,它们可以被重铸成彼此,否则T2T1 没有关系
        • 是的。有很多转换规则。对于这个特定规则,T1T2 具有相同的底层类型这一事实意味着它们也具有相同的内存大小、布局和内容。
        【解决方案5】:

        对于另一种选择,您可以使用嵌入:

        package main
        import "fmt"
        
        type T1 struct { s string }
        func (v *T1) F1() string { return v.s }
        
        type T2 struct { T1 }
        func (v *T2) F2() string { return v.s }
        
        func main() {
           a := new(T1).F1()
           // undefined (type *T1 has no field or method F2)
           // b := new(T1).F2()
           c := new(T2).F1()
           d := new(T2).F2()
           fmt.Print(a, c, d)
        }
        

        https://golang.org/ref/spec#Struct_types

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-26
          • 2017-05-23
          • 2018-10-25
          相关资源
          最近更新 更多