猿问

使用戈朗嵌套结构(带接口)

两句话,对于任何人来说,对于一个好的架构,我们应该使用接口,这些接口描述它的行为,这并不是一个秘密。Golang实现了这个想法,但他们的接口只有方法,但没有字段。因此,使用它们的唯一方法是创建获取器和设置器。但是有了这个,我在指针方面遇到了问题。


例如:



package main


import "fmt"


// A


type IA interface {

    Foo() string

}


type A struct {

    foo string

}


func (a *A) Foo() string {

    return a.foo

}


// B


type IB interface {

    A() *IA

}


type B struct {

    a *IA

}


func (b *B) A() *IA {

    return b.a

}


// main


func main() {

    a := &A{"lol"}

    b := &B{a} // cannot use a (type *A) as type *IA in field value: *IA is pointer to interface, not interface


    foo := b.A().Foo() // b.A().Foo undefined (type *IA is pointer to interface, not interface)

    fmt.Println(foo)

}



Ofc,我可以使用这样的东西:


(*(*b).A()).Foo()

但这会那么好和合适吗?


我只想有像蟒蛇,js,ts这样的行为:


someObj.child1.child2.child2SomeMethod()

也许我搞砸了指针,我只想知道使用嵌套对象的golang方法。


ITMISS
浏览 108回答 1
1回答

潇潇雨雨

这是绊倒的常见点,特别是对于刚接触更高层次语言背景的人来说。以下是我如何保持直截了当:首先,让我们确定Go中的“接收器”(例如“方法”)是什么。就像Python一样,一个方法实际上与一种类型相连的事实是语法糖。康德塞尔这个例子:package mainimport "fmt"type F struct {  i int}func (f F)Foo() {  fmt.Println(f.i)}func main() {  F.Foo(F{1})}尽管可能令人惊讶,但此代码已编译并成功打印出预期的 .这是因为当您在类型上调用接收器时,真正发生的事情是该类型成为接收器的第一个参数。1真的很快,让我们也回顾一下指针,因为你似乎在评论中倒着说了。因此,需要明确的是:计算机程序中的任何值都存储在内存中,它在内存中的地址也是可以存储在变量中的值。我们将这些变量称为“指向”值的指针。如果我给一个函数一个值,他们只能在其函数的范围内更改该值。如果该值是内存中的地址,则同样如此。但是,我可以更改该地址的数据,从而影响具有函数外部范围的数据。package mainimport "fmt"func f(i int) { i = i + 2 }func pf(i *int) { *i = *i + 2 }var i = 1func main() {  f(i)  fmt.Println(i)  pf(&i)  fmt.Println(i)}打印输出13f(i)更改其本地副本,但更改存储在 中的地址处的数据。ipf(&i)i我为什么经历这一切?因为这就是围棋中的大多数接收器都是指针接收器的原因;因为您不想传递接收器的副本;您实际希望传递接收方的地址,以便它可以在自己的方法中改变自身。请记住,接收器是语法糖:func (t *Type)f(arg string)等效于:func f(t *Type, arg string)希望这能清楚地说明为什么指针接收器如此普遍!好了,说到界面方面。如您所知,接口定义了一组方法。如果类型定义了具有相同签名的方法,则该类型将满足该接口。对于值接收器或指针接收器,情况可能如此。但是,一个类型不能同时具有具有相同名称的值接收器和指针接收器:func (t  T)F() {}func (t *T)F() {} //method redeclared: T.F因此,这意味着类型和指向该类型的指针不能具有相同的接收器;因此,类型或指向类型的指针实现接收器,但不是两者。这一点很容易被忽视,因为go会自动转换。所以这工作正常:type T struct{}func (t  T)F() {}func (t *T)PF() {}func main() { var t T  t.F() t.PF()}在 中,将自动转换为指针。t.PF()t但重申一下,类型和指向类型的指针不能同时定义相同的接收器。因此,如果满足接口 ,则不满足,反之亦然。TI*T话虽如此,并且已经理解了这一点,很容易想出一个简单的规则:当你打算用指针满足接口时,永远不要将指针指向接口。在代码中,满足 。所以你可以说你的“真的是*A*A'没有任何意义。*AIAIA.  Thinking of it like this, you can see that taking the address of an IA that is actually an 将它们放在一起,下面是定义两个接口并链接调用。请注意,虽然指向我的结构的指针可能是满足接口的值,但我永远不需要获取接口的地址。对于 和 接口的使用者来说,它们是类型还是指针接收器都不相关。IFIGpackage mainimport "fmt"type IF interface {  G() IG}type F struct {  g IG}func (f *F)G() IG {  return f.g}type IG interface {  G()}type G struct{  i int}func (g *G)G() {  g.i++  fmt.Println("Gee, ", g.i)}func main() {  f := F{&G{1}}  f.G().G()}需要指向接口的指针是非常罕见的,因此请确保您认为“接口由指针满足”而不是“指向接口的指针”。
随时随地看视频慕课网APP

相关分类

Go
我要回答