Golang中引入了在Golang中独有的struct和interface,其意义和传统语言中的不同。
struct是一个class但是没有virtual方法,比如说:
typeRectanglestruct{NamestringWidth,Heightfloat64}func(rRectangle)Area()float64{returnr.Width+r.Height}那么伪代码如下:
classRectanglefieldName:stringfieldWidth:float64fieldHeight:float64methodArea()//non-virtualreturnthis.Width*this.Height构造器functionconstruct(class,literal)helperfunctionassignFields(object,literal)//recursiveiftype-ofobjectis"object"ifliteralhasfield-namesforeachfieldinobject.fieldsifliteralhas-fieldfield.nameassignFields(field.value,literal.fields[field.name].value)//recurseelse//literalwithoutnames,assignbypositionforn=0toobject.fields.lengthassignFields(object.fields[n].value,literal.fields[n].value)//recurseelse//atomtypesetobject.value=literal.value//genericconstructormainbodyvarclassInstance=newclassassignFields(classInstance,literal)returnclassInstance对于Golang的构造器使用
packagemainimport."fmt"typeRectanglestruct{NamestringWidth,Heightfloat64}funcmain(){varaRectanglevarb=Rectangle{"I'mb.",10,20}varc=Rectangle{Height:12,Width:14}Println(a)Println(b)Println(c)}Golang中的嵌入类似于OOP中的没有virtual方法的多继承将一个结构体嵌入到另一个结构体,就好像是对非虚成员的多继承。让我们看看一个例子:
typebasestruct{astringbint}typederived{base//嵌入dintafloat32//隐藏base中的a字段}funcmain(){varxderived;fmt.Printf("%T",x.a)//x.afloat32fmt.Printf("%T",x.base.a)//=>x.}当base结构体嵌入到derived结构体中,那么base结构体中的字段和方法都可以在derived结构体中都可用。但是base内部的字段可以被derived中的字段shadowed。在内部,有一个名称叫base类型为base的字段被创建,。如果将base嵌入到了derived,那么在derived类型可以直接访问base的字段。
Shadowing表示在derived中定义另一个与base字段和方法相同名字的字段和方法,那么就会存在shadowinig这种情况。一但base中的字段被derived中的shadow,那么可以通过使用base名称来访问隐藏的字段。所有base中的字段,都可以通过隐藏字段的名称base来访问。需要注意的事情:
Itisimportanttonotethatallinheritedmethodsarecalledonthehidden-field-struct.Itmeansthatabasemethodcannotseeorknowaboutderivedmethodsorfields.Everythingisnon-virtual.
当和结构体和嵌入这种概念打交道的时候,我们应该知道所有的东西都是在编译期间静态绑定的,所以的引用解析都是在静态编译期间。
Whenworkingwithstructsandembedding,everythingisSTATICALLYLINKED.Allreferencesareresolvedatcompiletime.
typeNamedObjstruct{Namestring}typeShapestruct{NameObjcolorstringisRegularbool}typePointstruct{x,yfloat64}typeRectanglestruct{NameObjShapecenterPointWidthfloat64Heightfloat64}funcmain(){varaRect=Rectange{NameObj{"name1"},Shape{NameObj{"name2"},0,true},Point{0,0},20,2.5}fmt.Println(aRect.Name)fmt.Println(aRect.Shape)fmt.Println(aRect.Shape.Name)}等效的伪代码:
classNamedObjfieldName:stringclassShapeinheritsNamedObjfieldcolor:int32fieldisRegular:boolclassRectangleinheritsNamedObjinheritsShapefieldcenter:PointfieldWidth:float64fieldHeight:float64在varaRectRectangle中,
由于所有的golang-struct都是non-virtual的,所以你不可以覆盖这些方法。(当然接口是可以的)比如在NameObj中定义了一个名字叫做show的方法,但是呢,你在structRectangle中也定义了其他的方法,那么Rectangle/show()将会隐藏NameObj/show方法。正如基类的字段一样,你也可以通过使用基类的名称来访问基类被隐藏的方法。
typebasestruct{astringbint}func(thisbase)xyz(){fmt.Println("xyz,ais",this.a);}//methoddisplayfunc(thisbase)display(){fmt.Println("base,ais:",this.a)}typederivedstruct{base//embeddingdintafloat32//-SHADOWED}//methoddisplayfunc(thisderived)display(){fmt.Println("derivedais",this.a)}funcmain(){varaderived=derived{base{"base-a",10},20,2.5}a.display()//2.5a.base.diplay()//base,ais:base-aa.xyz();//callbase.xyz(),xyz,ais:base-a}Golang方法和接受者Golang的struct-method,和类的non-virtual方法类似,但是在如下地方不同:
typeNameObjstruct{Namestring}func(nNameObj)show(){fmt.Println(n.Name)}struct和interfaceGolang中的interface是一个没有字段的,只有虚方法。interface的设计是为了补充struct。在Golang中
**Structs:**classes,withfields,ALLNON-VIRTUALmethods**Interfaces:**classes,withNOfields,ALLVIRTUALmethods
通过严格限定struct是没有virtual的方法,interface是包含所有virtual的方法,通过嵌入来将两者结合起来,从而实现多态。
Golanginterface是一个没有字段的类,但是包含所有是virtual的函数。考虑到这种定义,那么你能够用interface干的事情:
在Golang中空接口是没有任何字段和没有任何方法,所以任何struct和基本类型都实现了interface{},这意味着varxinterface{}可以容纳任何类型的值。那么我们可以使用interface{}来干什么事情呢?本来什么事情都不可以干,但是我们可以使用typeswitch,typeassertion或反射
当你使用structembedding,那么你就是要创建一个multi-root体系,通过多继承。你要记住的是,所有的结构体方法都是non-virtual的。这就是为什么struct永远要比使用接口嵌入要快。因为没有接口涉及的时候,所有的函数的调用都是在编译期间就决定了。