首頁 > 軟體

Go語言之嵌入型別詳解

2022-07-12 22:06:45

一、什麼是嵌入型別

先看如下程式碼:

type user struct {
    name string
    email string
}

type admin struct {
    user // Embedded Type
    level string
}

可以看到admin結構中的一個成員是user,那麼admin中就嵌入了user型別。

  • admin也叫做外部型別
  • user也叫做內部型別

二、外部型別和內部型別之間的關係和機制

func (u *user) notify() {
    fmt.Printf("Sending user email to %s<%s>n",
        u.name,
        u.email)
}

如上程式碼,實現了一個方法notify(),接收者是 *user。

func main() {
    // Create an admin user.
    ad := admin{
        user: user{
            name: "john smith",
            email: "john@yahoo.com",
        },
        level: "super",
    }
    // We can access the inner type's method directly.
    ad.user.notify()
    // The inner type's method is promoted.
    ad.notify()
}

main函數中定義了一個變數ad,並且進行了賦值

執行:

Sending user email to john smith<john@yahoo.com>
Sending user email to john smith<john@yahoo.com>

①沒有編譯錯誤

②notify()可以被ad.user呼叫是可以理解的,但是ad.notify()也能執行是為什麼。

這裡涉及到了一個嵌入型別背後的機制,內部型別提升 (感覺有點像C#、Java裡面的繼承,user是父類別,admin是子類,admin的範例物件直接呼叫了父類別的notify方法。)

進一步研究:我們再定義一個介面、以及一個接受該介面的函數。

介面,只有一個方法notify

type notifier interface {
    notify()
}

函數,接受一個實現notifier介面的型別範例,內部就是呼叫notify方法

func sendNotification(n notifier) {
    n.notify()
}

main方法如下

func main() {
    // Create an admin user.
    ad := admin{
        user: user{
            name: "john smith",
            email: "john@yahoo.com",
        },
        level: "super",
    }
    
    var user = ad.user
    sendNotification(&user)

    sendNotification(&ad)
}

執行結果:

Sending user email to john smith<john@yahoo.com>
Sending user email to john smith<john@yahoo.com>

①可以看到這裡傳入 &user和&ad都是可以的,說明型別提升導致admin也是實現了notifier介面了。

②為什麼穿&user和&ad,而不是直接傳user和ad,這就涉及到了之前總結過的【方法集】的概念了。複習一下:

從上面兩個表,可以知道由於方法的接收者是 *user ,所以說只有*user實現了該介面的方法,這就是為什麼輸入&user、&ad了

再進一步研究:我們在C#當中,如果使用了virtual作為修飾符在父類別中寫了一個方法,那麼在子類中通過override可以重寫這個方法,最終的結果就是呼叫的非父類別的該方法,而是子類的,Go語言同樣可以。

例如

// 通過admin 型別值的指標
// 呼叫的方法
func (a *admin) notify() {
   fmt.Printf("Sending admin email to %s<%s>n",
       a.name,
       a.email)
}

在剛剛的程式碼中,追加一個*admin作為接受者的方法。

執行結果如下:

Sending user email to john smith<john@yahoo.com>
Sending admin email to john smith<john@yahoo.com>

可以發現此時這兩此執行的結果就不一樣了,第二次sendNotification(&ad)呼叫的notify方法就是admin這個型別的了。

這表明,如果外部型別實現了notify 方法,內部型別的實現就不會被提升。不過內部型別的值一直存在,因此還可以通過直接存取內部型別的值,來呼叫沒有被提升的內部型別實現的方法。

三、總結

綜上:嵌入型別為Go語言型別提供了一種很好的擴充套件能力,通過內部型別的提升,使得外部型別擁有了內部型別的方法,也可以通過外部型別實現同樣的方法來替代內部型別的。總體來說很像C#語言中的繼承。

到此這篇關於Go語言之嵌入型別的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com