日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
我終于識(shí)破了這個(gè)Go編譯器把戲

本文轉(zhuǎn)載自微信公眾號(hào)「Golang技術(shù)分享」,作者機(jī)器鈴砍菜刀。轉(zhuǎn)載本文請(qǐng)聯(lián)系Golang技術(shù)分享公眾號(hào)。

成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)制作、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的長(zhǎng)順網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

在 Go 語(yǔ)言的日常編碼工作中,有一個(gè)非常普遍但詭異的編譯錯(cuò)誤,曾讓我十分困惑。這個(gè)問(wèn)題我相信不少 Gopher 都遇到過(guò),不妨來(lái)看一下。

背景回顧

我們定義一個(gè)帶有 WriteGoCode() 方法的 Gopher 接口,同時(shí)定義了 person 結(jié)構(gòu)體,它存在 WriteGoCode() 方法。

 
 
 
 
  1. type Gopher interface { 
  2.  WriteGoCode() 
  3.  
  4. type person struct { 
  5.  name string 
  6.  
  7. func (p person) WriteGoCode() { 
  8.  fmt.Printf("I am %s, i am writing go code!\n", p.name) 

在 Go 語(yǔ)言中,只要某對(duì)象擁有接口的所有方法,那該對(duì)象即實(shí)現(xiàn)了該接口。p 是 person 結(jié)構(gòu)體的實(shí)例化對(duì)象, Coding() 函數(shù)的入?yún)⑹?Gopher 接口, person 對(duì)象實(shí)現(xiàn)了 Gopher 接口,因此 p 入?yún)⒊晒Ρ贿\(yùn)行。

 
 
 
 
  1. func Coding(g Gopher) { 
  2.  g.WriteGoCode() 
  3.  
  4. func main() { 
  5.  p := person{name: "小菜刀"} 
  6.  Coding(p) 
  7.  
  8. // output: 
  9. I am 小菜刀, i am writing go code! 

此時(shí),我們將 Coding() 函數(shù)的入?yún)⒏臑?[]Gopher 類型,入?yún)?[]person 。

 
 
 
 
  1. func Coding(g Gopher) { 
  2.  g.WriteGoCode() 
  3.  
  4. func main() { 
  5.  p := person{name: "小菜刀"} 
  6.  Coding(p) 
  7.  
  8. // output: 
  9. I am 小菜刀, i am writing go code! 

但是,這個(gè)時(shí)候,編譯卻不能通過(guò)!

 
 
 
 
  1. ./main.go:29:8: cannot use p (type []person) as type []Gopher in argument to Coding 

明明 person 類型實(shí)現(xiàn)了 Gopher 接口,且當(dāng)函數(shù)入?yún)?Gopher 類型時(shí),能夠順利被執(zhí)行,但參數(shù)變?yōu)?[]Gopher 時(shí),卻過(guò)不了編譯,這是為什么?

語(yǔ)法通用規(guī)則

這個(gè)問(wèn)題在 stackoverflow 上被熱議,詳情見(jiàn)文末參考鏈接1。

在 Go 中,有一個(gè)通用規(guī)則,即語(yǔ)法不應(yīng)隱藏復(fù)雜/昂貴的操作。轉(zhuǎn)換一個(gè) string 到 interface{} 它的時(shí)間復(fù)雜度是 O(1),轉(zhuǎn)換 []string 到 interface{} 同樣也是一個(gè) O(1) 操作,因?yàn)樗€是一個(gè)單一值的轉(zhuǎn)換。

如果要將 []string 轉(zhuǎn)換為 []interface{},它是 O(N) 操作。因?yàn)榍衅拿總€(gè)元素都必須轉(zhuǎn)換為 interface{},這違背了 Go 的語(yǔ)法原則。

這個(gè)回答,你們同意嗎?

當(dāng)然,此規(guī)則存在一個(gè)例外:轉(zhuǎn)換字符串。在將 string 轉(zhuǎn)換為 []byte 或 []rune 時(shí),即使需要 O(n) 操作,但 Go 會(huì)允許執(zhí)行。

InterfaceSlice 問(wèn)題

