精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

為什么 Go 不支持 []T 轉換為 []interface

開發 前端
還有其他方式嗎?答案就是 Go 1.18 支持的泛型,這里就不過多介紹了,大家有興趣的話可以繼續研究。

在 Go 中,如果 interface{} 作為函數參數的話,是可以傳任意參數的,然后通過類型斷言來轉換。

舉個例子:

package main

import "fmt"

func foo(v interface{}) {
if v1, ok1 := v.(string); ok1 {
fmt.Println(v1)
} else if v2, ok2 := v.(int); ok2 {
fmt.Println(v2)
}
}

func main() {
foo(233)
foo("666")
}

不管是傳 int? 還是 string,最終都能輸出正確結果。

那么,既然是這樣的話,我就有一個疑問了,拿出我舉一反三的能力。是否可以將 []T? 轉換為 []interface 呢?

比如下面這段代碼:

func foo([]interface{}) { /* do something */ }

func main() {
var a []string = []string{"hello", "world"}
foo(a)
}

很遺憾,這段代碼是不能編譯通過的,如果想直接通過 b := []interface{}(a) 的方式來轉換,還是會報錯:

cannot use a (type []string) as type []interface {} in function argument

正確的轉換方式需要這樣寫:

b := make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}

本來一行代碼就能搞定的事情,卻非要讓人寫四行,是不是感覺很麻煩?那為什么 Go 不支持呢?我們接著往下看。

官方解釋

這個問題在官方 Wiki 中是有回答的,我復制出來放在下面:

The first is that a variable with type []interface{}? is not an interface! It is a slice whose element type happens to be interface{}. But even given this, one might say that the meaning is clear. Well, is it? A variable with type []interface{}? has a specific memory layout, known at compile time. 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.

大概意思就是說,主要有兩方面原因:

  1. []interface{}? 類型并不是interface?,它是一個切片,只不過碰巧它的元素是interface;
  2. []interface{}? 是有特殊內存布局的,跟interface 不一樣。

下面就來詳細說說,是怎么個不一樣。

內存布局

首先來看看 slice 在內存中是如何存儲的。在源碼中,它是這樣定義的:

// src/runtime/slice.go

type slice struct {
array unsafe.Pointer
len int
cap int
}

  • array 是指向底層數組的指針;
  • len 是切片的長度;
  • cap? 是切片的容量,也就是array 數組的大小。

舉個例子,創建如下一個切片:

is := []int64{0x55, 0x22, 0xab, 0x9}

那么它的布局如下圖所示:

圖片

假設程序運行在 64 位的機器上,那么每個「正方形」所占空間是 8 bytes。上圖中的 ptr 所指向的底層數組占用空間就是 4 個「正方形」,也就是 32 bytes。

接下來再看看 []interface{} 在內存中是什么樣的。

回答這個問題之前先看一下 interface{} 的結構,Go 中的接口類型分成兩類:

  1. iface 表示包含方法的接口;
  2. eface 表示不包含方法的空接口。

源碼中的定義分別如下:

type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}

具體細節我們不去深究,但可以明確的是,每個 interface{}? 包含兩個指針, 會占據兩個「正方形」。第一個指針指向 itab? 或者 _type;第二個指針指向實際的數據。

所以它在內存中的布局如下圖所示:

圖片

因此,不能直接將 []int64? 直接傳給 []interface{}。

程序運行中的內存布局

接下來換一個更形象的方式,從程序實際運行過程中,看看內存的分布是怎么樣的?

看下面這樣一段代碼:

package main

var sum int64

func addUpDirect(s []int64) {
for i := 0; i < len(s); i++ {
sum += s[i]
}
}

func addUpViaInterface(s []interface{}) {
for i := 0; i < len(s); i++ {
sum += s[i].(int64)
}
}

func main() {
is := []int64{0x55, 0x22, 0xab, 0x9}

addUpDirect(is)

iis := make([]interface{}, len(is))
for i := 0; i < len(is); i++ {
iis[i] = is[i]
}

addUpViaInterface(iis)
}

我們使用 Delve 來進行調試,可以點擊這里進行安裝。

dlv debug slice-layout.go
Type 'help' for list of commands.
(dlv) break slice-layout.go:27
Breakpoint 1 set at 0x105a3fe for main.main() ./slice-layout.go:27
(dlv) c
> main.main() ./slice-layout.go:27 (hits goroutine(1):1 total:1) (PC: 0x105a3fe)
22: iis := make([]interface{}, len(is))
23: for i := 0; i < len(is); i++ {
24: iis[i] = is[i]
25: }
26:
=> 27: addUpViaInterface(iis)
28: }

