type iface struct { tab *itab data unsafe.Pointer }
// layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with // ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs. type itab struct { inter *interfacetype // 接口类型 _type *_type // 实际类型 hash uint32// copy of _type.hash. Used for type switches. _ [4]byte// 4字节填充,与上面的4字节hash凑成8字节,与n内存对齐相关 // itab末尾是实现方法的引用,如果多余1个,则其余方法引用紧跟itab内存之后分配 fun [1]uintptr// variable sized. fun[0]==0 means _type does not implement inter. }
type interfacetype struct { typ _type // 接口类型信息 pkgpath name mhdr []imethod // 接口声明的方法 }
// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and // ../reflect/type.go:/^type.rtype. type _type struct { size uintptr ptrdata uintptr// size of memory prefix holding all pointers hash uint32// 类型hash值 tflag tflag // 类型相关一些flag,可以在反射包中使用 align uint8// 内存对齐 fieldalign uint8// 字段对齐 kind uint8// 类型kind alg *typeAlg // 类型的hash和equal方法 // gcdata stores the GC type data for the garbage collector. // If the KindGCProg bit is set in kind, gcdata is a GC program. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. gcdata *byte// 存储gc相关的信息 str nameOff // offset of name ptrToThis typeOff }
type uncommontype struct { pkgpath nameOff mcount uint16// number of methods xcount uint16// number of exported methods moff uint32// offset from this uncommontype to [mcount]method _ uint32// unused }
func(t *_type)uncommon() *uncommontype { if t.tflag&tflagUncommon == 0 { returnnil } switch t.kind & kindMask { case kindStruct: type u struct { structtype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindPtr: type u struct { ptrtype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindFunc: type u struct { functype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindSlice: type u struct { slicetype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindArray: type u struct { arraytype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindChan: type u struct { chantype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindMap: type u struct { maptype u uncommontype } return &(*u)(unsafe.Pointer(t)).u case kindInterface: type u struct { interfacetype u uncommontype } return &(*u)(unsafe.Pointer(t)).u default: type u struct { _type u uncommontype } return &(*u)(unsafe.Pointer(t)).u } }
通过汇编看iface
1 2 3 4 5 6 7 8 9 10
funcmain() { var r io.Reader = Arr{} r.Read(nil) }
var r io.ReadCloser = XXX{} r.Read(nil) _ = io.Reader(r) // ok _ = io.ReadCloser(r) // ok _ = io.Writer(r) // no var rc io.Reader = XXX{} _ = io.ReaderCloser(rc) // no
// 接口断言,第二个返回值表示是否断言成功 funcassertI2I2(inter *interfacetype, i iface)(r iface, b bool) { tab := i.tab // 接口是nil,返回断言失败 if tab == nil { return } if tab.inter != inter { tab = getitab(inter, tab._type, true) // true表示容忍失败 if tab == nil { // 不符合,返回false return } } r.tab = tab r.data = i.data b = true return }
funcgetitab(inter *interfacetype, typ *_type, canfail bool) *itab { iflen(inter.mhdr) == 0 { throw("internal error - misuse of itab") }
// easy case if typ.tflag&tflagUncommon == 0 { if canfail { returnnil } name := inter.typ.nameOff(inter.mhdr[0].name) panic(&TypeAssertionError{nil, typ, &inter.typ, name.name()}) }
var m *itab
// First, look in the existing table to see if we can find the itab we need. // This is by far the most common case, so do it without locks. // Use atomic to ensure we see any previous writes done by the thread // that updates the itabTable field (with atomic.Storep in itabAdd). // 先查表是否已经存在需要的itab t := (*itabTableType)(atomic.Loadp(unsafe.Pointer(&itabTable))) if m = t.find(inter, typ); m != nil { goto finish }
// Not found. Grab the lock and try again. lock(&itabLock) // 双重锁检查 if m = itabTable.find(inter, typ); m != nil { unlock(&itabLock) goto finish }
// Entry doesn't exist yet. Make a new entry & add it. // 分配itab内存,itab的内存分配在gc堆之外,不会被垃圾扫描、回收 m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys)) m.inter = inter m._type = typ m.init() // 初始化 itabAdd(m) // 添加到itabTable中,后续直接查表,不需要重新构造 unlock(&itabLock) finish: if m.fun[0] != 0 { // itab初始化成功 return m } if canfail { returnnil } // this can only happen if the conversion // was already done once using the , ok form // and we have a cached negative result. // The cached result doesn't record which // interface function was missing, so initialize // the itab again to get the missing function name. panic(&TypeAssertionError{concrete: typ, asserted: &inter.typ, missingMethod: m.init()}) }
// init fills in the m.fun array with all the code pointers for // the m.inter/m._type pair. If the type does not implement the interface, // it sets m.fun[0] to 0 and returns the name of an interface function that is missing. // It is ok to call this multiple times on the same m, even concurrently. func(m *itab)init()string { inter := m.inter typ := m._type x := typ.uncommon()
// both inter and typ have method sorted by name, // and interface names are unique, // so can iterate over both in lock step; // the loop is O(ni+nt) not O(ni*nt). // 接口和类型的方法列表是按照名字排序的,因此实际循环时间复杂度是O(ni+nt) ni := len(inter.mhdr) // 目标接口方法总数 nt := int(x.mcount) // 实际类型方法总数 // 计算实际类型的方法引用列表的偏移 xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt] j := 0 imethods: for k := 0; k < ni; k++ { i := &inter.mhdr[k] itype := inter.typ.typeOff(i.ityp) // 目标接口方法类型,与参数和返回值相关 name := inter.typ.nameOff(i.name) // 目标接口方法名 iname := name.name() ipkg := name.pkgPath() // 接口的包名 if ipkg == "" { ipkg = inter.pkgpath.name() } for ; j < nt; j++ { t := &xmhdr[j] tname := typ.nameOff(t.name) // 如果实际方法类型和方法名与目标方法的一致 if typ.typeOff(t.mtyp) == itype && tname.name() == iname { pkgPath := tname.pkgPath() if pkgPath == "" { pkgPath = typ.nameOff(x.pkgpath).name() } // 如果方法是导出的或者包名一致 // 如果接口有未导出方法,只能在同一个包内被实现,可以用来限制其他包实现该接口 if tname.isExported() || pkgPath == ipkg { if m != nil { ifn := typ.textOff(t.ifn) //实际函数入口PC // 保存到itab的方法列表中 *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn } continue imethods } } } // didn't find method m.fun[0] = 0// 没有找到方法,即目标类型没有实现该方法 return iname } m.hash = typ.hash return"" }