golang結(jié)構(gòu)體看這篇就夠啦

struct概述

結(jié)構(gòu)體是go語(yǔ)言最重要的數(shù)據(jù)結(jié)構(gòu)之一,go和其它編程語(yǔ)言不一樣,它沒(méi)有類的概念卵佛,類比過(guò)來(lái)struct就相當(dāng)于其它語(yǔ)言中的類,因此十分重要饼灿。

結(jié)構(gòu)體這部分涉及到的知識(shí)點(diǎn)頁(yè)比較多疑苫,此文偏長(zhǎng),請(qǐng)耐心閱讀抽高。

1. 認(rèn)識(shí)結(jié)構(gòu)體

直接說(shuō)語(yǔ)法往往非车勒担枯燥因苹,在正式開(kāi)始前,我們先來(lái)看一段簡(jiǎn)單的結(jié)構(gòu)體代碼鞭呕,建立整體感知蛤育,后續(xù)我們?cè)僖灰患?xì)說(shuō)其中的知識(shí)點(diǎn)。

package main

import "fmt"

// Person結(jié)構(gòu)體 - 相當(dāng)于類
type Person struct {
    Name string // 字段Name 類型為string
    Age  int8   // 字段Age  類型為int8
}

// 實(shí)例方法
func (p Person) GetName() {
    fmt.Printf("My name: %s\n", p.Name)
}

func main() {
    p := Person{
        Name: "zhangsan",
        Age:  18,
    }

    p.GetName()
}

// My name: zhangsan

看到了吧,還是很簡(jiǎn)單的,跟著注釋你大概已經(jīng)看懂了如何使用葫松。
下面我們拆分成知識(shí)點(diǎn)細(xì)細(xì)分析

1.1 如何定義

它按照如下方式定義(PS: 它還可以代標(biāo)簽瓦糕,為簡(jiǎn)單起見(jiàn),這里暫且不討論)

// 如下格式
type 結(jié)構(gòu)體名 struct {
  字段名1 字段類型1
  字段名2 字段類型2
  .....
}

1.2 實(shí)例化

主要有幾種方式:

var p = new(Person) // 這里返回的是實(shí)力化后的地址  注意地址哈
var p Person        // 它是值類型 所以這種相當(dāng)于零值初始化
var p = Person{}    // 這種和上面等效

// 這是一種最標(biāo)準(zhǔn)的賦值方式 把每個(gè)字段名都寫(xiě)了出來(lái)
p := Person{
    Name: "zhangsan",
    Age:  18,
}

// 可以省略字段名
p := Person{"zhangsan", 18}

實(shí)際例化后我們可以通過(guò)obj.字段名的方式調(diào)出值腋么,如上例中p.Name

1.3 方法

結(jié)構(gòu)體方法,對(duì)應(yīng)到面向?qū)ο笳Z(yǔ)言中就是實(shí)例方法.

在上例中,如下部分:

// 實(shí)例方法
func (p Person) GetName() {
    fmt.Printf("My name: %s\n", p.Name)
}

// 在這里 p Person稱為接收者 后續(xù)為方法名
// 定義后 我們可以同 obj.方法名調(diào)用

方法和函數(shù)有什么主要區(qū)別呢咕娄?

方法它有接收者,而函數(shù)沒(méi)有

1.4 接收者

接收者既可以是值也可以是指針類型,我們看下:

package main

import "fmt"

// Person結(jié)構(gòu)體 - 相當(dāng)于類
type Person struct {
    Name string // 字段Name 類型為string
    Age  int8   // 字段Age  類型為int8
}

// 值接收者
func (p Person) GetName() {
    fmt.Printf("My name: %s\n", p.Name)
}

// 指針接收者
func (p *Person) GetAge() {
    fmt.Printf("My age: %d\n", p.Age)
}

func main() {
    p1 := Person{Name: "張三", Age: 18}  // 值
    p2 := &Person{Name: "李四", Age: 16} // 指針

    // 值對(duì)象可以同時(shí)調(diào)用 值接收者 和 指針接收者方法
    p1.GetName()
    p1.GetAge()

    fmt.Println("---------分割線-------")
    // 指針對(duì)象可以同時(shí)調(diào)用 值接收者 和 指針接收者方法
    p2.GetName()
    p2.GetAge()
}

