Go36-13-結構體及其方法-創(chuàng)新互聯(lián)

結構體及其方法

結構體類型表示的是實實在在的數(shù)據(jù)結構。一個結構體類型可以包含若干個字段,每個字段通常都需要有確切的名字和類型。
結構體類型也可以不包含任何字段,這樣并不是沒有意義的,因為我們還可以為這些類型關聯(lián)上一些方法,這里你可以把方法看做是函數(shù)的特殊版本。
方法和函數(shù)不同,它需要有名字,不能被當作值來看待,最重要的是,它必須隸屬于某一個類型。方法所屬的類型會通過其聲明中的接收者(receiver)聲明體現(xiàn)出來。
方法隸屬的類型其實并不局限于結構體類型,但必須是某個自定義的數(shù)據(jù)類型,并且不能是任何接口類型。

創(chuàng)新互聯(lián)是網(wǎng)站建設技術企業(yè),為成都企業(yè)提供專業(yè)的成都網(wǎng)站建設、成都網(wǎng)站設計,網(wǎng)站設計,網(wǎng)站制作,網(wǎng)站改版等技術服務。擁有十余年豐富建站經(jīng)驗和眾多成功案例,為您定制適合企業(yè)的網(wǎng)站。十余年品質,值得信賴!

方法的使用

接收者聲明就是在關鍵字func和方法名稱之間的那個圓括號包裹起來的內(nèi)容,其中必須包含確切的名稱和類型字面量。這個接收者的類型其實就是當前方法所屬的那個類型,而接收者的名稱,則用于在當前方法中引用它所屬的類型的當前值。
舉個例子:

// AnimalCategory 代表動物分類學中的基本分類法
type AnimalCategory struct {
    kingdom string  // 界
    phylum string  // 門
    class string  // 綱
    order string  // 目
    family string  // 科
    genus string  // 屬
    species string  // 種
}

func (ac AnimalCategory) String() string {
    return fmt.Sprintf(
        "%s%s%s%s%s%s%s", 
        ac.kingdom, 
        ac.phylum, 
        ac.class, 
        ac.order, 
        ac.family, 
        ac.genus, 
        ac.species)
}

在Go語言中,我們可以通過為一個類型編寫名為String的方法,來自定義該類型的字符串表示形式。這個String方法不需要任何參數(shù)聲明,但需要有一個string類型的結果聲明。所以在再用fmt包里的函數(shù)時,會打印出上面自定義的字符串表示形式,而無需顯示的調用它的String方法。
我們可以把結構體類型中的一個字段看作是它的一個屬性或者一項數(shù)據(jù),再把隸屬于它的一個方法看作是附加在其中數(shù)據(jù)之上的一個能力或者一項操作。將屬性及其能力(或者說數(shù)據(jù)及其操作)封裝在一起,是面向對象編程(object-orientedprogramming)的一個主要原則。

匿名字段

下面聲明了一個結構體類型Animal,有兩個字段,一個是string類型的scientificName。另一個字段聲明中只有AnimalCategory,就是上面示例的那個結構體的名字:

type Animal struct {
    scientificName string // 學名
    AnimalCategory  // 動物基本分類
}

字段聲明AnimalCategory代表了Animal類型的一個嵌入字段。Go語言規(guī)范規(guī)定,如果一個字段的聲明中只有字段的類型名而沒有字段的名稱,那么它就是一個嵌入字段,也可以被稱為匿名字段。我們可以通過此類型變量的名稱后跟“.”,再后跟嵌入字段類型的方式引用到該字段。也就是說,嵌入字段的類型既是類型也是名稱。
強調一下,Go語言中沒有繼承的概念,它所做的是通過嵌入字段的方式實現(xiàn)了類型之間的組合

簡單來說,面向對象編程中的繼承,其實是通過犧牲一定的代碼簡潔性來換取可擴展性,而且這種可擴展性是通過侵入的方式來實現(xiàn)的。類型之間的組合采用的是非聲明的方式,我們不需要顯式地聲明某個類型實現(xiàn)了某個接口,或者一個類型繼承了另一個類型。
同時,類型組合也是非侵入式的,它不會破壞類型的封裝或加重類型之間的耦合。我們要做的只是把類型當做字段嵌入進來,然后坐享其成地使用嵌入字段所擁有的一切。如果嵌入字段有哪里不合心意,我們還可以用“包裝”或“屏蔽”的方式去調整和優(yōu)化。

值方法和指針方法

