我有下面的代码试图将嵌入结构分配给其父结构。有两组结构:Guider
是父结构体,DataBlock
从它扩展而来。方法func Put(x Guider)
接受一个类型为Guider
的参数。当我传递一个DataBlock
变量时,它工作。
但是,另一种情况是Mock
从zerolog.Event
扩展而来,但它未能在方法Test(e zerolog.Event)
上传递参数
出现以下错误:
无法将m(类型为Mock的变量)用作类型zerolog。Test参数中的事件
为什么这两种情况不同?我怎样才能使它们都起作用?
package main
import (
"fmt"
"github.com/rs/zerolog"
)
type Guider interface {
Guid() string
}
type FSEntity struct {
guid string
}
func (e FSEntity) Guid() string {
return e.guid
}
func Put(x Guider) {
fmt.Printf("%+v\n", x)
}
type Mock struct {
zerolog.Event
}
func Test(e zerolog.Event) {
}
//Child struct:
type DataBlock struct {
FSEntity
data []byte
}
func main() {
myVar := DataBlock{}
myVar.guid = "test"
myVar.data = []byte("moar test")
Put(myVar) // it works
m := Mock{}
Test(m) // it doesn't work. cannot use m (variable of type Mock) as type zerolog.Event in argument to Test
}
3条答案
按热度按时间b1zrtrql1#
首先,有几个定义:
Polymorphism
多态性是为不同类型的实体提供单个接口,或者使用单个符号表示多个不同类型。
Subtyping
子类型化(也称为子类型多态性或包含多态性)是类型多态性的一种形式,其中子类型是通过某种可替换性概念与另一数据类型(超类型)相关的数据类型,这意味着被编写为对超类型的元素进行操作的程序元素(通常为子例程或函数)也可以对子类型的元素进行操作
Inheritance
在面向对象编程中,继承是一种将一个对象或类建立在另一个对象(基于原型的继承)或类(基于类的继承)之上,并保持相似实现的机制。
Object composition
对象组合和对象聚合是将对象或数据类型组合成更复杂对象或数据类型的密切相关的方法。
Golang遵循composition over inheritance principle,例如,它不支持继承。
模拟从zerolog.事件扩展
你的意思是
Mock
包含了zerolog.Event
结构。Golang实现多态的方式是
interface
,所有实现某个接口的类型都可以在它的位置上使用,这就是你在使用Guider
时看到的。但是,它不适用于简单的结构体。
zerolog.Event
是Mock
内部的结构体。因此,通常情况下,
Test
函数应该接受某个接口作为参数,模拟事件和真实的事件都应该实现这个接口。然而,看起来zerolog没有为Event提供接口。因此,您应该访问结构体的Event
字段。Examplejaql4c8m2#
Put(myVar)
是法律的的,因为myVar
是一个DataBlock
,它 * 包含 *(不是继承也不是实现)一个FSEntity
,而FSEntity
又 * 实现 *Guider
接口。由于
Put
接受Guider
,所以对myVar
的引用是兼容的,因为它包含匿名的FSEntity
字段,该字段实现Guider
。FSEntity
上Guider
的实现(实际上)被提升到包含结构(提供了一种委托接口的方法)。这仅在包含字段是匿名的情况下发生。但是在
Test(m)
的情况下,函数接受zerolog.Event
,它是struct
类型,而不是interface
。因此,不可能有“委托”。Test()
必须传递zerolog.Event
,在这个场景中,这要求您使用匿名字段的类型名称:一些奖金信息:
如果
DataBlock
包含 * 两个 * 匿名字段,这两个匿名字段都实现了Guider
,则不能发生隐式委托/提升;golang不知道应该将包含的哪个实现委托给/elevated(如果有的话),在这种情况下,您必须再次使用希望传递给Put()
函数的字段的名称:无论是隐式的还是显式的,关键的区别在于传递给
Put()
的是DataBlock
(myVar
)的一个 * 字段 ,而不是*myVar
本身。如果要使用
Guider
接口将DataBlock
传递到Put()
,则DataBlock
必须自己实现Guider
接口。xyhw6mcr3#
对此持保留态度,因为我对
zerolog
包不熟悉。你的
Guider
是一个接口,只要Guid()
方法满足,它可以有任何底层类型。我假设这是通过包含FSEntity
的DataBlock
发生的,FSEntity
本身实现Guid()
方法,因此满足MIGHT接口。另一方面,我不知道应该实现什么方法来满足
zerolog.Event
,或者它是一个接口,还是一个结构体。如果它是一个接口,你可能需要实现它所需的方法,以便能够将DataBlock
用作zerolog.Event
类型。你可能想要/需要深入研究这个方向,以获得一些非常具体的答案。