golang類和結(jié)構(gòu)體

golang結(jié)構(gòu)體和類

golang中并沒有明確的面向?qū)ο蟮恼f法,實(shí)在要扯上的話,可以將struct比作其它語言中的class。

類聲明

type Poem struct {
    Title  string
    Author string
    intro  string
}

這樣就聲明了一個(gè)類,其中沒有public、protected、private的的聲明。golang用另外一種做法來實(shí)現(xiàn)屬性的訪問權(quán)限:屬性的開頭字母是大寫的則在其它包中可以被訪問,否則只能在本包中訪問。類的聲明和方法亦是如此。

類方法聲明

func (poem *Poem) publish() {
    fmt.Println("poem publish")
}

或者

func (poem Poem) publish() {
    fmt.Println("poem publish")
}

和其它語言不一樣,golang聲明方法和普通方法一致,只是在func后增加了poem Poem這樣的聲明。加和沒有加*的區(qū)別在于一個(gè)是傳遞指針對(duì)象,一個(gè)是傳遞值對(duì)象。

傳遞指針和對(duì)象的區(qū)別

type T struct {
    Name string
}

func (t T) M1() {
    t.Name = "name1"
}

func (t *T) M2() {
    t.Name = "name2"
}

M1() 的接收者是值類型 T, M2() 的接收者是值類型 *T , 兩個(gè)方法內(nèi)都是改變Name值。

下面聲明一個(gè) T 類型的變量,并調(diào)用 M1() 和 M2() 。

    t1 := T{"t1"}

    fmt.Println("M1調(diào)用前:", t1.Name)
    t1.M1()
    fmt.Println("M1調(diào)用后:", t1.Name)

    fmt.Println("M2調(diào)用前:", t1.Name)
    t1.M2()
    fmt.Println("M2調(diào)用后:", t1.Name)

輸出結(jié)果為:

M1調(diào)用前: t1
M1調(diào)用后: t1
M2調(diào)用前: t1
M2調(diào)用后: name2

下面猜測(cè)一下go會(huì)怎么處理。

先來約定一下:接收者可以看作是函數(shù)的第一個(gè)參數(shù),即這樣的: func M1(t T), func M2(t *T)。 go不是面向?qū)ο蟮恼Z言,所以用那種看起來像面向?qū)ο蟮恼Z法來理解可能有偏差。

當(dāng)調(diào)用 t1.M1() 時(shí)相當(dāng)于 M1(t1) ,實(shí)參和行參都是類型 T,可以接受。此時(shí)在M1()中的t只是t1的值拷貝,所以M1()的修改影響不到t1。

當(dāng)調(diào)用 t1.M2() => M2(t1),這是將 T 類型傳給了 *T 類型,go可能會(huì)取 t1 的地址傳進(jìn)去: M2(&t1)。所以 M2() 的修改可以影響 t1 。

匿名結(jié)構(gòu)體

p := struct {
    Name string
    Gender string
    Age uint8
}{"Robert", "Male", 33}

匿名結(jié)構(gòu)體最大的用處是在內(nèi)部臨時(shí)創(chuàng)建一個(gè)結(jié)構(gòu)以封裝數(shù)據(jù),而不必正式為其聲明相關(guān)規(guī)則。

實(shí)例化對(duì)象

實(shí)例化對(duì)象有好幾種方式

poem := &Poem{}

poem.Author = "Heine"

poem2 := &Poem{Author: "Heine"}

poem3 := new(Poem)

poem3.Author = "Heine"

poem4 := Poem{}

poem4.Author = "Heine"

poem5 := Poem{Author: "Heine"}

實(shí)例化的時(shí)候可以初始化屬性值,如果沒有指明則默認(rèn)為系統(tǒng)默認(rèn)值
注意:

p1 := &Poem{
        "zhangsan",
        25,
        []string{"lisi", "wangwu"},
    }

使用中如果包含數(shù)組,結(jié)構(gòu)體的實(shí)例化需要加上類型如上如果intro的類型是[]string。

加&符號(hào)和new的是指針對(duì)象,沒有的則是值對(duì)象,這點(diǎn)和php、java不一致,在傳遞對(duì)象的時(shí)候要根據(jù)實(shí)際情況來決定是要傳遞指針還是值。

tips:當(dāng)對(duì)象比較小的時(shí)候傳遞指針并不劃算。

構(gòu)造函數(shù)(自己創(chuàng)造)

