今天終於要來談談介面,也就是 Interface 啦!之前當我們在談繼承以及抽象類別的時候,說到在 Golang 跟 Rust 並沒有這樣的概念,在這兩個語言則是透過實作 Interface 來實現多型 (在 Rust 實際上叫做 Trait,我們晚點會提到)。而在 Scala 雖然有繼承系統,不過也有類似 Java Interface 的東西,叫做 Trait,但和 Java 有點不同,我們在講 Scala 的時候也會提到。最後就是 Python 的部分並沒有 Interface,我們也會簡單說明下原因囉!
ABCMeta
,來讓自定義的 Class 有個可以繼承的 Abstract Class (裡面沒有方法有被實作)來做到行為規範。Running
裡頭有一個方法 run()
。而 class Lion
繼承了 Xxx
,也實作了 trait Running
(用 with
)。注意的是,假使今天沒有繼承 Xxx
,只有實作 Running
的話,要用 class Lion extends Running
,但是這裡並不是繼承的關係,只是寫法上必須是這樣。假如沒有實作完全,就必須宣告成 abstract class
囉!trait Running {
def run(): Unit
}
class Lion extends Xxx with Running {
def run() = println("Run with 4 legs")
}
override
。trait Running {
def run(): Unit = println("Run")
}
class Lion extends Xxx with Running {
override def run() = println("Run with 4 legs")
}
sayHello()
依賴 name
的值,所以當我們的 Class with SayHi
的時候就要定義 name
的值,不然也是會被認定是 Abstract class 囉。除此之外,Trait 也可以 Extend 某個 Class (例如 Class A
),來依賴該 Class 的某個 Method,所以間接限制了可以引入此 Trait 的 Class,例如繼承了 Class A
的 Class 就可以引入,但不相干的 Class 就不行了!trait SayHi {
val name: String
def sayHello() = println("Hey, I'm " + name)
}
super
時要注意,因為 Trait 不是繼承那種層級關係,所以 super
在這其實是指最左邊,也就是最早引入的 Trait。也因為 Trait 的特性,可以拿來實現所謂的 Decorator Pattern,有興趣的可以參考這裡囉!type <Interface name> interface
。然而 Interface 也可以不帶任何方法,又叫做 Empty Interface。如果我們今天有一個類型實作了一個 Interface 所有的方法,我們就說這個類型實作了這個 Interface,例如下面的 MyStruct
實作了 MyInterface
的 A() int
(func(s MyStruct) A() int
),所以當 func f(i I)
需要 MyInterface
這個類型作為參數時,就能傳入 MyStruct
的 instance。type MyInterface interface {
A() int
}
type MyStruct struct {
X int
}
func(s MyStruct) A() int {
return s.X
}
func f(i MyInterface) {
i.A()
}
var i MyInterface = MyStruct{X: 1}
var i MyInterface = MyStruct{X: 1}
。如果要知道某個 Interface 的值,實際上是不是某個 Struct 的話,就可以用例如 value, ok := i.(MyStruct)
,這裡是看 i
這個 Interface 的變數是不是 MyStruct
,如果是的話,value
就是該類型的值,而 ok
是 true
,反之則是 false
,這就是所謂的 Type assertion。當我們想要同時判斷很多類型時,還可以使用所謂 Type switch,可以參考這裡。f
的參數表示可以丟入任何類型的值,Go 會自動幫我們進行轉換。然而 fAll
的參數是空 Interface 的 Slice,那是不是表示我們可以丟入任意類型的 Slice 呢?出乎意料,答案是不行的,可以參考官方解釋囉!func f(p interface{}){
...
}
func fAll(p []interface{}) {
...
}