日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

理解Golang中的[]interface{}和interface{}

發布時間:2023/12/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解Golang中的[]interface{}和interface{} 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

理解Golang中的[]interface{}和interface{}

原文鏈接: 理解Golang中的[]interface{}和interface{}

之前在開發Go項目操作Redis時,利用Do函數進行數據操作,在返回的interface{}類型的轉換中踩了一個大坑。

Do(ctx, "HKEYS", "KEY")

在閱讀源碼中發現,Do方法的是一個[]interface{}切片

func (c *Redis) Do(ctx context.Context, commandName string, args ...interface{}) (interface{}, error) {//// ...//reply, err := conn.Do(commandName, args...)//// ...//return reply, c.err } func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {return c.DoWithTimeout(c.readTimeout, cmd, args...) } func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {//// ...//reply := make([]interface{}, pending)//// ...//return reply, err }

在Goland中有一種特殊類型:interface{} ,空接口。interface{} 類型是沒有方法的接口。由于沒有 implements 關鍵字,所以所有類型都至少實現了 0 個方法,所以 所有類型都實現了空接口。這意味著,如果編寫一個函數以 interface{} 值作為參數,那么可以為該函數提供任何值,并且,[]interface{}在golang中也可以認為是interface{}

func main() {method("string")method(123)method(make(map[string]int))method(make([]interface{}, 0))method(true) }func method(arg interface{}) {}

所以Do方法的返回值是interface{}類型,但本質上應該是[]interface{}類型,又因為redis的hkeys操作返回的是field字符串數組

那么上述命令的返回值實際上應該是[]string或者[]byte類型,于是利用golang的類型判定,寫出了如下代碼

func main() {var a interface{} = method()bytes := a.([]byte)fmt.Println(bytes) }func method() interface{} {ans := make([]interface{}, 0)return append(ans, []byte{96, 97, 98, 99}) }

然而,編譯器狠狠的打了我的臉

既然interface{}能代表任意類型,那么interface{}的切片為什么不能代表任意類型的切片呢?

了解了相關底層數據存儲原理后,這個問題也就迎刃而解了

一個interface{}類型的變量的底層存儲結構由兩個字word組成;一個字用于指向該值底層類型的方法表,另一個字用于指向實際數據

type eface struct {_type *_typedata unsafe.Pointer }

所以即使兩個變量都是interface{}類型,但底層的類型不同,則兩個變量不相等

var (a interface{} = 123b interface{} = "string" ) fmt.Println(a == b) // false

那么對于[]interface{}類型的變量來說,切片里的每個元素可以存儲不同類型的變量,例如

func main() {var a = make([]interface{}, 0)a = append(a, []int{123, 456})a = append(a, []string{"abc", "ijk"})fmt.Println(a) // [[123 456] [abc ijk]] }

但即使切片里存的數據都是某個特定的類型,也不能通過類型斷定來強制轉換,因為底層的數據存儲結構不同

func main() {a := method()_, ok := a.([]int)fmt.Println(ok) // false }func method() interface{} {var a = make([]interface{}, 0)a = append(a, []int{123, 456})a = append(a, []int{789, 111})return a }

Each interface{} takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type []interface{} is backed by a chunk of data that is N*2 words long.

This is different than the chunk of data backing a slice with type []MyType and the same length. Its chunk of data will be N*sizeof(MyType) words long.

The result is that you cannot quickly assign something of type []MyType to something of type []interface{}; the data behind them just look different.

那么如果我們要把同類型組成的切片轉換成的特定類型,可以這樣做

func main() {a := method()ans := make([][]int, 0)b, ok := a.([]interface{})if ok {for _, element := range b {ans = append(ans, element.([]int))}}fmt.Println(ans) // [[123 456] [789 111]] }func method() interface{} {var a = make([]interface{}, 0)a = append(a, []int{123, 456})a = append(a, []int{789, 111})return a }

參考文章:

InterfaceSlice · golang/go Wiki (github.com)

總結

以上是生活随笔為你收集整理的理解Golang中的[]interface{}和interface{}的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。