interface可以把它當成是golang的一個不定型態的型態,好像有點繞舌~~
看範例比較好懂
package main
import "fmt"
func main() {
//傳入string
test("GG")
//傳入int
test(123)
//傳入bool
test(false)
//已宣告參數為string,塞入int當然無法編輯成功
notinterface(123)
}
func notinterface(qq string) {
fmt.Println("notinterface:", qq)
}
func test(qq interface{}) {
fmt.Println("test:", qq)
}
如果需要判斷interface{}參數的對應型態,可以使用斷言(Type Assertion)的方式取得,以下範例來看
,第一個test參入參數是string,直接斷言成string,直接寫成value.(型態),
但是第二跟第三的型態非string,所以就panic掉啦
package main
import "fmt"
func main() {
test("GG")
test(123)
test(false)
}
func test(qq interface{}) {
value := qq.(string)
fmt.Println(value)
}
panic: interface conversion: interface {} is int, not string
要防止上面的悲劇產生,可以考慮用switch來做斷言判斷
package main
import "fmt"
func main() {
test("GG")
test(123)
test(false)
}
func test(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("interface value is int: %v \n", v)
case string:
fmt.Printf("interface value is string: %v \n", v)
case bool:
fmt.Printf("interface value is bool: %v \n", v)
default:
fmt.Printf("interface value unknown type: %v \n", v)
}
}
除了可以當參數外,也可以當reuturn值回傳。
package main
import "fmt"
func main() {
v := test2("GG")
fmt.Printf("this is return interface:%v", v)
}
func test2(qq string) (res interface{}) {
type gg struct {
qq string
gg int
}
ininder := gg{
qq: qq,
gg: 30,
}
return ininder
}
interface那麼有彈性,是不是全都塞interface當參數就好了,
當然不能這樣子做,彈性越高,效能折損就越多,除非不在乎效能慢,
碼農當然比寫出來的code效能越好越屌rrrr。
除非當型態外,也可以跟一般的oop(Object-oriented programming,ex c#)語言的interface介面一樣用途,只是golang非oop語言,所以沒有繼承的概念。
要怎麼實作介面呢,一樣直接用範例來說明
package main
import (
"fmt"
"math"
)
//宣告名為幾何的interface
type geometry interface {
//定義了area 面積與perim的function
area() float64
perim() float64
}
//定義名為矩形的結構
type rect struct {
width, height float64
}
//定義名為圓形的結構
type circle struct {
radius float64
}
//矩形的求面積 function
func (r rect) area() float64 {
return r.width * r.height
}
//矩形的求周長 function
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
//圓形的求面積 function
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
//圓形的求周長 function
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
//定義一個測量的function來進行計算
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{width: 2, height: 3}
c := circle{radius: 10}
measure(r)
measure(c)
}
可以看到rect跟circle不同的struct可以丟進measure這個function去執行,
但是這二個struct都有定義area跟perim 這二個function,跟geometry定義的一致,
只是geometry只有定義function的名稱跟回傳值,裡面的實作是取決於struct實作的function。