iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 28
1
自我挑戰組

Let's Eat GO ! 實務開發雜談by Golang系列 第 28

Day28 .[心得與討論篇] embedded 嵌入

簡介

embedded,嵌入。

俗稱golang 的繼承,但不是真的繼承(背後的機制和程式語言處理方式不同)。

而行為可以做到類似繼承的特點。

子類別A繼承了父類別B,子類別A可以寫跟父類別同樣名字的method name,同樣的input 和output,method內部的細節卻不同,達到覆寫父類別method的目的。

golang也可以做出這樣的特點。

初始化成員

type Cellphone struct {
	ID   int
	name string
}

type Iphone struct {
	Cellphone
}

type HTC struct {
	Cellphone
}

func main() {

	newIphone := Iphone{}
	fmt.Println(newIphone)

	// 不可這樣使用
	newIphone2 := Iphone{
		ID: 1,
	}
	fmt.Println(newIphone2)
}

會有錯誤訊息如下

cannot use promoted field Cellphone.ID in struct literal of type Iphone

意思是說Iphone是嵌入Cellphone的型態。

嵌入的對象,裡面的變數有個專有名詞,叫做『promoted field』,初始化struct不可以這樣用。

稍微改造一下

	newIphone2 := Iphone{
		Cellphone{
			ID:   1,
			name: "iphone",
		},
	}
	fmt.Printf("%#v", newIphone2)

印出內容

main.Iphone{Cellphone:main.Cellphone{ID:1, name:"iphone"}}

外面的method優先使用

我們新增一個屬於Cellphone的method

func (c *Cellphone) SetID(n int) {
	c.ID = n + 100
}

func main() {
	newIphone2 := Iphone{
		Cellphone{
			ID:   1,
			name: "iphone",
		},
	}

	newIphone2.SetID(99)
	fmt.Printf("%#v", newIphone2)
}

結果會是

main.Iphone{Cellphone:main.Cellphone{ID:199, name:"iphone"}}

因為iphone沒有SetID的method,所以使用Cellphone的SetID

那麼,我再也加一個屬於iphone的SetID()

func (i *Iphone) SetID(n int) {
	i.ID = n + 500
}

再次執行結果會是

main.Iphone{Cellphone:main.Cellphone{ID:599, name:"iphone"}}

結論是如果自己沒有指定的method,就使用嵌入型態的method。

若有自己的method,就使用自己的,而不使用嵌入型態的method,這個行為很像我們物件導向使用的繼承吧。

喜歡還是可以用裡面的

改造Iphone的SetID()

func (c *Cellphone) SetID(n int) {
	c.ID = n + 100
}

func (i *Iphone) SetID(n int) {
	i.ID = n + 500
	i.Cellphone.SetID(-1000)
}

結果會是如下

main.Iphone{Cellphone:main.Cellphone{ID:-900, name:"iphone"}}

Embedded 的常見使用

Embedded 使用方式在golang也是常見的設計方式之一,io package那包source code就非常的經典。

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}


// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}

不只是struct,interface也是可以用embedded。

(前幾篇的系列文大概也讓你意識到了,會出現在這裡的interface,都可以看作背後站個struct,只是我們只知道有什麼method,不知道有struct實際有什麼其他的變數,或者interface沒列出的method)。

大抽象可以是小抽象組合而成的,一來是程式碼方便重複使用,只需要客製不同的部分,二來是方便管理,拆成小元件比起許多很類似的新個體,維護性更佳。

看懂embedded,對於golang程式閱讀和設計又可以更近一步了。


上一篇
Day27 .[心得與討論篇] struct 設計解析 - 以melody package (7)
下一篇
Day29 .[心得與討論篇] 位移處理與itoa
系列文
Let's Eat GO ! 實務開發雜談by Golang30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言