iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
0

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。


上一篇
[DAY10]一起來陷入function地獄吧
下一篇
[DAY12]GO要怎麼處理錯誤呢
系列文
欸你這週GO了嘛30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言