打印 is 的地址:

(dlv) p &is
(*[]int64)(0xc00003a740)

接下來看看 slice 在內存中都包含了哪些內容:

(dlv) x -fmt hex -len 32 0xc00003a740
0xc00003a740: 0x10 0xa7 0x03 0x00 0xc0 0x00 0x00 0x00
0xc00003a748: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a750: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a758: 0x00 0x00 0x09 0x00 0xc0 0x00 0x00 0x00

每行有 8 個字節,也就是上文說的一個「正方形」。第一行是指向數據的地址;第二行是 4,表示切片長度;第三行也是 4,表示切片容量。

再來看看指向的數據到底是怎么存的:

(dlv) x -fmt hex -len 32 0xc00003a710
0xc00003a710: 0x55 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a718: 0x22 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a720: 0xab 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a728: 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x00

這就是一片連續的存儲空間,保存著實際數據。

接下來用同樣的方式,再來看看 iis 的內存布局。

(dlv) p &iis
(*[]interface {})(0xc00003a758)
(dlv) x -fmt hex -len 32 0xc00003a758
0xc00003a758: 0x00 0x00 0x09 0x00 0xc0 0x00 0x00 0x00
0xc00003a760: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a768: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xc00003a770: 0xd0 0xa7 0x03 0x00 0xc0 0x00 0x00 0x00

切片的布局和 is 是一樣的,主要的不同是所指向的數據:

(dlv) x -fmt hex -len 64 0xc000090000
0xc000090000: 0x00 0xe4 0x05 0x01 0x00 0x00 0x00 0x00
0xc000090008: 0xa8 0xee 0x0a 0x01 0x00 0x00 0x00 0x00
0xc000090010: 0x00 0xe4 0x05 0x01 0x00 0x00 0x00 0x00
0xc000090018: 0x10 0xed 0x0a 0x01 0x00 0x00 0x00 0x00
0xc000090020: 0x00 0xe4 0x05 0x01 0x00 0x00 0x00 0x00
0xc000090028: 0x58 0xf1 0x0a 0x01 0x00 0x00 0x00 0x00
0xc000090030: 0x00 0xe4 0x05 0x01 0x00 0x00 0x00 0x00
0xc000090038: 0x48 0xec 0x0a 0x01 0x00 0x00 0x00 0x00

仔細觀察上面的數據,偶數行內容都是相同的,這個是 interface{}? 的 itab 地址。奇數行內容是不同的,指向實際的數據。

打印地址內容:

(dlv) x -fmt hex -len 8 0x010aeea8
0x10aeea8: 0x55 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(dlv) x -fmt hex -len 8 0x010aed10
0x10aed10: 0x22 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(dlv) x -fmt hex -len 8 0x010af158
0x10af158: 0xab 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(dlv) x -fmt hex -len 8 0x010aec48
0x10aec48: 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x00

很明顯,通過打印程序運行中的狀態,和我們的理論分析是一致的。

通用方法

通過以上分析,我們知道了不能轉換的原因,那有沒有一個通用方法呢?因為我實在是不想每次多寫那幾行代碼。

也是有的,用反射 reflect,但是缺點也很明顯,效率會差一些,不建議使用。

func InterfaceSlice(slice interface{}) []interface{} {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("InterfaceSlice() given a non-slice type")
}

// Keep the distinction between nil and empty slice input
if s.IsNil() {
return nil
}

ret := make([]interface{}, s.Len())

for i := 0; i < s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}

return ret
}

還有其他方式嗎?答案就是 Go 1.18 支持的泛型,這里就不過多介紹了,大家有興趣的話可以繼續研究。

以上就是本文的全部內容,如果覺得還不錯的話歡迎點贊,轉發和關注,感謝支持。

參考文章:

  • https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces
  • https://github.com/golang/go/wiki/InterfaceSlice
  • https://eli.thegreenplace.net/2021/go-internals-invariance-and-memory-layout-of-slices/
責任編輯:武曉燕 來源: AlwaysBeta
相關推薦

2021-10-27 07:15:36

Go 循環引用

2021-12-09 10:51:47

Go繼承

2021-12-15 07:49:22

Go語言設計

2024-01-01 08:10:40

Go語言map

2024-05-28 08:55:52

2024-01-05 08:45:35

Go語言map

2021-11-08 11:02:01

Go函數重載

2023-02-26 23:36:08

PHPGo函數

2024-03-08 08:51:59

