Go基礎系列 介面型別斷言和type switch

2021-09-07 20:22:51 字數 3295 閱讀 9172

介面例項中儲存了實現介面的型別例項,型別的例項有兩種:值型別例項和指標型別例項。在程式執行過程中,介面例項儲存的例項型別可能會動態改變。例如:

// ins是介面例項

var ins shaper

// ins儲存值型別的例項

ins = c1

// 一段時間後...

...// ins儲存指標型別的例項,儲存的型別發生改變

ins = c2

// 一段時間後...

// ins可能儲存另乙個型別例項

ins = s1

所以,需要一種探測介面例項所儲存的是值型別還是指標型別。

探測的方法是:ins.(type)ins.(*type)。它們有兩個返回值,第二個返回值是ok返回值,布林型別,第乙個返回值是探測出的型別。也可以只有乙個返回值:探測出的型別。

// 如果ins儲存的是值型別的type,則輸出

if t, ok := ins.(type); ok

// 如果ins儲存的是指標型別的*type,則輸出

if t, ok := ins.(*type); ok

// 乙個返回值的探測

t := ins.(type)

t := ins.(*type)

以下是乙個例子:

package main

import "fmt"

// shaper 介面型別

type shaper inte***ce

// square struct型別

type square struct

// square型別實現shaper中的方法area()

func (s square) area() float64

func main()

// 值型別的例項

s2 := square

ins2 = s2

if v, ok := ins2.(square); ok

}

上面兩個printf都會輸出,因為它們的型別判斷都返回true。如果將ins2.(square)改為ins2.(*square),第二個printf將不會輸出,因為ins2它儲存的是值型別的例項。

以下是輸出結果:

ins1: *main.square

ins2: main.square

特別需要注意的是,ins必須明確是介面例項。例如,以下前兩種宣告是有效的,第三種推斷型別是錯誤的,因為它可能是介面例項,也可能是型別的例項副本。

var ins shaper     // 正確

ins := shaper(s1) // 正確

ins := s1 // 錯誤

當ins不能確定是介面例項時,用它來進行測試,例如ins.(square)將會報錯:

invalid type assertion:ins.(square) (non-inte***ce type (type of ins) on left)
它說明了左邊的ins是非介面型別(non-inte***ce type)。

另一方面,通過介面型別斷言(ins.(type)),如果type是乙個介面型別,就可以判斷介面例項ins中所儲存的型別是否也實現了type介面。例如:

var r io.read

tty, err := os.openfile("/dev/tty", os.o_rdwr, 0)

if err != nil

r = tty

var w io.writer

w = r.(io.writer)

上面的r是io.read介面的乙個例項變數,它裡面儲存的是tty和它的型別,即(tty, *os.file),然後斷言r的型別,探測它裡面的型別*file是否也實現了io.writer介面,如果實現了,則儲存到io.writer介面的例項變數w中,這樣w例項也將儲存(tty,*os.file)

由於任意內容都實現了空介面,所以,總是可以把乙個介面例項無需通過任何斷言地賦值給乙個空介面例項:

var empty inte***ce{}

empty = w

現在empty也儲存了(tty,*os.file)

switch流程控制結構還可以用來探測介面例項儲存的型別。這種結構稱為type-switch

用法如下:

switch v := ins.(type)
其中ins.(type)中的小寫type是固定的詞語。

以下是乙個使用示例:

package main

import (

"fmt"

)// shaper 介面型別

type shaper inte***ce

// circle struct型別

type circle struct

// circle型別實現shaper中的方法area()

func (c *circle) area() float64

// square struct型別

type square struct

// square型別實現shaper中的方法area()

func (s square) area() float64

func main()

whichtype(s1)

s2 := square

whichtype(s2)

c1 := new(circle)

c1.radius = 2.3

whichtype(c1)

}func whichtype(n shaper)

}

上面的type-switch中,之所以沒有加上case circle,是因為circle只實現了指標型別的receiver,根據method set對介面的實現規則,只有指標型別的circle示例才算是實現了介面shaper,所以將值型別的示例case circle放進type-switch是錯誤的。

go 型別斷言 (57)介面的型別斷言

go提供了乙個方法,用來判斷介面的底層值是什麼型別 型別斷言提供了訪問介面值底層具體值的方式。t i.t 該語句斷言介面值i儲存了具體型別t,並將其底層型別為t的值賦予變數t。若i並未儲存t型別的值,該語句就會觸發乙個panic。為了判斷乙個介面值是否儲存了乙個特定的型別,型別斷言可返回兩個值 其底...

Go型別斷言

package main import fmt 型別斷言 type assertion 是乙個使用在介面值上的操作,用於檢查介面型別變數所持有的值是否實現了期望的介面或者具體的型別。如何進行型別斷言的判斷?1.使用if語句或者switch語句 2.依靠 value,ok x.t x 表示乙個介面的型...

Go之型別斷言

一 由於介面是基本型別,不知道具體型別,如果要轉成具體型別需要使用型別斷言 package main import fmt type dy struct func main var dy dy dy i1 dy var i2 dy dy i1 會報錯 型別斷言才能把介面轉為具體型別 i2 i1.dy...