【问题标题】:Interfaces and address operators接口和地址运算符
【发布时间】:2020-12-04 02:17:17
【问题描述】:

我有个问题理解为什么返回类型是接口时可以使用地址操作符

func NewReader() IReader {
    return &Reader{}
}

但(当然)不是当返回类型是结构时

func NewReader() Reader {
    return &Reader{} // cannot use &Reader literal (type *Reader) as type Reader in return argument
}

后面的函数签名是func MyFuncReader(r IReader),但reflect.TypeOf(r)*main.Reader

  1. 所以IReader 类型隐藏了它是指针的事实?
  2. 函数签名func MyFuncReader(r IReader) 没有告诉我,指针或值已传递给函数?

样品

  1. 带有接口https://play.golang.org/p/1Db1Jybp0rP的完整示例
  2. 不带接口的完整示例https://play.golang.org/p/nPtu09yhe0C

【问题讨论】:

  • 人们可以提出如何改进问题的建议已经是隐含的了。问可能无济于事。

标签: pointers go struct interface


【解决方案1】:

如果函数的返回类型是接口类型,则可以返回实现该接口的任何值。 Spec: Return statements:

一个或多个返回值可以在“return”语句中明确列出。每个表达式必须是单值的,并且assignable 必须是函数结果类型的对应元素。

在您的第一个示例中,Reader 具有带有 指针接收器 的方法,因此只有指向 Reader(即 *Reader)的指针实现了 IReader 接口。所以你必须返回&Reader{}

如果你的函数有一个具体类型的返回类型,你必须返回一个确切的具体类型的值,你不能返回一个指向那个类型的指针的值。

【讨论】:

  • 我如何知道我是在传递一个指针还是创建一个新的数据副本,如果一个接口可以两者兼而有之。使用指针接收器或值接收器时。
  • @dhcgn 如果指针和非指针类型都实现了接口,那么两者都可以。应该使用哪个视情况而定。
【解决方案2】:

当返回类型为Reader

func NewReader() Reader {
    return &Reader{} // cannot use &Reader literal (type *Reader) as type Reader in return argument
}

您不能使用指向Reader 类型的指针来代替Reader 类型。原因是它们不属于同一类型。

当你使用像IReader 这样的接口作为返回类型时

func NewReader() IReader {
    return &Reader{}
}

它基本上意味着实现IReader 接口的方法的任何 类型将被归类为实现该接口的类型,因此是可以接受的。由于 *Reader 类型在您的示例中实现了 IReader 类型,因此它是此处 NewReader 函数的可接受返回值。这意味着如果我引入一个新的type 来实现这个接口,例如,

type dummy int

func (d dummy) GetCount() int {
    return d
}

func (d dummy) IncreaseCount() {
    fmt.Println("Increased count: %d", d)
}

然后我可以做类似的事情

func NewReader() IReader {
    var d dummy
    d = 5
    return d
}

它仍然可以工作。使用reflect 包检查时,此返回值的基础类型将是dummy

【讨论】:

  • 这是否会让我更难判断我是在使用值还是引用?
  • @dhcgn 我不知道你为什么会这么想。也许请告诉我同样的原因?此外,如果是指针*Reader 实现了接口,则Reader 值类型将不是作为IReader 返回类型的可接受值。但是,如果是实现接口的Reader,那么*ReaderReader 都是可接受的返回类型,因为afaik go 可以解释为实现接口的是Reader,并且可以从@987654344 获取基础值@.
  • 您可能会发现thisthis 很有帮助。
猜你喜欢
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 2019-02-03
  • 2017-01-09
  • 2022-01-23
  • 1970-01-01
  • 2020-07-22
相关资源
最近更新 更多