iT邦幫忙

2021 iThome 鐵人賽

DAY 15
2
Modern Web

golang後端入門分享系列 第 15

Day15-Go介面interface

前言

Go 語言的介面(interface)是一組以方法簽名(method signatures)的組合,透過介面來定義物件的一組行為,它將物件導向的內容組織,實現得非常方便。

介紹Interface

Interface 定義了一組 method,Interface 裡的值可以保存實現這些方法的任何值 。這裡以 Go Tutorial 上的例子來解說,這邊有稍微做了些調整,我們直接看以下的程式碼:

package main
 
import (
   "fmt"
   "math"
)
 
type Abser interface {
   Abs() float64
}
 
func main() {
   var a Abser
   f := MyFloat(-math.Sqrt2)
   v := Vertex{3, 4}
 
   a = f  // a MyFloat implements Abser
   fmt.Println(a.Abs())
 
   a = &v // a *Vertex implements Abser
   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)
}

我們來解釋一下上述程式碼, Abser interface 實現了 Abs method,而 Abs method 同時定義在 Vertex struct 和 MyFloat 上。

Interface 值

Interface 裡到底能存什麼值呢?如果我們定義了一個 interface 的變數,那麼這個變數可以實現該 interface 裡所有的變數型態。例如上述的例子, Abser interface 最終實現了 Vertex struct 和 MyFloat 兩種變數型態,而最後儲存 float64 這個變數型態。

我們再來看一個例子:

package main
 
import (
   "fmt"
   "math"
)
 
type I interface {
   M()
}
 
type T struct {
   S string
}
 
func (t *T) M() {
   fmt.Println(t.S)
}
 
type F float64
 
func (f F) M() {
   fmt.Println(f)
}
 
func main() {
   var i I
 
   i = &T{"Hello"}
   describe(i)
   i.M()
 
   i = F(math.Pi)
   describe(i)
   i.M()
}
 
func describe(i I) {
   fmt.Printf("(%v, %T)\n", i, i)
}

Interface I 實現了 M method,而 M method 定義在 T struct 和 F float64上,最後 M method 因出了兩個型態變數中帶的參數

空 Interface

空 interface 不包含任何的 method,所以所有的型別都實現了空 interface。空 interface 對於描述起不到任何的作用(因為它不包含任何的 method),但是在我們需要儲存任意型別的數值時,空 interface 及發揮到他的作用,因為它可以儲存任意變數型態,我們來看一下下面的例子:

package main
 
import (
   "fmt"
)
 
var a interface{}
 
func main() {
   // 定義 a 為空介面
 
   var i int = 5
   s := "Hello world"
   // a 可以儲存任意型別的數值
   a = i
   fmt.Println(a) // 5
 
   a = s
   fmt.Println(a) // Hello world
}

nil Interface 值

一個 nil interface 值既不包含值也不包含具體類型。
在 nil interface 上調用方法是一個運行時錯誤,因為 interface 裡沒有任何類型定義在任何方法上。

package main
 
import "fmt"
 
type I interface {
   M()
}
 
func main() {
   var i I
   describe(i)
   i.M()
}
 
func describe(i I) {
   fmt.Printf("(%v, %T)\n", i, i)
}

結語

今天帶來 Go 語言中非常巧妙的設計 interface,它讓物件導向,內容組織實現非常的方便,本人自覺 Go 語言的 interface 簡單且非常實用,希望今天帶來的文章對你有初步認識 interface 的幫助,謝謝你今天的閱讀。

參考來源

https://tour.golang.org/methods/9
https://tour.golang.org/methods/10
https://tour.golang.org/methods/11
https://tour.golang.org/methods/12
https://tour.golang.org/methods/13
https://tour.golang.org/methods/14


上一篇
Day14-Go函式function
下一篇
Day16-打包自己的 Go package
系列文
golang後端入門分享30

1 則留言

0
obarisk
iT邦新手 3 級 ‧ 2021-09-24 09:17:12

是不是 接收器 只能用在 main package 裡?

我要留言

立即登入留言