玩轉(zhuǎn)Golang之Struct結(jié)構(gòu)體

先介紹一下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周荐、protectedpublic這樣的關(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
} 

這樣愚屁,Rectarea()方法只能在該類(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)彼此的私有成員。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仰猖,一起剝皮案震驚了整個(gè)濱河市捏肢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饥侵,老刑警劉巖鸵赫,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異躏升,居然都是意外死亡辩棒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)膨疏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)一睁,“玉大人,你說(shuō)我怎么就攤上這事佃却≌哂酰” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵饲帅,是天一觀的道長(zhǎng)复凳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)洒闸,這世上最難降的妖魔是什么染坯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮丘逸,結(jié)果婚禮上单鹿,老公的妹妹穿的比我還像新娘。我一直安慰自己深纲,他們只是感情好仲锄,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著湃鹊,像睡著了一般儒喊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上币呵,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天怀愧,我揣著相機(jī)與錄音侨颈,去河邊找鬼。 笑死芯义,一個(gè)胖子當(dāng)著我的面吹牛哈垢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扛拨,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼耘分,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绑警?” 一聲冷哼從身側(cè)響起求泰,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎计盒,沒(méi)想到半個(gè)月后渴频,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡章郁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年枉氮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暖庄。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡聊替,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出培廓,到底是詐尸還是另有隱情惹悄,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布肩钠,位于F島的核電站泣港,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏价匠。R本人自食惡果不足惜当纱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望踩窖。 院中可真熱鬧坡氯,春花似錦、人聲如沸洋腮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)啥供。三九已至悯恍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伙狐,已是汗流浹背涮毫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工瞬欧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窒百。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓黍判,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親篙梢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容