1. 程式人生 > >golang中interface的一些語法缺陷的改進

golang中interface的一些語法缺陷的改進

GO語言有一個獨門祕技:interface,是大師們對OOP的經典詮釋,是對傳統OOP思維的一個巧妙顛覆。

既優雅地實現執行時多型,又不需要像C++那樣顯式申明,完美的解除了型別實現跟介面呼叫之間的耦合。

Go語言的主要設計者之一Russ Cos曾經說過,如果只能選擇一個Go語言的特性移植到其他語言中,他會選擇介面。可見介面在GO中的地位,及其對GO這門語言所帶來的活力。

Russ Cos: interface https://research.swtch.com/interfaces

Ian Lance Taylor: go interface https://www.airs.com/blog/archives/277

 

然而,由於GO的interface定義與具體實現型別之間不需要顯式申明,只需要實現類實現interface定義的所有method即可賦值。

然而這種寬鬆的約定,卻帶來一些邏輯上的麻煩。

這裡有個例子:https://github.com/vipally/glab/blob/master/lab12/walk_test.go

 

有兩個包filepath和pet都定義了一個Walker介面,並實現了相應的實現型別。

但是巧的是這兩個Walker介面的定義都是一樣的

type Walker interface {
    Walk()
}

 

但是顯然,pet.Walker是想實現所有pet的“走路”行為

而filepath.Walker是想實現目錄的“遍歷”功能

然而,雖然兩個介面的定義是一樣的,但是期望的行為應該是不一樣的。

從邏輯上說,用filepath.Walker呼叫pet.Dog.Walk()應該是一個錯誤的行為,然而從GO的語法上看,這種操作居然是合法的:

	
var petWalker pet.Walker
var filepathWalker filepath.Walker
println("call by pet.Walker:")
petWalker = &pet.Dog{}
petWalker.Walk()
petWalker = &pet.Cat{}
petWalker.Walk()
petWalker = &filepath.FilePath{}
petWalker.Walk()

println("\ncall by filepath.Walker:")
filepathWalker = &pet.Dog{}
filepathWalker.Walk()
filepathWalker = &pet.Cat{}
filepathWalker.Walk()
filepathWalker = &filepath.FilePath{}
filepathWalker.Walk()

println("\nThe strange is that pet.Warker and filepath.Walker has the same signiture but they are not the same one.")
println("But Go treat them as the same one.")


 

從語法上修復這個bug的方法如下:

implements pet.Walker{
    *pet.Dog
    *pet.Cat
}

implements *filepath.FilePath{
    filepath.Walker
    filepath.Reader
}

通過顯式的申明 實現並可以使用介面的具體型別,告訴編譯器什麼樣的介面賦值,是被允許的。

這種外部申明的語法,仍然沒有破壞GO interface非侵入式的設計,無須對interface和實現型別做任何修改。

這樣,下面的介面賦值將被編譯器判斷為非法

filepathWalker  = &pet.Dog{}

 

另外,這種顯式申明還有一個好處,就是可以明確通過查詢引用的方法,找出實現了某個介面的所有實現型別。

起到一個建立介面定義與實現型別關係的書面說明,

不會像現在一樣,通過interface名字,只能找到interface的物件,卻沒法找出所有實現並賦值給該介面的所有具體型別的資訊。

 

參考連結:

Russ Coss: interface https://research.swtch.com/interfaces

Ian Lance Taylor: go interface https://www.airs.com/blog/archives/277

confused interface: https://github.com/vipally/glab/blob/master/lab12/walk_test.go