方法的接收者類型必須是某個自定義的數(shù)據(jù)類型(不能是接口)。所謂的值方法,就是接收者類型是非指針的自定義數(shù)據(jù)類型的方法。之前的示例中的方法都是值方法。
下面的這個就是指針方法:

func (a *Animal) SetScientificName(name string) {
    a.scientificName = name
}

方法的接受者類型是*Animal,是一個指針類型。這時Animal可以被叫做*Animal的基本類型。可以認為,指針類型的值就是指向某個基本類型值的指針。指針方法,就是接收者類型是上述指針類型的方法。

值方法和指針方法之間的不同點:

  1. 值方法的接收者是方法所屬類型的一個副本。在方法內(nèi)對副本的修改一般不會提現(xiàn)在原值上,除非這個類型本身是某個引用類型。而指針方法內(nèi)對的修改是一定會提現(xiàn)在原值上的。
  2. 嚴格來講,通過值只能調用到值方法,通過指針只能調用到指針方法。但是,Go會適時的進行自動的轉義,使得通過值也能調用到它的指針方法。比如,Animal.SetScientificName("Duck")會自動轉義為(&Animal).SetScientificName("Duck"),即:先取指針值,然后再在改指針值上調用指針方法。
  3. 這條和接口相關,一個類型的方法集合中有哪些方法與它能實現(xiàn)哪些接口類型是息息相關的。如果一個基本類型和它的指針類型的方法集合是不同的,那么它們具體實現(xiàn)的接口類型的數(shù)量就也會有差異,除非這兩個數(shù)量都是零。比如,一個指針類型實現(xiàn)了某某接口類型,但它的基本類型卻不一定能夠作為該接口的實現(xiàn)類型。

這個是驗證上述差異的示例:

package main

import "fmt"

type Cat struct {
    name           string // 名字。
    scientificName string // 學名。
    category       string // 動物學基本分類。
}

func New(name, scientificName, category string) Cat {
    return Cat{
        name:           name,
        scientificName: scientificName,
        category:       category,
    }
}

func (cat *Cat) SetName(name string) {
    cat.name = name
}

func (cat Cat) SetNameOfCopy(name string) {
    cat.name = name
}

func (cat Cat) Name() string {
    return cat.name
}

func (cat Cat) ScientificName() string {
    return cat.scientificName
}

func (cat Cat) Category() string {
    return cat.category
}

func (cat Cat) String() string {
    return fmt.Sprintf("%s (category: %s, name: %q)",
        cat.scientificName, cat.category, cat.name)
}

func main() {
    cat := New("little pig", "American Shorthair", "cat")
    cat.SetName("monster") // (&cat).SetName("monster")
    fmt.Printf("The cat: %s\n", cat)

    cat.SetNameOfCopy("little pig")
    fmt.Printf("The cat: %s\n", cat)

    type Pet interface {
        SetName(name string)
        Name() string
        Category() string
        ScientificName() string
    }

    _, ok := interface{}(cat).(Pet)
    fmt.Printf("Cat implements interface Pet: %v\n", ok)  // false
    _, ok = interface{}(&cat).(Pet)
    fmt.Printf("*Cat implements interface Pet: %v\n", ok)  // true
}

這里牽涉到了接口的知識點,所以這個例子和下面的內(nèi)容,下一篇還會再講一遍。
最后的2行輸出的內(nèi)容,說明cat沒有實現(xiàn)Pet的接口,而&cat是實現(xiàn)了Pet的接口。
因為要實現(xiàn)Pet接口需要實現(xiàn)接下的那4個方法。而Cat類型沒有實現(xiàn)SetName方法,所以cat沒有實現(xiàn)Pet接口。代碼中SetName方法是通過*Cat實現(xiàn)的,另外其他的3個方法都已經(jīng)通過Cat實現(xiàn)了,通過*Cat也能調用(差異的第2條),所以只有指針方法實現(xiàn)了Pet接口的所有方法。

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡助力業(yè)務部署。公司持有工信部辦法的idc、isp許可證, 機房獨有T級流量清洗系統(tǒng)配攻擊溯源,準確進行流量調度,確保服務器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務器買多久送多久。

本文題目:Go36-13-結構體及其方法-創(chuàng)新互聯(lián)
轉載來源:http://bm7419.com/article48/ijdep.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供微信公眾號軟件開發(fā)、定制網(wǎng)站網(wǎng)站制作、電子商務、網(wǎng)站策劃

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司