GoLang之方法与接口

  • 来源:本站
  • 发布时间:2019-08-13
  • 43已阅读
您现在的位置:首页 >> 现代文学 >> 文章
简介 Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。 方法,receiver可以是内置类型或者结构体类型的一个值或者是一个指针。

	GoLang之方法与接口

Go语言没有沿袭传统面向对象编程中的诸多概念,比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。

方法,receiver可以是内置类型或者结构体类型的一个值或者是一个指针。 所有给定类型的方法属于该类型的方法集。 如下面的这个例子,定义了一个新类型Integer,它和int一样,只是为它内置的int类型增加了个新方法Less()typeIntegerfunc(aInteger)Less(bInteger)bool{returnab}funcmain(){varaInteger=(2){("lessthen2")}}可以看出,Go语言在自定义类型的对象中没有C++/Java那种隐藏的this指针,而是在定义成员方法时显式声明了其所属的对象。

method的语法如下:func(rReceiverType)funcName(parameters)(results)当调用method时,会将receiver作为函数的第一个参数:funcName(r,parameters);所以,receiver是值类型还是指针类型要看method的作用。

如果要修改对象的值,就需要传递对象的指针。 指针作为Receiver会对实例对象的内容发生操作,而普通类型作为Receiver仅仅是以副本作为操作对象,并不对原实例对象发生操作。

func(a*Ingeger)Add(bInteger){*a+=b}funcmain(){varaInteger=(3)("a=",a)//a=4}如果Add方法不使用指针,则a返回的结果不变,这是因为Go语言函数的参数也是基于值传递。 注意:之前说过,Go语言没有构造函数的概念,通常使用一个全局函数来完成。

例如:funcNewRect(x,y,width,heightfloat64)*Rect{returnRect{x,y,width,height}}funcmain(){rect1:=NewRect(1,2,10,20)()}typeBasestruct{namestring}func(base*Base)Set(mynamestring){=myname}func(base*Base)Get()string{}typeDerivedstruct{Baseage}func(derived*Derived)Get()(nmstring,ag){,}funcmain(){b:=Derived{}("sina")(())}例子中,在Base类型定义了get()和set()两个方法,而Derived类型继承了Base类,并改写了Get()方法,在Derived对象调用Set()方法,会加载基类对应的方法;而调用Get()方法时,加载派生类改写的方法。 组合的类型和被组合的类型包含同名成员时,会不会有问题呢?可以参考下面的例子:typeBasestruct{namestringage}func(base*Base)Set(mynamestring,myage){==myage}typeDerivedstruct{Basenamestring}funcmain(){b:=Derived{}("sina",30)("=",,"\=",)("=",,"\=",)}值语义和引用语义值语义和引用语义的差别在于赋值,比如b=()Go语言中的大多数类型都基于值语义,包括:C语言中的数组比较特别,通过函数传递一个数组的时候基于引用语义,但是在结构体定义数组变量的时候基于值语义。 而在Go语言中,数组和基本类型没有区别,是很纯粹的值类型,例如:vara=[3]{1,2,3}varb=ab[1]++(a,b)//[123][133]从结果看,b=a赋值语句是数组内容的完整复制,要想表达引用,需要用指针:vara=[3]{1,2,3}varb=a    //引用语义b[1]++(a,b)//[133][133]接口Interface是一组抽象方法(未具体实现的方法/仅包含方法名参数返回值的方法)的集合,如果实现了interface中的所有方法,即该类/对象就实现了该接口。 Interface的声明格式:typeinterfaceNameinterface{//方法列表}Interface可以被任意对象实现,一个类型/对象也可以实现多个interface;如下面的例子:packagemainimporttypeHuman{nameagephone}typeStudent{Humanschoolloanfloat32}typeEmployee{Humancompanymoneyfloat32}func(hHuman)SayHi(){(,,)}func(hHuman)Sing(lyrics){(,lyrics)}func(eEmployee)SayHi(){(,,,)}typeMen{SayHi()Sing(lyrics)}funcmain(){mike:=Student{Human{,,},,}paul:=Student{Human{,,},,}sam:=Employee{Human{,,},,}tom:=Employee{Human{,,},,}iMeni=mike    ()()()i=()()()()x:=make([]Men,)x[],x[],x[]=paul,sam,mike_,value:=rangex{()}}空接口空interface(interface{})不包含任何的method,正因为如此,。 空interface对于描述起不到任何的作用(因为它不包含任何的method),但是a{}i=s:=a=ia=sinterface的变量里面可以存储任意类型的数值(该类型实现了interface),那么我们怎么反向知道这个interface变量里面实际保存了的是哪个类型的对象呢?目前常用的有两种方法:switch测试、Comma-ok断言。

switch测试如下:typeElement{}typeList[]ElementtypePerson{nameage}func(pPerson)String(){+++()+}funcmain(){list:=make(List,)list[]=list[]=list[]=Person{,}index,element:=rangelist{value:=element.(type){:(,index,value):(,index,value)Person:(,index,value):(,index)}}}如果使用Comma-ok断言的话:funcmain(){list:=make(List,)list[]=list[]=list[]=Person{,}index,element:=rangelist{value,ok:=element.();ok{(,index,value)}value,ok:=element.();ok{(,index,value)}value,ok:=element.(Person);ok{(,index,value)}{(,index)}}}嵌入接口正如struct类型可以包含一个匿名字段,interface也可以嵌套另外一个接口。

如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式的包含了interface1里面的method。 反射所谓反射(reflect)就是能检查程序在运行时的状态。

使用reflect一般分成三步,下面简要的讲解一下:要去反射是一个类型的值(这些值都实现了空interface),首先需要把它转化成reflect对象(或者,根据不同的情况调用不同的函数)。 这两种获取方式如下:t:=(i)v:=(i)转化为reflect对象之后我们就可以进行一些操作了,也就是将reflect对象转化成相应的值,例如tag:=().Field().Tagname:=().Field().String()获取反射值能返回相应的类型和数值xfloat64=v:=(x)(,())(,()==)(,())最后,反射的话,那么反射的字段必须是可修改的,我们前面学习过传值和传引用,这个里面也是一样的道理。

反射的字段必须是可读写的意思是,如果下面这样写,那么会发生错误xfloat64=v:=(x)()如果要修改相应的值,必须这样写xfloat64=p:=(x)v:=()()上面只是对反射的简单介绍,更深入的理解还需要自己在编程中不断的实践。 参考文档:http:///chenny7/p/。