Go 語言中關於介面的三個
我的線上部落格:http://golang.iswbm.com
我的 Github:github.com/iswbm/GolangCodingTime
1. 對方法的呼叫限制
介面是一組固定的方法集,由於靜態型別的限制,介面變數有時僅能呼叫其中特定的一些方法。
請看下面這段程式碼
package main import "fmt" type Phone interface { call() } type iPhone struct { name string } func (phone iPhone)call() { fmt.Println("Hello,iPhone.") } func (phone iPhone)send_wechat() { fmt.Println("Hello,Wechat.") } func main() { var phone Phone phone = iPhone{name:"ming's iphone"} phone.call() phone.send_wechat() }
我定義了一個 Phone 的介面,只要求實現 call 方法即可,也就是隻要能打電話的裝置就是一個電話(好像是一句沒用的廢話)。
然後再定義了一個 iPhone 的結構體,該結構體接收兩個方法,一個是打電話( call 函式),一個是發微信(send_wechat 函式)。
最後一步是關鍵,我們定義了一個 Phone 介面型別的 phone 物件,該物件的內容是 iPhone 結構體。然後我們呼叫該物件的 call 方法,一切正常。
但是當你呼叫 phone.send_wechat
方法,程式會報錯,提示我們 Phone 型別的方法沒有 send_wechat 的欄位或方法。
# command-line-arguments ./demo.go:30:10: phone.send_wechat undefined (type Phone has no field or method send_wechat)
原因也很明顯,因為我們的phone物件顯示宣告為 Phone 介面型別,因此 phone呼叫的方法會受到此介面的限制。
那麼如何讓 phone 可以呼叫 send_wechat 方法呢?
答案是可以不顯示的宣告為 Phone介面型別 ,但要清楚 phone 物件實際上是隱式的實現了 Phone 介面,如此一來,方法的呼叫就不會受到介面型別的約束。
修改 main 方法成如下
func main() { phone := iPhone{name:"ming's iphone"} phone.call() phone.send_wechat() }
執行後,一切正常,沒有報錯。
Hello,iPhone.
Hello,Wechat.
2. 呼叫函式時的隱式轉換
Go 語言中的函式呼叫都是值傳遞的,變數會在方法呼叫前進行型別轉換。
比如下面這段程式碼
import ( "fmt" ) func printType(i interface{}) { switch i.(type) { case int: fmt.Println("引數的型別是 int") case string: fmt.Println("引數的型別是 string") } } func main() { a := 10 printType(a) }
如果你執行後,會發現一切都很正常
引數的型別是 int
但是如果你把函式內的內容搬到到外面來
package main import "fmt" func main() { a := 10 switch a.(type) { case int: fmt.Println("引數的型別是 int") case string: fmt.Println("引數的型別是 string") } }
就會有意想不到的結果,居然報錯了。
# command-line-arguments ./demo.go:9:5: cannot type switch on non-interface value a (type int)
這個操作會讓一個新人摸不著頭腦,程式碼邏輯都是一樣的,為什麼一個不會報錯,一個會報錯呢?
原因其實很簡單。
當一個函式介面 interface{} 空介面型別時,我們說它可以接收什麼任意型別的引數(江湖上稱之為無招勝有招)。
當你使用這種寫法時,Go 會默默地為我們做一件事,就是把傳入函式的引數值(注意:Go 語言中的函式呼叫都是值傳遞的)的型別隱式的轉換成 interface{} 型別。
如何進行介面型別的顯示轉換
上面瞭解了函式中 介面型別的隱式轉換後,你的心裡可能開始有了疑問了,難道我使用型別斷言,只能通過一個接收空介面型別的函式才能實現嗎?
答案當然是 No.
如果你想手動對其進行型別轉換,可以像下面這樣子,就可以將變數 a 的靜態型別轉換為 interface{} 型別然後賦值給 b (此時 a 的靜態型別還是 int,而 b 的靜態型別為 interface{})
var a int = 25 b := interface{}(a)
知道了方法後,將程式碼修改成如下:
package main import "fmt" func main() { a := 10 switch interface{}(a).(type) { case int: fmt.Println("引數的型別是 int") case string: fmt.Println("引數的型別是 string") } }
執行後,一切正常。
引數的型別是 int
3. 型別斷言中的隱式轉換
上面我們知道了,只有靜態型別為介面型別的物件才可以進行型別斷言。
而當型別斷言完成後,會返回一個靜態型別為你斷言的型別的物件,也就是說,當我們使用了型別斷言,Go 實際上又會預設為我們進行了一次隱式的型別轉換。
驗證方法也很簡單,使用完一次型別斷言後,對返回的物件再一次使用型別斷言,Goland 立馬就會提示我們新物件 b 不是一個介面型別的物件,不允許進行型別斷言。
總結
到此這篇關於Go 語言中關於介面的三個"潛規則"的文章就介紹到這了,更多相關go語言介面內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!