func NewPoem(param string, p ...interface{}) *Poem

示例:

func NewPoem(author string) (poem *Poem) {
    poem = &Poem{}
    poem.Author = author
    return
}

poem6 := NewPoem("Heine")

繼承

確切的說golang中叫做組合(composition)

func (e *Poem) ShowTitle() {
    fmt.Printf(e.Title)
}
type Poem struct {
    Title  string
    Author string
    intro  string
}

type ProsePoem struct {
    Poem
    Author string
}

ProsePoem屬性中聲明了Poem,表示組合了Poem的屬性和方法(屬性和方法都會(huì)被繼承)。

初始化方式

1、先初始化為空再賦值

prosePoem := &ProsePoem{}
prosePoem.author = "Heine"

2、直接賦值

prosePoem := &ProsePoem{
        Poem: Poem{
            Title:  "Jack",
            Author: "slow",
            intro:  "simple",
        },
        Author: "test",
    }

如果其中屬性有沖突,則以外圍的為主,也就是說會(huì)被覆蓋。

type ProsePoem struct {
    Poem
    Author string
}

當(dāng)訪問Author的時(shí)候默認(rèn)為ProsePoem的Author,如果需要訪問Poem的Author屬性可以使用
prosePoem.Poem.Author來訪問方法同理**。

prosePoem := &ProsePoem{}

prosePoem.Author = "Shelley"

prosePoem.Poem.Author = "Heine"

fmt.Println(prosePoem)

從輸出中可以很直觀看到這一點(diǎn)。

&{{ Heine } Shelley}

方法的繼承和屬性一致,這里不再羅列。通過組合的話可以很好的實(shí)現(xiàn)多繼承。

多繼承

比如有一個(gè)父親,是中國人:

type Father struct {
    MingZi string
}

func (this *Father) Say() string {
    return "大家好,我叫 " + this.MingZi
}

可以理解為父親類有一個(gè)屬性,有一個(gè)Say方法

有父親當(dāng)然有母親,母親是個(gè)外國人:

type Mother struct {
    Name string
}

func (this *Mother) Say() string {
    return "Hello, my name is " + this.Name
}

父親和母親結(jié)合有了孩子類,孩子類繼承了父親和母親:

type Child struct {
    Father
    Mother
}

然后孩子類有一個(gè)實(shí)例c:

    c := new(Child)
    c.MingZi = "張小明"
    c.Name = "Tom Zhang"

因?yàn)镸ingZi和Name這個(gè)屬性在Mother和Father中并沒有沖突,所以可以直接使用 c. 就可以獲取而沒有問題

但是,如果這樣直接調(diào)用Child類的Say方式:

c.Say()

會(huì)出現(xiàn)沖突:

ambiguous selector c.Say

怎么辦?其實(shí)這樣就可以輕松解決:

    c.Father.Say()
    c.Mother.Say()

上面兩條表達(dá)式的值分別為:

大家好,我叫 張小明
Hello, my name is Tom Zhang

方法重載

方法重載就是一個(gè)類中可以有相同的函數(shù)名稱,但是它們的參數(shù)是不一致的,在java、C++中這種做法普遍存在。golang中如果嘗試這么做會(huì)報(bào)重新聲明(redeclared)錯(cuò)誤,但是golang的函數(shù)可以聲明不定參數(shù),這個(gè)非常強(qiáng)大。

func (poem *Poem) recite(v ...interface{}) {

fmt.Println(v)

}

其中v …interface{}表示參數(shù)不定的意思,其中v是slice類型,fmt.Println方法也是這樣定義的。如果要根據(jù)不同的參數(shù)實(shí)現(xiàn)不同的功能,要在方法內(nèi)檢測(cè)傳遞的參數(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 《Go語言四十二章經(jīng)》第二十章 方法 作者:李驍 在前面我們講了結(jié)構(gòu)(struct)和接口(interface),...
    ffhelicopter閱讀 2,787評(píng)論 3 8
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法,可以作為本類的靜態(tài)方法來...
    XLsn0w閱讀 1,428評(píng)論 0 2
  • 面向?qū)ο笾饕槍?duì)面向過程。 面向過程的基本單元是函數(shù)。 什么是對(duì)象:EVERYTHING IS OBJECT(萬物...
    sinpi閱讀 1,220評(píng)論 0 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,675評(píng)論 1 32
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,017評(píng)論 0 11

友情鏈接更多精彩內(nèi)容