golang 的 interface,我覺得對初學者來說會有點疑惑,畢竟 interface 在這裡有兩個意思,一個代表『泛用型別』、一個代表類似傳統 OOP(Object-oriented programming) 所說的 interface,下面就來介紹兩種使用方式。

泛用型別

interface{} 如果在後面加上兩個大括號,可以把它當作一種 type 使用 範例如下:

package main

import (
	"fmt"
)

func main() {
	var a interface{}
	var b interface{}
	var c interface{}

	a = 5
	b = 1.5
	c = "hello world"
	fmt.Println(a, b, c)
}

https://play.golang.org/p/MVG8kd3qjI-

這個型別看起來很好用,但是在強型別語言中,如果濫用這個機制,會吃到不少苦頭。個人目前的使用情境都是用在面對一個型別不是太穩定的 api 需求,會使用這種型別設計

如果像上述的範例,我要怎麼知道它的原始型別呢? 如下範例

package main

import (
	"fmt"
)

func Switch(input interface{}) {

	switch v := input.(type) {
	case float64:
		fmt.Printf("Twice %v is %v\n", v, v*2)
	case int:
		fmt.Printf("Twice %v is %v\n", v, v*2)
	case string:
		fmt.Printf("%q is %v bytes long\n", v, len(v))
	default:
		fmt.Printf("I don't know about type %T!\n", v)
	}

}

func main() {
	var a interface{}
	var b interface{}
	var c interface{}

	a = 5
	b = 1.5
	c = "hello world"
	Switch(a)
	Switch(b)
	Switch(c)
	fmt.Println(a, b, c)
}

https://play.golang.org/p/bHDoHEdWZVS

interface

golang 的 interface 跟其他 OOP(Object-oriented programming) 不太一樣,它不需要『顯示聲明』,這是一個很有趣也很強大的功能,我們先用一個範例來說明一下

package main

import (
	"fmt"
)

type Member interface {
	GetName() string
	GetAge() int
}

type Robot struct {
	name  string
	age   int
	power int
}

func (r *Robot) Work() {
}

func (r *Robot) GetName() string {
	return r.name
}
func (r *Robot) GetAge() int {
	return r.age
}

type Car struct {
	name     string
	age      int
	odometer int
}

func (r *Car) Run() {
}

func (r *Car) GetName() string {
	return r.name
}
func (r *Car) GetAge() int {
	return r.age
}

func Cleaning(m Member) {
	fmt.Printf("Consumer Name:%s, Age:%d\n", m.GetName(), m.GetAge())
}

func main() {
	r := &Robot{
		name:  "GUMDAM",
		age:   1,
		power: 100,
	}
	c := &Car{
		name:     "BENZ",
		age:      2,
		odometer: 100,
	}
	Cleaning(c)
	Cleaning(r)
}

https://play.golang.org/p/uOqkD36c4Bt

由上面可以看到,我建構了 Robot struct 還有 Car struct,這兩個完全不同類型的 struct,竟然可以丟進去 Cleaning func,就是因為他們兩個都有實作, Member interface,在 golang 裡面 interface 的定義是隱性的,不用刻意像其他語言一樣要使用 implement 之類的 keyword,來顯示宣告,它只要有實作該 interface 所規範的 func ,即可定義它有實作。

也可以參考看看官方套件裡面大家用最多的叫做 error 它就是一種 interface 喔!

這種型別的好處,我在一開始學時也還無法體會它的好用之處,也很難在短短幾句之間跟大家介紹清楚。多實作多看其他人的應用,即可以體會這個功能的強之處

一個小心得分享,這種在接外部 package 時非常好用,我可以無痛用我的 struct ,丟到別人定義的 api 裡面。