文章轉載地址:https://www.flysnow.org/2017/04/06/go-in-action-go-embedded-type.htmlhtml
嵌入類型或嵌套類型,這是一種能夠把已有類型的聲明嵌入到新的類型裏的一種方式,這種功能對代碼複用很是函數
重要htm
在其餘語言中,有繼承的概念,可是在 Go 語言中沒有繼承的概念,Go 提倡的代碼複用的方式是組合,因此,這blog
也是嵌入類型的意義所在,組合不是繼承,因此,Go 纔會更加靈活繼承
type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int,err error) } type Closer interface { Close() error } type ReadWriter interface { Reader Writer } type ReadCloser interface { Reader Closer } type WriteCloser interface { Writer Closer }
上面是標準 io 包裏,咱們經常使用的接口,能夠看到 ReadWriter 接口是嵌入 Reader、Writer 接口組合而成的新接口,這樣接口
咱們就不用在重複的定義被嵌入接口的方法,直接經過嵌入就能夠了。嵌入類型一樣適用於結構體類型,看下面例子:string
type user struct { name string email string } type admin struct { user level string }
嵌入後,被嵌入的類型稱之爲內部類型,新定義的類型稱之爲外部類型,這裏 user 就是內部類型,而 admin 是外部類型it
經過嵌入類型,與內部類型相關的字段、方法、標識符等都會被外部類型所擁有,就像外部類型本身的同樣,這樣就達到了io
代碼快捷複用組合的目的class
同時,外部類型還能夠添加本身的方法,字段等,能夠很方便的擴展外部類型的功能
type user struct { name string email string } type admin struct { user level string } func main() { ad := admin{user{"張三","zhangsans@qq.com"},"管理員"} fmt.Println("能夠直接調用,名字是:",ad.name) fmt.Println("也能夠經過內部類型調用:",ad.user.name) fmt.Println("但新增的屬性只能直接調用:",ad.level) }
上面是嵌入類型的使用,在初始化的時候,咱們採用的是字面值的方式,先初始化 user 這個內部類型,再初始化
新增的 level 屬性
對於內部類型的屬性和方法訪問上,咱們能夠採用外部類型直接訪問,也能夠經過內部類型進行訪問,可是咱們爲
外部類型新增方法屬性字段,只能使用外部類型訪問,由於內部類型沒有這些
固然,外部類型也能夠聲明同名的字段或方法,來覆蓋內部類型,這種狀況方法比較多,以方法爲例:
type user struct { name string email string } type admin struct { user level string } func (u user) sayHello() { fmt.Println("Hello,I am a user") } func (a admin) sayHello() { fmt.Println("Hello,I am a admin") } func main() { ad := admin{user{"張三","zhangsans@qq.com"},"管理員"} ad.user.sayHello() ad.sayHello() }
內部類型 user 有一個 sayHello 方法,外部類型對其進行了覆蓋,同名重寫 sayHello,而後在 main 方法分別訪問這兩個
類型的方法,打印輸出:
Hello,I am a user Hello,I am a admin
從上面的輸出能夠看出,方法 sayHello 被覆蓋了
嵌入類型還有一個強大的地方就是:若是內部類型實現了某個接口,那麼外部類型也被認爲實現了這個接口,以下示例:
type Hello interface { hello() } type user struct { name string email string } type admin struct { user level string } func (u user) hello() { fmt.Println("Hello, I am a user") } func sayHello(h Hello) { h.hello() } func main() { ad := admin{user{"張三","zhangsans@qq.com"},"管理員"} sayHello(ad.user) // 使用 user 做爲參數 sayHello(ad) // 使用 admin 做爲參數 }
新增一個 Hello 接口,而後讓 user 類型實現這個接口,最後定義了一個 sayHello 方法,它接受一個 Hello 類型的
參數,最後咱們在 main 函數調用的時候,發現無論是 user 類型吧,仍是 admin 類型做爲參數傳遞給 sayHello 都能正
常調用,這裏就能說名 admin 接口實現了接口 Hello,可是又沒有顯示聲明 admin 實現,因此這個實現是經過內部類型
user 實現的,由於 admin 包含了 user 全部方法和字段,因此也就實現了這個接口