golang
中的介面可以輕鬆實現c++
中的多型,而且沒有繼承自同一父類的限制,感覺方便很多。但是在使用的時候,如果沒有理解,也可能會遇到"坑"。比如《go語言實戰》中的乙個例子:
package main
import "fmt"
type user struct
type notifier inte***ce
func (u *user) notify()
func sendnotification(n notifier)
func main()
sendnotification(u)
}// compile error
// cannot use u (type user) as type notifier in argument to sendnotification:
// user does not implement notifier (notify method has pointer receiver)
報的錯是u
沒有實現notifier
這個介面,實現了這個介面的是*user
型別,而不是user
型別,u
是user
型別,所以不能賦值給notifier
這個介面。
既然如此,修改為sendnotification(&u)
就ok了。然而問題是,如何理解到底是t
型別還是*t
型別實現了某個介面呢?
參考雨痕的《go語言學習筆記》第七章,go
語言中的介面定義如下:
type iface struct
type itab struct
雖然具體的細節操作不太懂,但是可以知道,對乙個介面賦值的時候,會拷貝型別資訊和該型別的方法集。這就類似於c++
多型中的虛指標(vptr
)和虛函式表(vtable
)了。我理解的是,只要這個型別的方法集中包括這個介面的所有方法,那麼它就是實現了這個介面,才能夠賦值給這個介面,那麼問題來了,乙個型別的方法集是什麼呢?
雖然看起來比較複雜,但總結完就一話,*t
型別就是厲害,方法集包括t
和*t
的方法。
所以文章開頭的例子中,u
是user
型別,方法集是空的,不算是實現了notifier
介面。
當在糾結應該將t
型別還是*t
型別賦值給某個介面的時候,第一步就是看方法集,看一看該型別到底有沒有實現這個介面。(所以t
和*t
不是乙個型別。。。)
go
語言的內建庫中有定義了很多介面,如error
介面,
type error inte***ce
內建的errors
包實現了這個介面:
// package errors implements functions to manipulate errors.
package errors
// new returns an error that formats as the given text.
func new(text string) error
}// errorstring is a trivial implementation of error.
type errorstring struct
func (e *errorstring) error() string
可以看到new
方法返回值是error
介面,而只有*errorstring
型別實現了這個介面,所以new
方法返回的是&errorstring
而不是errorstring
。 golang 方法與介面
在程式語言中,方法與函式的概念來搞清楚。函式指的是乙個封裝的 塊,我們可以直接呼叫它,並且返回結果。而方法其實也是一種函式,只不過方法需要和某個物件繫結。golang並沒有類的概念,不過仍然有方法和介面這些概念。方法接收者是乙個特殊引數,給函式指定了這個引數之後,函式就成為方法了。這個特性有點像ko...
使用方法集與介面
作用於變數上的方法實際上是不區分變數到底是指標還是值的。當碰到介面型別值時,這會變得有點複雜,原因是介面變數中儲存的具體值是不可定址的,幸運的是,如果使用不當編譯器會給出錯誤。考慮下面的程式 package main import fmt type list int func l list len ...
golang結構體與方法
type people inte ce type student struct func stu student speak think string talk string else return func main think speak fmt.println peo.speak think ...