【问题标题】:Can embedded struct method have knowledge of parent/child?嵌入式结构方法可以了解父/子吗?
【发布时间】:2015-06-03 14:11:13
【问题描述】:

几个月来,我一直在空闲时间和 Go 一起工作,我觉得我已经掌握了窍门。来自传统的 OOP 语言,例如 Java 和 PHP,我很难掌握 Go 的组合和嵌入。我认为它最近终于点击并想要更多地使用它,但我已经为我的一个想法遇到了障碍。

假设我有一个来自具有 Validate 方法的包的结构,并且我将它嵌入到我当前正在使用的包的结构中。有没有一种方法(我拥有两个包)可以参考在 Validate 方法中进行嵌入的结构?有点像查看谁给我打电话的一种方式,因为我会在“父”而不是嵌入式上调用它。

我会试着想象一下这个......

type B struct {}
func (b B) Validate() {
  // get reference somehow of A obj
}


type A struct {
  B
}

a := A{B{}}
a.Validate()

我觉得这似乎是不可能的,但如果可以的话,那就太酷了。我想您需要将 A 和 B 设为相同的接口类型才能使其工作。任何想法或帮助将不胜感激。

【问题讨论】:

    标签: struct go embedding


    【解决方案1】:

    这是不可能的。为了更好地理解原因,请查看您的示例的略微修改版本:

    type B struct{}
    
    func (b *B) Validate() {
        fmt.Printf("b:%p\n", b)
    }
    
    type A struct {
        *B
    }
    
    func main() {
        b := B{}
        a1 := A{&b}
        a2 := A{&b}
    
        a1.Validate()
        a2.Validate()
        a1.B.Validate()
        a2.B.Validate()
    
        b.Validate()
    }
    

    按预期输出,*B 的值在任何地方都相同 (Go Playground):

    b: 0x1becd8
    b: 0x1becd8
    b: 0x1becd8
    b: 0x1becd8
    b: 0x1becd8
    

    如您所见,我将方法接收器和嵌入类型更改为B的指针。

    从这个例子很清楚:你可以使用B的相同值(或者更确切地说B值的相同地址)来嵌入A类型的不同值!

    您可以同时调用Validate():因此对于*B 的给定值,理论上的“父级”甚至不是“常量”。这不会破坏交易, 但是:如果值为A,您可以通过编写a.Validate() 来调用提升的方法B.Validate(),这没关系,但您也可以像a.B.Validate() 一样调用它 - 现在这一次您真的没有A 的值(有争议,但 Validate() 是在 *B 而不是 A 的值上调用的),但最后你也可以调用 b.Validate() - 这次你肯定没有 @ 的值987654341@.

    没有明确的父类型,B(或*B)可以嵌入任何类型(所以它不能是interface{}以外的任何类型)。

    所以图像:你有一个具体的值*B,当它的Validate() 方法被调用时,有时有一个父级,有时没有。那么有父母的理由是什么?

    回到你的例子:为了让这个 Validate() 方法验证有意义的东西,它应该(必须)作为参数传递给 Validate() 方法 - 显式而不是自动传递。

    你能做的最好的就是 captncraig 在his answer (+1) 中写的。

    如果你明确地向A 添加一个方法,它会像这样调用B.Validate(),你可以稍微简化一下:

    func (a *A) Validate2() {
        a.Validate(a)
    }
    
    // And using it:
    a.Validate2()
    

    没有理由将您想象的那种验证器嵌入A,它应该只是A 的一个字段,或者由于没有直接关系,它可以是一个“独立”的验证器.在这两种情况下,如果您想简化验证,您可以向 A 添加一个帮助器 Validate() 方法。

    【讨论】:

      【解决方案2】:

      任何类型的parent 引用都是不可能的。你希望对父母做什么?由于它们可能是完全不同的类型,因此它们将无法做任何有意义的事情。

      如果您需要不同类型之间的共同点,则需要一个接口,并且需要将其传入:

      type B struct {}
      func (b B) Validate(parent MyInterface) {
      }
      
      
      type A struct {
        B
      }
      // A implements MyInterface
      a := A{B{}}
      a.Validate(a)
      

      如果你能解释你真正想要完成的事情,几乎可以肯定有比这更好的方法。

      【讨论】:

      • 目前我有一个验证库,它类似于 Java 中的 HIbernate 验证。截至目前,我有一个您使用的验证方法,如您所建议的: mypackage.Validate(myStructOb) 。如果有一种方法可以在我要验证的结构上嵌入验证方法并调用它,我会认为它会更干净。
      • 我在 Java API 索引中找不到任何关于 Hibernate 的信息,所以我不知道您要做什么。我会重申这个答案的第一段。 Validate 对嵌入它的结构需要了解什么?
      猜你喜欢
      • 2015-06-06
      • 2020-04-09
      • 1970-01-01
      • 1970-01-01
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-31
      相关资源
      最近更新 更多