Gomain函數

2020-10-09 06:48:19

Pythonswitch語句

2020-07-22 08:01:41

Python開發運算符

2024-03-12 09:13:28

Go語言main

2025-10-31 02:30:00

Go系統Protobuf

2021-02-01 13:53:53

StringlongJava

2009-03-12 08:42:38

AndroidWMMTK

2021-06-11 00:03:31

鴻蒙智能手機

2021-08-02 09:31:20

Python工具代碼

2025-06-26 02:22:00

GoProtobuf標簽

2023-04-03 11:21:29

PythonGoRust

2021-07-13 08:09:34

微博推特評論
點贊
收藏

51CTO技術棧公眾號

日本女优爱爱视频| 日本欧美精品久久久| 免费在线观看日韩| 老牛影视av一区二区在线观看| 午夜精品福利一区二区三区av| 久久综合婷婷综合| 中文字幕在线有码| 福利一区和二区| 久久精品综合网| 国产日产欧美精品| 国产在线视频卡一卡二| 狠狠色狠狠色综合婷婷tag| 在线不卡中文字幕| 国产淫片免费看| jizz在线观看| 成人妖精视频yjsp地址| 国产成人福利网站| 精品人妻一区二区三区视频| 欧洲精品久久久久毛片完整版| 一区二区欧美视频| 亚洲精品在线视频观看| 成人久久精品人妻一区二区三区| 玖玖在线精品| 色综合久久天天综线观看| 国产精品免费无码| 国产精品天天看天天狠| 欧美日韩国产免费一区二区| 亚洲欧洲一区二区在线观看| 伊人网免费视频| 成人羞羞网站入口| 精品国产三级电影在线观看| 亚洲一级片网站| 91激情在线| 精品亚洲aⅴ乱码一区二区三区| 97视频在线观看免费| 欧美色视频一区二区三区在线观看| 日韩激情毛片| 精品国产成人系列| 免费无码av片在线观看| 男女在线观看视频| 99精品久久99久久久久| 91色在线观看| 国产一级做a爰片在线看免费| 91影院成人| 亚洲午夜激情免费视频| 亚洲综合欧美在线| 国产黄网站在线观看| 国产日韩欧美不卡在线| 国产日韩在线亚洲字幕中文| 少妇久久久久久被弄高潮| 日本一区二区免费高清| 欧美一级片在线观看| 91福利国产成人精品播放| 国产淫片在线观看| 中文字幕一区二区在线播放| 亚洲国产欧美日韩| 成在在线免费视频| 欧美韩国日本一区| 日韩区国产区| av在线电影免费观看| 国产一区二区三区四区五区入口 | 头脑特工队2在线播放| 国产aⅴ综合色| 91视频网页| www.97av.com| 亚洲欧美高清| 日韩在线观看免费高清完整版| jizz中文字幕| 日本一区二区高清不卡| 最新91在线视频| 无码人妻一区二区三区在线| 成人免费网站www网站高清| 亚洲人成影院在线观看| 日本一区二区三区在线视频| 国产福利小视频在线观看| 国产欧美一区在线| 国产精选在线观看91| 成人免费一级片| 日本系列欧美系列| 97成人精品视频在线观看| 亚洲欧美综合7777色婷婷| 久久精品国产99久久| 亚洲国内精品在线| 亚洲午夜福利在线观看| 综合伊人久久| 亚洲激情电影中文字幕| 中文字幕 自拍| 国产精品久久久久久久久久10秀 | 欧美精品97| 亚洲视频在线观看| 日本免费网站视频| 国产精品videossex久久发布| 最新国产精品拍自在线播放| 永久免费看片直接| 成人影视亚洲图片在线| 亚洲男人天堂网站| 成人三级视频在线观看| 国产欧美一区二区三区精品观看 | 国产精品一区二区三区成人| 精品久久久中文字幕人妻| 成人18视频在线播放| 日韩在线国产| 国产鲁鲁视频在线观看免费| 91亚洲精品乱码久久久久久蜜桃| 日本欧美精品久久久| 免费在线超碰| 91视频免费观看| 亚洲欧洲另类精品久久综合| 国产高清一级毛片在线不卡| 一区二区三区在线视频观看| 免费大片在线观看| 芒果视频成人app| 欧美午夜视频一区二区| 天天色天天综合网| 最新亚洲精品| 欧美激情第6页| 欧美人与禽zozzo禽性配| 亚洲精品一区二区在线看| 庆余年2免费日韩剧观看大牛| 精品国产免费观看| 国内成人免费视频| 欧美人与性禽动交精品| av在线中文| 岛国av一区二区三区| 欧美日韩在线视频一区二区三区| 四虎视频在线精品免费网址| 亚洲欧美国产精品专区久久| 青娱乐国产在线| 99国产精品久久久久久久成人热| 国产在线98福利播放视频| 国产精品一区二区三区在线免费观看| 26uuu久久天堂性欧美| 大片在线观看网站免费收看| 欧美啪啪网站| 国产亚洲欧美另类中文| 日韩黄色在线视频| 风间由美一区二区三区在线观看| 伊人久久大香线蕉综合75| 欧美成人资源| 日韩成人在线视频观看| 四虎永久在线精品| 国产91在线|亚洲| 免费观看国产视频在线| 久久亚洲精品人成综合网| 亚洲无限av看| 久久精品视频2| 久久婷婷色综合| 欧美日韩一道本| 久久精品国产亚洲5555| 久久久视频免费观看| 午夜精品久久久久久久91蜜桃| 亚洲欧洲成人自拍| 免费成人黄色大片| 91视频综合| 亚洲精品免费一区二区三区| 免费a级毛片在线播放| 午夜精品久久久久久久| 日本一区二区免费视频| 国产精品视频一区二区三区四蜜臂| 午夜精品99久久免费| 一卡二卡在线视频| 9人人澡人人爽人人精品| 成人免费性视频| a看欧美黄色女同性恋| 久久久久久久久久久久久久久久久久av| 国产成人三级在线播放 | 精品亚洲永久免费| 日韩国产精品久久久| 日韩精品久久一区二区三区| 成人福利片在线| 日韩一区二区在线视频| 国产精品黄色大片| 国产成人综合视频| 亚洲精品二区| 精品国产一区二区三区性色av | 欧美伊人久久久久久午夜久久久久| 成人在线一级片| 国产字幕视频一区二区| 精品国产乱码久久久久久丨区2区 精品国产乱码久久久久久蜜柚 | gogo在线高清视频| 精品999久久久| 日本黄色片免费观看| 国产成人日日夜夜| 一卡二卡三卡视频| 久久99国产成人小视频| 国产专区精品视频| 9999精品成人免费毛片在线看 | 欧美jizz18性欧美| 欧美午夜女人视频在线| 色噜噜噜噜噜噜| 国产精品123区| 中文字幕中文字幕在线中心一区| 日韩性xxx| 日韩成人中文电影| 日本va欧美va国产激情| 国产精品美女久久久久久久久久久| 欧美不卡在线播放| 成人直播大秀| 国产精品久久久久久久久久尿| 四季av日韩精品一区| 亚洲一区二区精品久久av| 91精品人妻一区二区| 亚洲精品色图| 精品国产一区二区三| 123成人网| 久久久久亚洲精品国产| av片在线免费观看| 欧美日韩电影在线| 一本一本久久a久久| 久久精品久久精品| 亚洲欧美日韩国产yyy| jizzjizzjizz欧美| 国产精品三级久久久久久电影| 国产美女性感在线观看懂色av| 日韩免费一区二区| 亚洲视频久久久| 懂色av影视一区二区三区| 欧美做爰爽爽爽爽爽爽| 成人在线综合网站| 又粗又黑又大的吊av| 亚洲综合五月| 丁香婷婷久久久综合精品国产| 日韩一区二区三区免费| 自拍亚洲一区欧美另类| 国产精品老熟女视频一区二区| 亚洲欧美日韩在线| 美国黄色特级片| 久久久另类综合| 欧美在线一级片| 国产高清久久久| 99re6在线观看| 欧美日韩1080p| 中文精品一区二区三区| 亚洲一区二区三区四区电影| 性金发美女69hd大尺寸| 你懂的在线看| 亚洲精品一区二区三区四区高清| 国产成人无码专区| 欧美日韩一区二区免费在线观看| 国产性猛交普通话对白| 亚洲男人电影天堂| 亚洲一区二区三区四区五区六区| 成人综合婷婷国产精品久久 | 在线一区日本视频| 国产一区二区精品福利地址| 开心色怡人综合网站| 欧美天堂影院| 国产在线精品自拍| rebdb初裸写真在线观看| 亚洲热线99精品视频| 天堂a√在线| 欧美美女喷水视频| 五月婷婷开心网| 午夜不卡在线视频| 西西44rtwww国产精品| 亚洲精品成a人| 国产精品天天干| 久久久精品日韩欧美| 黑人巨大精品欧美| 国产激情视频一区二区在线观看 | 久久er99热精品一区二区三区 | 久久久成人网| 欧美人与动牲交xxxxbbbb| 久久爱www成人| 欧美精彩一区二区三区| 精品国产一区二区三区久久久蜜臀| 青青草国产精品| 国产乱人伦精品一区| 国产有码在线一区二区视频| 在线黄色的网站| 欧美精品18videos性欧美| av电影在线观看一区二区三区| 中文字幕欧美日韩精品| 91一区二区三区在线| 国内揄拍国内精品少妇国语| 免费a级毛片在线播放| 欧美成人国产va精品日本一级| 国产美女视频一区二区三区| 亚洲白拍色综合图区| 国产乱码精品一区二区三区精东| 日本韩国一区二区三区| 韩国av免费观看| 日韩欧美国产网站| 91久久久久久久久久久久| 一本久道久久综合中文字幕 | 香蕉视频黄色在线观看| 国产成人超碰人人澡人人澡| 一级黄色高清视频| 成人av综合在线| 美国黑人一级大黄| 久久精品无码一区二区三区| 亚洲色图27p| 亚洲h在线观看| 伊人久久成人网| 亚洲成色999久久网站| 国产福利小视频在线| 亚洲欧洲在线观看| 国产三区在线观看| 久久精品色欧美aⅴ一区二区| 川上优的av在线一区二区| 欧美成人精品一区二区| 二区三区不卡| 日韩女优人人人人射在线视频| 国产精品视频一区二区三区| 成人午夜在线视频一区| 久久电影在线| 免费成人在线观看av| 亚洲美女视频| wwwwww欧美| 日本一不卡视频| 六十路息与子猛烈交尾| 中文字幕综合网| 国产精品视频一区二区三 | 国产成人a视频高清在线观看| 国产91一区二区三区| 久久神马影院| 红桃av在线播放| 成人av在线一区二区| 中出视频在线观看| 久久综合色一综合色88| 久久久一二三区| 欧美日韩五月天| 国产强被迫伦姧在线观看无码| 亚洲女同精品视频| 8888四色奇米在线观看| 97在线视频免费观看| 日韩精品成人在线观看| 一区二区三区|亚洲午夜| 一本精品一区二区三区| 国产精品入口免费软件| 91色视频在线| 欧美成人短视频| 狠狠色狠色综合曰曰| 亚洲第一第二区| 久久天天躁狠狠躁夜夜爽蜜月| 成人va天堂| 91大片在线观看| 99国产精品免费网站| 熟妇熟女乱妇乱女网站| 麻豆精品视频在线观看免费| 亚洲区自拍偷拍| 色婷婷综合久久久中文字幕| 一区二区三区黄色片| 最近2019免费中文字幕视频三 | 男人的天堂最新网址| 国产精品天美传媒| 国产精品theporn动漫| 日韩一区二区三区免费看| 毛片激情在线观看| 97视频在线观看免费| 成人免费黄色| 色一情一区二区三区四区 | 天天干天天av| av在线播放成人| 特级西西人体高清大胆| 欧美网站一区二区| 尤物网在线观看| 国产日韩中文字幕在线| 希岛爱理av免费一区二区| 霍思燕三级露全乳照| www.亚洲在线| 波多野结衣喷潮| 欧美午夜精品久久久久久浪潮 | 成人午夜在线| 国产另类第一区| 国产精品毛片久久| 激情久久综合网| 国产日韩av一区二区| 中文字幕一区二区三区四区视频 | 婷婷综合久久一区二区三区| 91麻豆一区二区| 美女视频黄免费的亚洲男人天堂| 网站一区二区| 在线观看欧美一区| 国产精一品亚洲二区在线视频| 亚洲黄色小说视频| 香蕉加勒比综合久久| 国产一区二区在线视频观看| 蜜臀久久99精品久久久久久宅男 | 在线观看av一区| 久久久久久国产精品免费无遮挡| 不卡一区二区三区视频| 亚洲尤物影院| 亚洲激情 欧美| 在线视频一区二区三区| а天堂中文在线官网| 久久国产精品一区二区三区四区| 久久性色av| 男女做暖暖视频| 91麻豆精品国产自产在线观看一区 | 久久午夜av| 午夜精品一区二区三级视频| 日韩精品一区二区三区在线播放| 哥也色在线视频| 国产精品一区二区免费看| 视频一区在线播放| 欧美做受xxxxxⅹ性视频| 91精品麻豆日日躁夜夜躁| 免费观看成人高潮| 久久亚洲一区二区|