繼續上次的 Method, Go 內的 interface  也是很重要的一個環節, 尤其跟 method 間的關係更是緊密
基本宣告
Interce 是用來定義 method signatures, 換句話說, 如果是這個型別(interface) 的值, 就會有所規範的 method 可以使用
1 2 3
   | type Abser interface { 	Abs() float64 }
  | 
 
這樣的描述跟原本常見的 interface 會有些差異, 主要原因還是因為 Go 沒有 class 造成的
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 32
   | func main() { 	var a Abser 	f := MyFloat(-math.Sqrt2) 	v := Vertex{3, 4}
  	a = f   	a = &v 
  	 	 	a = v 
  	fmt.Println(a.Abs()) }
 
  type MyFloat float64
  func (f MyFloat) Abs() float64 { 	if f < 0 { 		return float64(-f) 	} 	return float64(f) }
  type Vertex struct { 	X, Y float64 }
  func (v *Vertex) Abs() float64 { 	return math.Sqrt(v.X*v.X + v.Y*v.Y) }
  | 
 
- 在上述程式碼提到 line 11 行會壞掉, 主要原因是 Abs() 方法只有在 struct Vertex 上面實做 (Pointer type), 而沒有再 value type 上面實做。這也是為什麼會發生錯誤的原因
 
nil
interface 當被指定時, 預設值是 nil , 而所宣告的 method  還是可以被呼叫, 只是是透過 nil receiver 罷了
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
   |  type I interface { 	M() }
  type T struct { 	S string }
  func (t *T) M() { 	if t == nil { 		fmt.Println("<nil>") 		return 	} 	fmt.Println(t.S) }
  func main() { 	var i I
  	var t *T 	i = t  	describe(i)  	i.M()  }
 
  | 
 
但如果只有單純的宣告卻沒有指定值時 (如 line 22), 就會出現以下的錯誤訊息
1 2 3 4 5 6 7 8 9 10
   | type I interface { 	M() }
  func main() { 	var i I     describe(i)      i.M()  }
 
  | 
 
Type switches
在介紹 Type switches 之前, 要先了解兩個東西, 1. empty interface, 2. type assertions
Empty interface
empty interface 就字面上意思, 是沒有宣告任何 method 的 interface, 在 go 裡面會這樣子表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | 
  func main() { 	var i interface{}     describe(i) 
  	i = 42     describe(i) 
  	i = "hello"     describe(i)  }
  func describe(i interface{}) { 	fmt.Printf("(%v, %T)\n", i, i) }
 
  | 
 
透過上面的範例, 得知我們可以透過 empty interface 來取得變數的值及型別兩種資訊
Type assertions
既然知道型別, 那是否可以直接做條件判斷了, 在 go 裡面是可以做到的
1 2 3 4 5 6 7 8 9 10 11 12 13
   | var i interface{} = "hello"
  s := i.(string) fmt.Println(s)
  s, ok := i.(string)  fmt.Println(s, ok) 
  f, ok := i.(float64)  fmt.Println(f, ok)
  f = i.(float64)  fmt.Println(f)
  | 
 
- 如果 i 的值是 
string 型別的話, s 就會等於 i 的值 
- 但如果不是, 就會噴錯。但這樣子就太蠢了, 所以 go 提供了第二個值可以接, 當這一個有接起來, 效果就等於 try catch. 執行時就不會噴錯了
 
switches
透過前面兩地的特性, 再搭配 switch 就可以做到型別的判斷了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   |  type Vertex struct { 	name string }
  func do(i interface{}) { 	switch v := i.(type) { 	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)) 	case Vertex: 		fmt.Printf("Vertex %v", v) 	default: 		fmt.Printf("I don't know about type %T!\n", v) 	} }
  func main() { 	do(21) 	do("hello") 	do(true) 	do(Vertex{"Go"}) }
 
  | 
 
參考資料