}
additab 会检查 itab 持有的 interfacetype 和 _type 是否符合,就是看 _type 是否完全实现了 interfacetype 的方法,也就是看两者的方法列表重叠的部分就是 interfacetype 所持有的方法列表。注意到其中有一个双层循环,乍一看,循环次数是 ni * nt,但由于两者的函数列表都按照函数名称进行了排序,因此最终只执行了 ni + nt 次,代码里通过一个小技巧来实现:第二层循环并没有从 0 开始计数,而是从上一次遍历到的位置开始。
求 hash 值的函数比较简单:
funcitabhash(inter *interfacetype, typ *_type)uint32{
h := inter.typ.hash
h += 17* typ.hash
returnh % hashSize
}
hashSize 的值是 1009。
更一般的,当把实体类型赋值给接口的时候,会调用 conv 系列函数,例如空接口调用 convT2E 系列、非空接口调用 convT2I 系列。这些函数比较相似:
如何用 interface 实现多态
在面向对象中,只有接口和共有方法,继承方法才有复写,私有方法不可以复习,但是又想了一下,才明白:不是不可以复习而是,根本就不存在复写私有方法的概念。3.简朴的(非纯)impure virtual函数具体指定接口继承及缺省实现继承。1.顶层函数:多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层函数不属于成员函数,是不能被继承的。
多态是一种运行期的行为,它有以下几个特点:
看一个实现了多态的代码例子:
packagemain
import"fmt"
funcmain(){
qcrao := Student{age: 18}
whatJob(&qcrao)
growUp(&qcrao)
fmt.Println(qcrao)
stefno := Programmer{age: 100}
whatJob(stefno)
growUp(stefno)
fmt.Println(stefno)
}
funcwhatJob(p Person){
p.job()
}
funcgrowUp(p Person){
p.growUp()
}
typePerson interface{
job()
growUp()
}
typeStudent struct{
age int
}
func(p Student)job(){
fmt.Println("I am a student.")
return
}
func(p *Student)growUp(){
p.age += 1
return
}
typeProgrammer struct{
age int
}
func(p Programmer)job(){
fmt.Println("I am a programmer.")
return
}
func(p Programmer)growUp(){
// 程序员老得太快 ^_^
p.age += 10
return
}
代码里先定义了 1 个 Person 接口,包含两个函数:
job() growUp()
然后,又定义了 2 个结构体,Student 和 Programmer,同时,类型 *Student、Programmer 实现了 Person 接口定义的两个函数。注意,*Student 类型实现了接口, Student 类型却没有。
之后,我又定义了函数参数是 Person 接口的两个函数:
funcwhatJob(p Person)
funcgrowUp(p Person)
main 函数里先生成 Student 和 Programmer 的对象,再将它们分别传入到函数 whatJob 和 growUp。函数中,直接调用接口函数,实际执行的时候是看最终传入的实体类型是什么,调用的是实体类型实现的函数。go语言实现短信接口于是,不同对象针对同一消息就有多种表现,多态就实现了。
更深入一点来说的话,在函数 whatJob() 或者 growUp() 内部,接口 person 绑定了实体类型 *Student 或者 Programmer。根据前面分析的 iface 源码,这里会直接调用 fun 里保存的函数,类似于:s.tab->fun[0],而因为 fun 数组里保存的是实体类型实现的函数,所以当函数传入不同的实体类型时,调用的实际上是不同的函数实现,从而实现多态。
运行一下代码:
I am a student.
{19}
I am a programmer.
{100}
Go 接口与 C++ 接口有何异同
接口定义了一种规范,描述了类的行为和功能,而不做具体实现。
C++ 的接口是使用抽象类来实现的,如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 "= 0" 来指定的。例如:
classShape
{
public:
// 纯虚函数
virtualdoublegetArea()= 0;
private:
stringname; // 名称
};
设计抽象类的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。
派生类需要明确地声明它继承自基类,并且需要实现基类中所有的纯虚函数。
对象属性可以设置存取器函数,使用 get 声明存取器getter函数, set 声明存取器setter函数。如果你声明没有inline,却在定义时inline了.这时,如果其它要调用该函数的文件看到了它的声明,就认为该函数不是内联的,所以,到了调用处,转到该函数实现的地方,却意外地看到了inline声明,这时,会导致链接出错.若要改正的话,就要让调用该函数的文件也看到有inline的定义,而不是在调用时才看到.你可以在每个文件都加上有inline的定义.(如果不加inline,则会出现重复定义的错误,因为内联函数才可以被重复定义).或者另一种修改方法,你将定义时的inline去掉,这样就成为普通函数,链接不会出错.如果是前一种改法,仍是内联的,因为符合了看到了inline且随处可见其定义的条件.。把内联函数的定义放在头文件中,可以确保在调用函数时所使用的定义是相同的,并保证在调用点该函数的定义对调用点可见.在头文件中加入或修改内敛函数时,使用了该头文件的所有源文件都需要重新编译.2)类中的成员函数作为内联函数.在类内声明的成员函数,如果在类中实现,则自动转化为内联函数,但若违反上面所述的情况时,则将其作为一般函数对待.若在类定义外面实现该函数,则需要显示指定inline.类定义写在头文件中时,如果需要内联函数,函数也应在头文件中实现.参考:c+。
C++ 和 Go 在定义接口方式上的不同,也导致了底层实现上的不同。go语言实现短信接口C++ 通过虚函数表来实现基类调用派生类的函数;而 Go 通过 itab 中的 fun 字段来实现接口变量调用实体类型的函数。C++ 中的虚函数表是在编译期生成的;而 Go 的 itab 中的 fun 字段是在运行期间动态生成的。原因在于,Go 中实体类型可能会无意中实现 N 多接口,很多接口并不是本来需要的,所以不能为类型实现的所有接口都生成一个 itab, 这也是“非侵入式”带来的影响;这在 C++ 中是不存在的,因为派生需要显示声明它继承自哪个基类。
参考资料,由于篇幅有限,参考资料有删减
【包含反射、接口等源码分析】https://zhuanlan.zhihu.com/p/27055513
【虚函数表和C++的区别】https://mp.weixin.qq.com/s/jU9HeR1tOyh-ME5iEYM5-Q
【具体类型向接口赋值】https://tiancaiamao.gitbooks.io/go-internals/content/zh/07.2.html
【Go夜读群的讨论】https://github.com/developer-learning/reading-go/blob/master/content/discuss/2018-08-30-understanding-go-interfaces.md
领队:周德奎 教练:周加峰 855 董国忠 861 徐胡鹏 877 董治国 888 周加峰 865 洪艳 871 陈朝芳 885 叶新新 856 杨象国 862 陈海哨 878 赵宇宏 889 余进 866 廖雪峰 872 吴飞霞 886 陈艳乐 857 庄在锦 863 杨雄 879 张 亮 890 李瑞文 867 颜蓓蕾 873 王高英 892 杨筱玲 858 吴东 874 胡小平 880 章志彪 891 毕保祥 868 周茹茹 882 柯素芬 869 李美琴 883 方小洁 859 王涛 875 陈军 881 刘明刚 男子 854 郑国领 860 赵益民 876 叶洲荣 887 王跃东 女子 864 潘品丽 870 王丹 884 孔向东。罗美英、童浒华、蓝雪峰、何德清、蓝启云、梁冠仁、刘锦荣、钟伟明、廖金亮、石集福、。12、并不是所有时候都需要继承,继承也不是完美的,有时候会创造比他能解决的更多的问题,特别是当层次关系没那么明显的时候,这时候应该多用结构 类型(又叫鸭子类型,如果它看起来像鸭子、游泳像鸭子并且叫声像鸭子,那么它就是鸭子),用结构类型设计灵活的对象接口的时候,不需要创建类工厂来返回类 的实例,而是直接返回对象,对象具备预期的方法和属性,比如:。
转载自:https://www.jianshu.com/p/f5fc14bde8a0。链接:https://www.jianshu.com/p/cf80d644727e。https://www.jianshu.com/p/cf80d644727e。
【总体说明itab的生成方式、作用】
https://blog.csdn.net/angelasan/article/details/44917283。转载自:https://blog.csdn.net/javazejian/article/details/51932554。 primer 第四版http://blog.csdn.net/odaynot/article/details/7923148http://blog.csdn.net/xiaofei2010/article/details/7609355。
【convI2I itab作用】https://www.jianshu.com/p/a5e99b1d50b1
作者:饶全成,中科院计算所硕士,滴滴出行后端研发工程师。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-98808-5.html
倘若国内蒸蒸日上
帅呀