interface 在 Go 中兩種不同的意義,一種是作為抽象化使用,另一種作為型別使用。Go 沒有繼承這樣子功能,但是可以透過組合或者介面的方式,達到類似的需求。
介面
package main
import "fmt"
type Shape interface {
Area() float64
}
type Rectangle struct {
W float64
H float64
}
func (r Rectangle) Area() float64 {
return r.W * r.H
}
type Circle struct {
R float64
}
func (c Circle) Area() float64 {
return 3.14 * c.R * c.R
}
func main() {
rect := Rectangle{W: 5, H: 3}
circle := Circle{R: 2}
// 使用接口
shapes := []Shape{rect, circle}
for _, shape := range shapes {
fmt.Printf("Area: %.2f\n", shape.Area())
}
}
空介面
package main
import (
"fmt"
"reflect"
)
func main() {
foo(123) // 123 int
foo("str") // str string
}
// 可以接任意型別參數
func foo(a interface{}) {
fmt.Println(a, reflect.TypeOf(a))
}
型別斷言 (type assertion)
package main
import (
"fmt"
"reflect"
)
func main() {
foo(123) // 123 int
foo("str") // str string
}
// 可以接任意型別參數
func foo(a interface{}) {
fmt.Println(a, reflect.TypeOf(a))
// 如果想要轉換成指定型別時
// str2 := a.(string) // 如果不檢查是否可以轉換,會引發 panic
// 所以加上檢查
str, ok := a.(string)
if ok {
fmt.Println("is string: " + str)
}
// 可以根據不同的型態做不同的行為,達成泛型的功能
// 使用 switch
switch v := a.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
case bool:
fmt.Println("bool")
case nil:
fmt.Println("nil")
default:
fmt.Println("unknown", v)
}
}
Go 1.18 is released!,於 Go 1.18 釋出後開始支援泛型,因此可以使用此功能取代使用 nterface{} 當作任意參數的方式
Tutorial: Getting started with generics