Interface

Go 的 interface (介面) 是一堆方法簽章集合而成的 type (型態), 只要一個 type 實作出 interface 定義的所有方法,就是實作 interface

interface 是 Go 用來定義物件行為的方式,其概念是:

如果某個物件可以做「這件事」,那麼它就可以用來當成是「這種東西」。

(if something can do this, then it can be used here.)

看看以下範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
type Shape interface {
	Area() float64
}

type Rectangle struct {
	Width, Height float64
}

func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

type Circle struct {
	Radius float64
}

func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

func printArea(shape Shape) {
	fmt.Println("area:", shape.Area())
}

func main() {
	r := Rectangle{Width: 7, Height: 8}
	c := Circle{Radius: 5}

	printArea(r) // output: area: 56
	printArea(c) // output: area: 78.53981633974483
}

我們定義了 Shape interface,只要實作 Shape 定義的方法 Area() 就是實作 Shape

而 Rectangle 跟 Circle 兩個 struct 都有實作出 Area(),所以都符合 Shape interface

所以都可以使用 printArea() 印出結果

Implicit Interface

跟其他程式語言不太一樣的地方是 Go 的 interface 是 implicit interface, 不需要使用 implements 關鍵字實作,只要設計好對應的方法就可以達成實作

這個特性增加了 interface 使用上的彈性

  • 程式不會在實作 interface 時跟任何的 package 相依
  • 一個 type 可以實作多個 interface

看看以下範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type Rectangle struct {
	Width, Height float64
}

func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

func (r Rectangle) Info() string {
	return fmt.Sprintf("w: %f, h: %f, a: %f", r.Width, r.Height, r.Area())
}

type Information interface {
	Info() string
}

func printInfo(i Information) {
	fmt.Println(i.Info())
}

func main() {
	r := Rectangle{Width: 7, Height: 8}

	printArea(r) // output: area: 56
	printInfo(r) // output: w: 7.00, h: 8.00, a: 56.00
}

我們增加了 Information interface,並且在 Rectangle 藉由實作 Info() 方法來實作 Information interface

現在 Rectangle 同時實作了 Shape 跟 Information interface

Empty Interface

當 interface 不包含任何方法時,稱之為 empty interface (空介面)

空介面可以裝入任何型態的數值,因為每一種型態都會實作至少 0 個方法

如果要存取 empty interface 的數值時,可以使用 type assertion 或是 type switch

看看以下範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 宣告 a 為 empty interface
var a interface{}

// 放入任意數值
a = 5
a = "xyz"

// type assertion
s, ok = a.(string)
fmt.Println(s, ok) // output: xyz true

// type switch
switch v := a.(type) {
case string:
	fmt.Printf("type string: %s\n", v)
case int:
	fmt.Printf("type int: %d\n", v)
}
// output: type string: xyz

其實官網的教學 A Tour of Go 都有說明


Reference