Ian Lance Taylor(Go 核心開(kāi)發(fā)者) 在 Go 官方倉(cāng)庫(kù)中也回答了這個(gè)問(wèn)題,詳情見(jiàn)文末參考鏈接2。他給出了這樣做的兩個(gè)主要原因。

原因一:類型為 []interface{} 的變量不是 interface!它僅僅是一個(gè)元素類型恰好為 interface{} 的切片。

原因二:[]interface{} 變量有特定大小的內(nèi)存布局,在編譯期可知。這與 []MyType 是不同的。

每個(gè) interface{} (運(yùn)行時(shí)通過(guò) runtime.eface 表示)占兩個(gè)字長(zhǎng)(一個(gè)字代表所包含內(nèi)容的類型 _type,另外一個(gè)字表示所包含的數(shù)據(jù) data 或者指向它的指針 )

因此,類型為 []interface{} 的長(zhǎng)度為 N 的變量,它是由 N*2 個(gè)字長(zhǎng)的數(shù)據(jù)塊支持。而這與類型為 []MyType 的長(zhǎng)度為 N 的變量的數(shù)據(jù)塊大小是不同的,因?yàn)楹笳叩臄?shù)據(jù)塊是 N*sizeof(MyType) 字長(zhǎng)。

數(shù)據(jù)塊的不同,造成的結(jié)果是編譯器無(wú)法快速地將 []MyType 類型的內(nèi)容分配給 []interface{} 類型的內(nèi)容。

同理,[]Gopher 變量也是特定大小的內(nèi)存布局(運(yùn)行時(shí)通過(guò) runtime.iface 表示)。這同樣不能快速地將 []MyType 類型的內(nèi)容分配給 []Gopher 類型。

因此,Ian Lance Taylor 回答閉環(huán)了 Go 的語(yǔ)法通用規(guī)則:Go 語(yǔ)法不應(yīng)隱藏復(fù)雜/昂貴的操作,編譯器會(huì)拒絕它們。

代碼解決方案

再次將文章開(kāi)頭的例子附上,如果我們需要 [] person 類型的 p 能夠成功入?yún)?Coding() 函數(shù),應(yīng)該如何做呢。

 
 
 
 
  1. func Coding(gs []Gopher) { 
  2.  for _, g := range gs { 
  3.   g.WriteGoCode() 
  4.  } 
  5.  
  6. func main() { 
  7.  p := []person{ 
  8.   {name: "小菜刀1號(hào)"}, 
  9.   {name: "小菜刀2號(hào)"}, 
  10.  } 
  11.  Coding(p) 

代碼方案如下,核心是需要一個(gè) []Gopher 類型的轉(zhuǎn)換變量。

 
 
 
 
  1. func main() { 
  2.  p := []person{ 
  3.   {name: "小菜刀1號(hào)"}, 
  4.   {name: "小菜刀2號(hào)"}, 
  5.  } 
  6.  var interfaceSlice []Gopher = make([]Gopher, len(p)) 
  7.  for i, g := range p { 
  8.   interfaceSlice[i] = g 
  9.  } 
  10.  Coding(interfaceSlice) 
  11.  
  12. // output: 
  13. I am 小菜刀1號(hào), i am writing go code! 
  14. I am 小菜刀2號(hào), i am writing go code! 

總結(jié)

由于 []MyType 到 []interface{} 的轉(zhuǎn)換,是昂貴的操作,Go 編譯器不會(huì)允許這種情況通過(guò)編譯,故而將這種開(kāi)銷的責(zé)任傳遞給開(kāi)發(fā)者。

Go 是一門(mén)編譯速度很快的語(yǔ)言,得益于它語(yǔ)法設(shè)計(jì)中貫徹著 “simpler is better” 的理念,這可不是說(shuō)說(shuō)而已。

參考鏈接

【1. Type converting slices of interfaces】https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces/12754757#12754757

【2. InterfaceSlice】https://github.com/golang/go/wiki/InterfaceSlice


本文標(biāo)題:我終于識(shí)破了這個(gè)Go編譯器把戲
分享路徑:http://www.dlmjj.cn/article/dhpshss.html