英文:
How are interface types handled between functions?
问题
我对接口有一些问题,特别是当这些接口在函数之间传递时。
我知道接口可以隐式地满足,也就是说以下代码是有效的:
type itemX struct {}
func (x *itemX) Do() string {
return "itemX"
}
type Itf interface {
Do() string
}
func test(i Itf) string {
return i.Do()
}
func main() {
x := new(itemX)
str := test(x) // 有效,因为x隐式满足Itf接口
}
然而,当我开始在函数之间传递接口时,发生了什么以及类型约定是什么就不那么清楚了。以下是一个例子:
// itemX、Itf和test的声明与上面的代码片段相同
func returnsItf(i Itf) Itf {
return i
}
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
func takeItf(i Itf) {}
func takeX(x *itemX) {}
func main() {
x := new(itemX)
var i Itf = x
a := returnsItf(i) // 返回类型为Itf的值
_ = takeItf(a) // 没有错误
b := returnsTypeAssertedX(i)
_ = takeItf(b) // 没有错误,因为*itemX实现了Itf接口
_ = takeX(b) // 错误,无法将b(类型为Itf)用作*itemX类型
}
当一个接口作为函数返回时,似乎有一些隐藏的行为。如果返回类型是*itemX
而函数的类型是Itf
,则在函数框架终止之前,返回值会被转换为Itf
类型。
因此,这种隐式检查(具体类型 -> 接口类型)在每次函数调用时都会进行两次:
- 在每次函数调用开始时,
- 和在结束时。
对于这个隐式转换的理解是否正确?
英文:
I have some questions about interfaces, especially when these interfaces are passed between functions.
I understand that interfaces are satisfied implicitly, meaning the following code is valid:
type itemX struct {}
func (x *itemX) Do() string {
return "itemX"
}
type Itf interface {
Do() string
}
func test(i Itf) string {
return i.Do()
}
func main() {
x := new(itemX)
str := test(x) // valid, since x implicitly satisfies Itf
}
However, it is not so clear what happens or what the type contract is like when I start passing interfaces between functions. An example:
// itemX, Itf, and test have the same declaration as the above snippet
func returnsItf(i Itf) Itf {
return i
}
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
func takeItf(i Itf) {}
func takeX(x *itemX) {}
func main() {
x := new(itemX)
var i Itf = x
a := returnsItf(i) // returns type Itf
_ = takeItf(a) // no error
b := returnsTypeAssertedX(i)
_ = takeItf(b) // no error, since *itemX implements Itf
_ = takeX(b) // error, cannot use b (type Itf as *itemX)
}
There seems to be some hidden behavior when an interface is passed out as a function return. If the return is *itemX
and type is Itf
, the return is transformed into Itf
before the function frame is terminated.
So, this implicit check (concrete -> interface if type is interface) is done twice per function call:
- at the start of each function call,
- and at the end.
Is my understanding of this implicit transformation correct?
答案1
得分: 1
接口是一种具有两个成员的数据类型:底层对象的类型和指向该对象的指针。因此,当您在需要接口的上下文中使用非接口类型时,编译器会从该值构造一个接口类型,并使用它。
在上面的函数中,它首先对传入的参数进行类型断言,确保其为所需的类型,然后将参数的底层值转换回接口。
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
上述代码将无法正常工作,因为b
是一个interface{}
类型,而takeX
需要一个*itemX
类型。然而,以下代码可以正常工作:
takeX(b.(*itemX))
英文:
An interface is a data type that has two members: The type of the underlying object, and a pointer to that object. So, wen you use a non-interface type in a context that needs an interface, the compiler constructs an interface type from that value, and uses that.
func returnsTypeAssertedX(i Itf) Itf {
return i.(*itemX)
}
In the above function, it first type-asserts that the passed in argument is of the required type, and then converts the underlying value of the argument back to an interface.
b := returnsTypeAssertedX(i)
_ = takeX(b)
The above will not work, because b
is an interface{}
, and takeX
requires an *itemX
. However, this would work:
takeX(b.(*itemX))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论