Go 为什么返回具体类型不能满足需要接口返回的接口

Go 为什么返回具体类型不能满足需要接口返回的接口,go,interface,Go,Interface,假设我们有以下代码 包干管 I1型接口{ Foo字符串 } I2型接口{ 钢筋I1 } 类型S1结构{} func s*S1 Foo字符串{ 返回foo } 类型S2结构{} 函数s*S2条*S1{ 返回&S1{} } func main{ x:=&S2{} 变量i I1=x.巴 printlni.Foo 变量y I2 y=&S2{} printlny.Bar.Foo } 现在,从我的观点来看,S2满足I2,正如Bar的返回满足I1,如上面几行所示,但编译器不同意我的观点: # command-

假设我们有以下代码

包干管 I1型接口{ Foo字符串 } I2型接口{ 钢筋I1 } 类型S1结构{} func s*S1 Foo字符串{ 返回foo } 类型S2结构{} 函数s*S2条*S1{ 返回&S1{} } func main{ x:=&S2{} 变量i I1=x.巴 printlni.Foo 变量y I2 y=&S2{} printlny.Bar.Foo } 现在,从我的观点来看,S2满足I2,正如Bar的返回满足I1,如上面几行所示,但编译器不同意我的观点:

# command-line-arguments
./main.go:28:4: cannot use S2 literal (type *S2) as type I2 in assignment:
        *S2 does not implement I2 (wrong type for Bar method)
                have Bar() *S1
                want Bar() I1
是的,我知道它们是不同的类型†,但这不是接口接受任何满足其要求的类型的要点吗

是否有人能提供更多信息,说明在此阶段未考虑接口满意度的技术原因


接口不满意,因为方法签名不匹配。接口中指定的方法签名为: 钢筋I1 但提供的方法签名是: 条*S1


您仍然可以返回指向S1实例的指针,但需要方法签名进行匹配。将方法的返回类型更改为I1。

函数返回的就是它返回的。两个内存布局不同的东西,例如I1和*S1是完全不同的东西。返回值不受限制,如果可赋值,则它必须在内存布局级别上匹配。为什么?只是一个猜测:它使一切变得更容易,例如在延迟中修改返回值,特别是在运行中的接口满意度是隐含的,因此如果允许的话,可能会导致难以防止的错误。@Volker在某种程度上说得通,但我仍然无法协调整件事。据我所知,返回的接口无论如何都是一个指针,因此我们没有分配实际的内存,而是一个指针,对于任何类型,afaik都是几乎相同的数据布局。更进一步说,接口甚至有内存布局吗?它不只是一个需要匹配的规则,而不是任何包含数据的东西吗?另外,接受接口作为参数并传入具体类型怎么样?为什么我可以在var I I1=x.Bar中将*S1分配给I1?接口不是指针。接口的内存布局与指针不同。这是未指定的,因此它是一个实现细节,可以更改,但它们大致是两个指针,一个指向实际值,另一个指向类型,它的方法更好。接口甚至有内存布局吗?它不只是一个需要匹配的规则,而不是任何包含数据的东西吗?这就是接口和接口值之间的差异。接口的抽象概念只是一个方法的集合,但在Go中有接口类型的变量:例如,var io。Reader是内存中的某个东西。为什么我可以在var I I1=x.Bar中将*S1分配给I1?从技术上来说,因为语言规范允许它。非正式:如果没有接口,您将无法使用接口:要从接口中获益,您需要能够使用接口变量编写通用代码,并为实现该接口的非接口值赋值。这是如何工作的,这篇文章已经过时了,但信息丰富:在签名中查找它显然不符合字符串比较级别,但是Bar*S1满足Bar I1签名,因为*S1满足I1接口。所以如果你重新阅读我的问题,为什么在技术层面上这被认为是不匹配的,因为它不匹配。你的意见可以向Go团队提出,但是规范中记录的编译器的意见与此处相关,并且它说签名必须相同。@Adrian我知道我的意见与整个世界无关,尤其是编译器,在本例中是错误的,但到了一天结束时,每个人的节目都是基于他们认为语言在他们看来是如何运作的,而真正改变这种错误理解的唯一方法就是深入挖掘。这就是我试图表述我的问题的方式。这就是为什么它不是一个答案,什么是技术原因,这是它的方式。你有没有什么建议可以重新制定Q来更好地表达这一点?为什么X的设计方式是这样的,99%的时候,这是X设计师的问题,而不是整个社区的问题;社区不仅不能提供明确的答案,而且问题本身也是基于意见的,因为它的核心是关于设计师的意见。