go定義接口以及類怎么使用接口
多態是指代碼可以根據類型的具體實現采取不同行為的能力。如果一個類型實現了某個接口,所有使用這個接口的地方,都可以支持這種類型的值。
- 接口是用來定義行為的類型。這些被定義的行為不由接口直接實現,而是通過方法由用戶定義的類型實現。如果用戶定義的類型實現了某個接口類型聲明的一組方法,那么這個用戶定義的類型的值就可以賦給這個接口類型的值。這個賦值會把用戶定義的類型的值存入接口類型的值。對接口值方法的調用會執行接口值里存儲的用戶定義的類型的值對應的方法。因為任何用戶定義的類型都可以實現任何接口,所以對接口值方法的調用自然就是一種多態。
下面將創建一個用戶定義結構體並實現一個發送接口:
package main import "fmt" // 定義一個notifier接口 // 通知類行為的一個接口 type notifier interface { notify() } // 定義一個用戶類 type user struct { name string email string } // nofity是使用指針接收者實現的方法 func (u *user) notify() { fmt.Print("發送一條郵件給%s<%s>", u.name, u.email) } func main() { // 創建一個用戶並復制 user := user{"小明", "1001**@qq.com"} sendNotification(&user) } func sendNotification(n notifier) { n.notify() }
注意:這里傳遞給sendNotification方法的用戶定義結構體值user,是使用引用的方式傳遞的。因為類在實現接口的時候傳遞的參數是引用類型:(u *user),如果你是使用值傳遞的話,編輯器會報錯。
./demo.go:25:18: cannot use user (type user) as type notifier in argument to sendNotification: user does not implement notifier (notify method has pointer receiver)
進一步探索新問題,為什么上述使用值不行,使用引用可以呢?
如果你把是實現接口的傳遞參數改成值的形式而不是引用,你將會發現有所不同
// nofity是使用指針接收者實現的方法 func (u user) notify() { fmt.Print("發送一條郵件給%s<%s>", u.name, u.email) }
// 創建一個用戶並復制
user := user{"小明", "1001**@qq.com"}
sendNotification(user)
sendNotification(&user)
你將會發現,使用引用的方式調用跟使用值的方式調用,編譯器都不會報錯,這是為什么?
- 因為底層實現是如果使用指針來實現一個接口(u *user),那么只有指向那個類型(user)的指針才能實現對應的接口。
- 如果使用值來實現一個接口,那么那個類型(user)的值和指針都能夠實現對應的接口。
注意:使用指針實現接口和使用值實現接口有個區別在於,指針是指向內存同一塊地址的,所以通過指針傳遞的參數,在函數體內執行結構體的改變會影響函數外的用戶類型值,而使用值傳遞則不會 ,這也是在使用指針和使用值的不同場景選擇的一個區別其中之一。
使用值:
package main import "fmt" // 定義一個notifier接口 // 通知類行為的一個接口 type notifier interface { notify() } // 定義一個用戶類 type user struct { name string email string } // nofity是使用指針接收者實現的方法 func (u user) notify() { u.name = "小紅" fmt.Print("發送一條郵件給%s<%s>", u.name, u.email) } func main() { // 創建一個用戶並復制 user := user{"小明", "1001**@qq.com"} //sendNotification(user) sendNotification(&user) // 小明 fmt.Println(user.name) sendNotification(user) // 小明 fmt.Println(user.name) } func sendNotification(n notifier) { n.notify() }
使用指針:
package main import "fmt" // 定義一個notifier接口 // 通知類行為的一個接口 type notifier interface { notify() } // 定義一個用戶類 type user struct { name string email string } // nofity是使用指針接收者實現的方法 func (u *user) notify() { u.name = "小紅" fmt.Print("發送一條郵件給%s<%s>", u.name, u.email) } func main() { // 創建一個用戶並復制 user := user{"小明", "1001**@qq.com"} //sendNotification(user) sendNotification(&user) // 小紅 fmt.Println(user.name) } func sendNotification(n notifier) { n.notify() }