先介紹一下go語(yǔ)言的類(lèi)型系統(tǒng)
Golang中的類(lèi)型系統(tǒng)
類(lèi)型系統(tǒng)是指一個(gè)語(yǔ)言的類(lèi)型體系結(jié)構(gòu)竖般。一個(gè)典型的類(lèi)型系統(tǒng)通常包含如下基本內(nèi)容:
? 基礎(chǔ)類(lèi)型,如byte晦毙、int来惧、bool暇赤、float等;
? 復(fù)合類(lèi)型心例,如數(shù)組、結(jié)構(gòu)體鞋囊、指針等;
? 可以指向任意對(duì)象的類(lèi)型(Any類(lèi)型);
? 值語(yǔ)義和引用語(yǔ)義;
? 面向?qū)ο笾购螅此芯邆涿嫦驅(qū)ο筇卣?比如成員方法)的類(lèi)型;
? 接口。
Go語(yǔ)言中的大多數(shù)類(lèi)型都是值語(yǔ)義溜腐,并且都可以包含對(duì)應(yīng)的操作方法译株。在需要的時(shí)候,你可以給任何類(lèi)型(包括內(nèi)置類(lèi)型)“增加”新方法挺益。而在實(shí)現(xiàn)某個(gè)接口時(shí)歉糜,無(wú)需從 該接口繼承(事實(shí)上,Go語(yǔ)言根本就不支持面向?qū)ο笏枷胫械睦^承語(yǔ)法)望众,只需要實(shí)現(xiàn)該接口 要求的所有方法即可匪补。任何類(lèi)型都可以被Any類(lèi)型引用。Any類(lèi)型就是空接口烂翰,即interface{}夯缺。
什么是結(jié)構(gòu)體
結(jié)構(gòu)體(struct)是用戶自定義的類(lèi)型,它代表若干字段的集合甘耿,可以用于描述一個(gè)實(shí)體對(duì)象喳逛,類(lèi)似java中的class,是golang面向?qū)ο缶幊痰幕A(chǔ)類(lèi)型棵里。
結(jié)構(gòu)體的概念在軟件工程上舊的術(shù)語(yǔ)叫 ADT(抽象數(shù)據(jù)類(lèi)型:Abstract Data Type)。在 C++ 它也存在姐呐,并且名字也是 struct殿怜,在面向?qū)ο蟮木幊陶Z(yǔ)言中,跟一個(gè)無(wú)方法的輕量級(jí)類(lèi)一樣曙砂。因?yàn)?Go 語(yǔ)言中沒(méi)有類(lèi)的概念头谜,所以在 Go 中結(jié)構(gòu)體有著更為重要的地位。
如何定義一個(gè)結(jié)構(gòu)體
type Coordinate struct {
X, Y float32
}
語(yǔ)法:type<Name>struct{}
上述代碼定義個(gè)一個(gè)名為Coordinate
的結(jié)構(gòu)體鸠澈,里面包括了兩個(gè)float32的變量X
,Y
柱告,該結(jié)構(gòu)體可用于表示一個(gè)平面坐標(biāo)截驮。
添加對(duì)象方法
其他的經(jīng)典面向?qū)ο笳Z(yǔ)言,如java际度,C#葵袭,定義對(duì)象方法時(shí),會(huì)包含在class的定義內(nèi)乖菱,如
public class Coordinate{
public float X {get; set;}
public float Y {get; set;}
//打印坐標(biāo)
public void GetCoordinate(){
Console.WriteLine("("+this.X+","+this.Y+")");
}
}
在go語(yǔ)言中坡锡,對(duì)象方法在結(jié)構(gòu)體定義的外部添加
type Coordinate struct {
X, Y float32
}
//打印坐標(biāo)
func (coo *Coordinate) GetCoordinate() {
fmt.Printf("(%.2f,%.2f)\n", coo.X, coo.Y)
return
}
其中,func
關(guān)鍵字后面的(coo *Coordinate)
窒所,表示該函數(shù)傳入一個(gè)指向Coordinate
的指針鹉勒,可通過(guò)指針變量coo
來(lái)操作結(jié)構(gòu)體的值。
幾種結(jié)構(gòu)體初始化
一吵取、按原始字段順序通過(guò)創(chuàng)建結(jié)構(gòu)體
package main
import (
"fmt"
)
func main(){
p0 := Coordinate{1, 2}
p0.GetCoordinate()
}
輸出:(1.00,2.00)
禽额,其中X=1,Y=2
二皮官、按照自定義字段順序進(jìn)行初始化
package main
import (
"fmt"
)
func main(){
p0 := Coordinate{Y:1, X:2}
p0.GetCoordinate()
}
輸出:(2.00,1.00)
脯倒,其中X=2,Y=1
三臣疑、通過(guò)new函數(shù)創(chuàng)建
package main
import (
"fmt"
)
func main(){
//給該結(jié)構(gòu)體p2變量分配內(nèi)存盔憨,它返回指向已分配內(nèi)存的指針
p0 := new(Coordinate)
p0.X=1
p0.Y=2
p0.GetCoordinate()
}
輸出:(1.00,2.00)
,其中X=1讯沈,Y=2
其中p0 := new(Coordinate)
等價(jià)于以下寫(xiě)法
p3 := &Coordinate{X: 1, Y: 2}
p3 := &Coordinate{1,2}
比較三種創(chuàng)建方式
其中郁岩,第一種與第二種,p0
均為一個(gè)類(lèi)型為Coordinate
的實(shí)例缺狠,而第三種p0
為一個(gè)指向Coordinate
的指針问慎,相當(dāng)于var p0 *Coordinate = new(Coordinate)
一般在進(jìn)行例如
type T struct {a, b int}
的結(jié)構(gòu)體定義之后
習(xí)慣使用t := new(T)
給該結(jié)構(gòu)體變量分配內(nèi)存,它返回指向已分配內(nèi)存的指針挤茄。變量t
是一個(gè)指向T
的指針如叼,此時(shí)結(jié)構(gòu)體字段的值是它們所屬類(lèi)型的零值。
聲明var t T
也會(huì)給t
分配內(nèi)存穷劈,并零值化內(nèi)存笼恰,但是這個(gè)時(shí)候 t是類(lèi)型T。在這兩種方式中歇终,t 通常被稱做類(lèi)型T的一個(gè)實(shí)例(instance)
或?qū)ο?code>(Object)社证。var t *T = new(T)
等價(jià)于t := new(T)
。
通過(guò)代碼分析以上結(jié)論
package main
import (
"fmt"
)
func main(){
p0 := Coordinate{1, 2}
//給該結(jié)構(gòu)體p2變量分配內(nèi)存评凝,它返回指向已分配內(nèi)存的指針
p2 := new(Coordinate)
p2.X = 1
p2.Y = 2
p3 := &Coordinate{X: 1, Y: 2}
p4 := &Coordinate{1, 2}
fmt.Println("-------輸出p0-------")
fmt.Printf("%v\n%T\n", p0, p0)
fmt.Println("-------輸出p2-------")
fmt.Printf("%v\n%T\n", p2, p2)
fmt.Println("-------輸出p3-------")
fmt.Printf("%v\n%T\n", p3, p3)
fmt.Println("-------輸出p4-------")
fmt.Printf("%v\n%T\n", p4, p4)
}
輸出:
-------輸出p0-------
{1 2}
Coordinate
-------輸出p2-------
&{1 2}
*Coordinate
-------輸出p3-------
&{1 2}
*Coordinate
-------輸出p4-------
&{1 2}
*Coordinate
可以看出來(lái)追葡,p2,p3,p4均為一個(gè)指針變量
添加值拷貝的對(duì)象方法
剛才說(shuō)到了,添加一個(gè)對(duì)象方法,可以通過(guò)func (t *T) functionname()
來(lái)創(chuàng)建宜肉,其中t
為一個(gè)指針變量匀钧。我們也可以通過(guò)值拷貝的方式,添加一個(gè)對(duì)象方法谬返,語(yǔ)法為func(t T) functionname()
package main
import (
"fmt"
)
type Coordinate struct {
X, Y float32
}
func (coo *Coordinate) GetCoordinate() {
fmt.Printf("(%.2f,%.2f)\n", coo.X, coo.Y)
return
}
//值拷貝對(duì)象方法
func (coo Coordinate) SetPosition01(a float32,b float32) {
coo.X = a
coo.Y = b
}
//指針變量對(duì)象方法
func (coo *Coordinate) SetPosition02(a float32,b float32) {
coo.X = a
coo.Y = b
}
func main(){
p0 := Coordinate{1, 2}
fmt.Print("SetPosition01調(diào)用前:")
p0.GetCoordinate()
p0.SetPosition01(0, 0)
fmt.Print("SetPosition01調(diào)用后:")
p0.GetCoordinate()
fmt.Print("SetPosition02調(diào)用前:")
p0.GetCoordinate()
p0.SetPosition02(0, 0)
fmt.Print("SetPosition02調(diào)用后:")
p0.GetCoordinate()
}
輸出:
SetPosition01調(diào)用前:(1.00,2.00)
SetPosition01調(diào)用后:(1.00,2.00)
SetPosition02調(diào)用前:(1.00,2.00)
SetPosition02調(diào)用后:(0.00,0.00)
從程序輸出中可以看出之斯,調(diào)用SetPosition01
方法,發(fā)生了值拷貝朱浴,即使在方法內(nèi)改變了coo
的值吊圾,外部的p0
的值沒(méi)有被改變。而SetPosition02
方法中翰蠢,coo
為指向p0
地址的指針项乒,由于是通過(guò)指針變量修改了X,Y
的值,所以調(diào)用完畢后梁沧,外部p0
的值會(huì)被修改為(0,0)
匿名結(jié)構(gòu)體
package main
import (
"fmt"
)
func main(){
p_3d := struct {
X, Y, Z float32
}{1, 2, 3}
fmt.Println("-------輸出p_3d-------")
fmt.Printf("%v\n%T\n", p_3d, p_3d)
}
輸出:
-------輸出p_3d-------
{1 2 3}
struct { X float32; Y float32; Z float32 }
p_3d
為一個(gè)包含X,Y,Z
三個(gè)變量的匿名結(jié)構(gòu)體
golang構(gòu)造函數(shù)?
在Go語(yǔ)言中沒(méi)有構(gòu)造函數(shù)的概念檀何,對(duì)象的創(chuàng)建通常交由一個(gè)全局的創(chuàng)建函數(shù)來(lái)完成,以
NewXXX
來(lái)命名廷支,表示“構(gòu)造函數(shù)”:
這一切非常自然频鉴,開(kāi)發(fā)者也不需要分析在使用了new之后到底背后發(fā)生了多少事情。在Go語(yǔ)言中恋拍,一切要發(fā)生的事情都直接可以看到垛孔。
—— 《Go語(yǔ)言編程》
func NewRect(x, y, width, height float64) *Rect {
return &Rect{x, y, width, height}
}
變量、方法可見(jiàn)性
Go語(yǔ)言對(duì)關(guān)鍵字的增加非常吝嗇施敢,其中沒(méi)有private
周荐、protected
、public
這樣的關(guān)鍵 字僵娃。要使某個(gè)符號(hào)對(duì)其他包(package
)可見(jiàn)(即可以訪問(wèn))概作,需要將該符號(hào)定義為以大寫(xiě)字母開(kāi)頭,如:
type Rect struct {
X, Y float64
Width, Height float64
}
這樣默怨,Rect類(lèi)型的成員變量就全部被導(dǎo)出了讯榕,可以被所有其他引用了Rect所在包的代碼訪問(wèn)到。 成員方法的可訪問(wèn)性遵循同樣的規(guī)則匙睹,例如:
func (r *Rect) area() float64 {
return r.Width * r.Height
}
這樣愚屁,Rect
的area()
方法只能在該類(lèi)型所在的包內(nèi)使用。
需要注意的一點(diǎn)是痕檬,Go語(yǔ)言中符號(hào)的可訪問(wèn)性是包一級(jí)的而不是類(lèi)型一級(jí)的集绰。在上面的例 子中,盡管area()
是Rect
的內(nèi)部方法谆棺,但同一個(gè)包中的其他類(lèi)型也都可以訪問(wèn)到它。這樣的可訪問(wèn)性控制很粗曠,很特別改淑,但是非常實(shí)用碍岔。如果Go語(yǔ)言符號(hào)的可訪問(wèn)性是類(lèi)型一級(jí)的,少不 了還要加上friend這樣的關(guān)鍵字朵夏,以表示兩個(gè)類(lèi)是朋友關(guān)系蔼啦,可以訪問(wèn)彼此的私有成員。