为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
ITMISS 2022-10-04 19:55:59
两句话,对于任何人来说,对于一个好的架构,我们应该使用接口,这些接口描述它的行为,这并不是一个秘密。Golang实现了这个想法,但他们的接口只有方法,但没有字段。因此,使用它们的唯一方法是创建获取器和设置器。但是有了这个,我在指针方面遇到了问题。例如:package mainimport "fmt"// Atype IA interface {    Foo() string}type A struct {    foo string}func (a *A) Foo() string {    return a.foo}// Btype IB interface {    A() *IA}type B struct {    a *IA}func (b *B) A() *IA {    return b.a}// mainfunc 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方法。
查看完整描述

1 回答

?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

这是绊倒的常见点,特别是对于刚接触更高层次语言背景的人来说。以下是我如何保持直截了当:


首先,让我们确定Go中的“接收器”(例如“方法”)是什么。就像Python一样,一个方法实际上与一种类型相连的事实是语法糖。康德塞尔这个例子:


package main


import "fmt"


type F struct {

  i int

}


func (f F)Foo() {

  fmt.Println(f.i)

}


func main() {

  F.Foo(F{1})

}

尽管可能令人惊讶,但此代码已编译并成功打印出预期的 .这是因为当您在类型上调用接收器时,真正发生的事情是该类型成为接收器的第一个参数。1


真的很快,让我们也回顾一下指针,因为你似乎在评论中倒着说了。因此,需要明确的是:计算机程序中的任何值都存储在内存中,它在内存中的地址也是可以存储在变量中的值。我们将这些变量称为“指向”值的指针。


如果我给一个函数一个值,他们只能在其函数的范围内更改该值。如果该值是内存中的地址,则同样如此。但是,我可以更改该地址的数据,从而影响具有函数外部范围的数据。


package main

import "fmt"


func f(i int) { i = i + 2 }


func pf(i *int) { *i = *i + 2 }


var i = 1


func main() {

  f(i)

  fmt.Println(i)

  pf(&i)

  fmt.Println(i)

}

打印输出


1

3

f(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 


将它们放在一起,下面是定义两个接口并链接调用。请注意,虽然指向我的结构的指针可能是满足接口的值,但我永远不需要获取接口的地址。对于 和 接口的使用者来说,它们是类型还是指针接收器都不相关。IFIG


package main


import "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()

}


需要指向接口的指针是非常罕见的,因此请确保您认为“接口由指针满足”而不是“指向接口的指针”。


查看完整回答
反对 回复 2022-10-04
  • 1 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号