英文:
How is the itab struct actually having a list of function pointers?
问题
在研究Go语言中的接口值时,我发现了一篇很棒的(可能有点过时)文章,作者是Russ Cox。根据这篇文章:
itable首先包含一些关于涉及的类型的元数据,然后变成一系列函数指针。
这个itable的实现应该是来自src/runtime/runtime2.go的代码:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // _type.hash的副本。用于类型切换。
_ [4]byte
fun [1]uintptr // 可变大小。fun[0]==0表示_type不实现inter。
}
第一个令人困惑的问题是,一个数组如何是可变大小的?
第二个问题是,假设我们在索引0处有一个满足接口的方法的函数指针,我们应该在哪里存储第二个/第三个/...函数指针?
英文:
Researching the interface value in go - I found a great (maybe outdated) article by Russ Cox.
According to it:
> The itable begins with some metadata about the types involved and then becomes a list of function pointers.
The implementation for this itable should be the one from src/runtime/runtime2.go:
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
First confusing thing is - how is an array - variable sized?
Second, assuming that we have a function pointer at index 0 for a method that satisfies the interface, where could we store a second/third/... function pointer?
答案1
得分: 1
编译后的代码和运行时访问fun
,就好像字段声明为fun [n]uintptr
,其中n
是接口中方法的数量。第二个方法存储在fun[1]
,第三个方法存储在fun[2]
,依此类推。Go语言没有像这样的可变大小数组功能,但是可以使用unsafe来模拟该功能。
下面是itab的分配方式:
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys))
函数persistentalloc
用于分配内存。函数的第一个参数是要分配的大小。表达式inter.mhdr
是接口中方法的数量。
下面是在可变大小数组上创建切片的code:
methods := (*[1<<16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
表达式methods[i]
在假设m.fun
是长度大于i
的可变大小数组的情况下,引用与m.fun[i]
相同的元素。后续的代码使用methods
和普通的切片语法来访问可变大小数组m.fun
。
英文:
The compiled code and runtime access fun
as if the field is declared fun [n]uintpr
where n
is the number of methods in the interface. The second method is stored at fun[1]
, the third at fun[2]
and so on. The Go Language does not have a variable size array feature like this, but unsafe shenanigans can be used to simulate the feature.
Here's how itab is allocated:
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, &memstats.other_sys))
The function persistentalloc
allocates memory. The first argument to the function is the size to allocate. The expression inter.mhdr
is the number of methods in the interface.
Here's code that creates a slice on the variable size array:
methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
The expression methods[i]
refers to the same element as m.fun[i]
in a hypothetical world where m.fun
is a variable size array with length > i
. Later code uses normal slice syntax with methods
to access the variable size array m.fun
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论