// My name: 張三
// My age: 18
// ---------分割線-------
// My name: 李四
// My age: 16

我們可以發(fā)現(xiàn)党晋,無(wú)論接收者是值類型還是指針類型,它們?cè)谡{(diào)用上卻不會(huì)有任何區(qū)別谭胚,這是因?yàn)間o編譯器會(huì)悄悄自動(dòng)幫我轉(zhuǎn)換, nice!

1.5 指針接收者or值接收者

那么什么時(shí)候使用值接收者啥時(shí)候用指針接收者呢?

  1. 在go中一般約定,同一個(gè)struct接收者類型保持一致(要么全是指針接收者,要么全是值接收者
  2. 值接收者: 結(jié)構(gòu)體相對(duì)較形床!(拷貝成本不高)灾而,不需要改變結(jié)構(gòu)體內(nèi)部值場(chǎng)景
  3. 指針接收者: 結(jié)構(gòu)體比較大(拷貝成本高),需要改變結(jié)構(gòu)體內(nèi)部值場(chǎng)景

2. 匿名字段及嵌套

匿名字段可以說(shuō)是結(jié)構(gòu)體最有用的功能,使用的地方比比皆是,下面我們來(lái)看下

2.1 匿名字段

所謂匿名字段指的是在結(jié)構(gòu)體中字段名可以不用顯示寫(xiě)出來(lái),比如:

package main

import "fmt"

type Data struct {
    uint8 // 沒(méi)有結(jié)構(gòu)體字段名 只有類型名
          // 此時(shí)字段名 == 類型名
}

func main() {
    d := Data{8}
    // 直接通過(guò)類型名調(diào)用
    fmt.Println(d.uint8)
}

// 8

關(guān)鍵點(diǎn)在于字段名 == 類型名

2.2 結(jié)構(gòu)體嵌套

在開(kāi)始之前我們來(lái)看下兩個(gè)結(jié)構(gòu)體

// 人結(jié)構(gòu)體
type Person struct {
    Name string // 姓名
    Age  int8   // 年齡
}

// 結(jié)構(gòu)體
type Student struct {
    ID    int     // 學(xué)生id
    Name  string  // 姓名
    Age   int8    // 年齡
    Score float32 // 分?jǐn)?shù)
}

我們會(huì)發(fā)現(xiàn)學(xué)生結(jié)構(gòu)體和人結(jié)構(gòu)體相比只多了兩個(gè)字段(IDScore)分別定義有點(diǎn)浪費(fèi)扳剿?
另外人和學(xué)生有許多相似的地方,某些時(shí)候Person結(jié)構(gòu)體中的方法,Student同樣也需要旁趟,如果分別寫(xiě)兩份相同的方法,也很浪費(fèi)庇绽?

好啦锡搜!在go中可以通過(guò)嵌套解決,直接看代碼

package main

import "fmt"

type Person struct {
    Name string // 姓名
    Age  int8   // 年齡
}

// person結(jié)構(gòu)體方法
func (p Person) GetName() {
    fmt.Printf("My name: %s\n", p.Name)
}

type Student struct {
    ID     int     // 學(xué)生id
    Score  float32 // 分?jǐn)?shù)
    Person         // 嵌套Person結(jié)構(gòu)體 這里是匿名字段
}

func (s Student) GetScore() {
    fmt.Printf("My score: %v\n", s.Score)
}

func main() {
    p := Student{
        ID:    1,
        Score: 98,
        Person: Person{ // 這里是匿名字段 字段名 == 字段類型
            Name: "zhangsan",
            Age:  18,
        },
    }

    // 調(diào)用嵌套結(jié)構(gòu)體字段
    fmt.Printf("My age: %d\n", p.Age)                     // 直接調(diào)用 嵌套結(jié)構(gòu)體字段
    fmt.Printf("My age p.Person.age: %d\n", p.Person.Age) // 通過(guò)匿名字段間接調(diào)用

    p.GetScore()       // 調(diào)用自己方法
    p.GetName()        // 直接調(diào)用嵌套結(jié)構(gòu)體字段
    p.Person.GetName() // 通過(guò)匿名字段間接調(diào)用
}

// My age: 18
// My age p.Person.age: 18
// My score: 98
// My name: zhangsan
// My name: zhangsan

上面的注釋已經(jīng)非常詳細(xì),這里總結(jié)下規(guī)律:

匿名結(jié)構(gòu)體嵌套瞧掺,會(huì)有如下效果:

  1. 匿名結(jié)構(gòu)體中字段,當(dāng)前結(jié)構(gòu)體可以直接調(diào)用
  2. 匿名結(jié)構(gòu)體方法,當(dāng)前結(jié)構(gòu)體可以直接調(diào)用

本質(zhì)是:go在字段查找時(shí),現(xiàn)在本結(jié)構(gòu)體中找耕餐,如果找不到則到匿名結(jié)構(gòu)體中查找;方法同理

2.3 匿名結(jié)構(gòu)體嵌套經(jīng)典使用

數(shù)據(jù)庫(kù)表設(shè)計(jì)中:
我們可以把常用的字段抽出來(lái)成一個(gè)結(jié)構(gòu)體辟狈,其它結(jié)構(gòu)體只需要引入就可以擴(kuò)展其中字段以及方法肠缔,比如:

package main

import (
    "fmt"
    "time"
)

type BaseTable struct {
    ID        int
    CreatedAt time.Time
    UpdatedAt time.Time
}

type User struct {
    Name      string
    BaseTable // 擴(kuò)展User
}

3. 方法值和方法表達(dá)式

方法值和方法表達(dá)式類似于函數(shù)表達(dá)式,我們可以將函數(shù)表達(dá)式當(dāng)作變量傳遞,方法值和方法表達(dá)式也是一樣,文字上不太容易明白,直接看代碼

package main

import (
    "fmt"
)

type Person struct {
    Name string
    Age  int8
}

func (p Person) GetName() {
    fmt.Printf("My name: %s\n", p.Name)
}

func main() {
    p := Person{Name: "zhangsan", Age: 18}

    // 方法值
    getName := p.GetName
    getName() // 調(diào)用方法值

    fmt.Println("--------分割線-------")
    // 方法表達(dá)方式
    pGetName := Person.GetName
    pGetName(p) // 方法表達(dá)式需要傳遞接收者
}

// My name: zhangsan
// --------分割線-------
// My name: zhangsan

它可以做為變量取出,因此可以實(shí)現(xiàn)復(fù)雜精巧場(chǎng)景下的使用哼转,舉例這里不做舉例,方法值和方法表達(dá)式的區(qū)別在于:

方法表達(dá)式需要把接收者做為參數(shù)傳入

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末明未,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子壹蔓,更是在濱河造成了極大的恐慌趟妥,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佣蓉,死亡現(xiàn)場(chǎng)離奇詭異披摄,居然都是意外死亡亲雪,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)行疏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匆光,“玉大人,你說(shuō)我怎么就攤上這事酿联≈障ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵贞让,是天一觀的道長(zhǎng)周崭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)喳张,這世上最難降的妖魔是什么续镇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮销部,結(jié)果婚禮上摸航,老公的妹妹穿的比我還像新娘。我一直安慰自己舅桩,他們只是感情好酱虎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著擂涛,像睡著了一般读串。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上撒妈,一...
    開(kāi)封第一講書(shū)人閱讀 49,792評(píng)論 1 290
  • 那天恢暖,我揣著相機(jī)與錄音,去河邊找鬼狰右。 笑死杰捂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棋蚌。 我是一名探鬼主播琼娘,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼附鸽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起瞒瘸,我...
    開(kāi)封第一講書(shū)人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坷备,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后情臭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體省撑,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赌蔑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竟秫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娃惯。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肥败,靈堂內(nèi)的尸體忽然破棺而出趾浅,到底是詐尸還是另有隱情,我是刑警寧澤馒稍,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布皿哨,位于F島的核電站,受9級(jí)特大地震影響纽谒,放射性物質(zhì)發(fā)生泄漏证膨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一鼓黔、第九天 我趴在偏房一處隱蔽的房頂上張望央勒。 院中可真熱鬧,春花似錦澳化、人聲如沸崔步。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刷晋。三九已至,卻和暖如春慎陵,著一層夾襖步出監(jiān)牢的瞬間眼虱,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工席纽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捏悬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓润梯,卻偏偏與公主長(zhǎng)得像过牙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纺铭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

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