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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

slice 转byte go_一文告诉你神奇的Go内建函数源码在哪里

發(fā)布時(shí)間:2024/7/5 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 slice 转byte go_一文告诉你神奇的Go内建函数源码在哪里 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Go內(nèi)建函數(shù)源碼,我好像在哪里見(jiàn)過(guò)你。 - 佚名

1. 何為Go內(nèi)建函數(shù)

眾所周知,Go是最簡(jiǎn)單的主流編程語(yǔ)言之一,截至Go 1.15版本,Go語(yǔ)言的關(guān)鍵字的規(guī)模依舊保持在25個(gè):

很多剛?cè)腴T的gopher可能會(huì)問(wèn):像bool、byte、error、true、iota甚至int都難道都不是關(guān)鍵字?沒(méi)錯(cuò)!和其他語(yǔ)言不同,這些標(biāo)識(shí)符并不是關(guān)鍵字,在Go中它們被稱為預(yù)定義標(biāo)識(shí)符。這些標(biāo)識(shí)符擁有universe block作用域(關(guān)于go代碼塊作用域的詳細(xì)解析,可參考我的技術(shù)專欄:“改善Go語(yǔ)?編程質(zhì)量的50個(gè)有效實(shí)踐”),可以在任何源碼位置使用。

從上圖我們看到:所謂的Go內(nèi)建函數(shù)也包含在這個(gè)預(yù)定義標(biāo)識(shí)符集合中,只是這些標(biāo)識(shí)符被用作函數(shù)名稱標(biāo)識(shí)符罷了。

2. 預(yù)定義標(biāo)識(shí)符可被override

Go語(yǔ)言的關(guān)鍵字是保留的,我們無(wú)法將其用于規(guī)范之外的其他場(chǎng)合,比如作為變量的標(biāo)識(shí)符。但是預(yù)定義標(biāo)識(shí)符不是關(guān)鍵字,我們可以override它們。下面就是一個(gè)對(duì)默認(rèn)表示整型類型的預(yù)定義標(biāo)識(shí)符int進(jìn)行override的例子:

package mainimport ("fmt""unsafe" )type int int8func main() {var a int = 5fmt.Printf("%Tn", a) // main.int,而不是intfmt.Println(unsafe.Sizeof(a)) // 1,而不是8 }

在上述這個(gè)源文件中,預(yù)定義標(biāo)識(shí)符int被override為一個(gè)自定義類型int,該類型的underlying type為int8,于是當(dāng)我們輸出該類型變量(代碼中的變量a)的類型和長(zhǎng)度時(shí),我們得到的是http://main.int和1,而不是int和8。

3. 預(yù)定義標(biāo)識(shí)符的聲明源碼在哪里

Go是開(kāi)源的編程語(yǔ)言,這些預(yù)定義標(biāo)識(shí)符想必也都有自己的“歸宿”吧,的確是這樣的。Go的每個(gè)發(fā)行版都帶有一份源碼,而預(yù)定義標(biāo)識(shí)符就在這份源碼中。

以Go 1.14為例,我們可以在下面路徑中找到預(yù)定義標(biāo)識(shí)符的源碼:

$GOROOT/src/builtin/builtin.go

以string、int、uint這幾個(gè)代表原生類型的預(yù)定義標(biāo)識(shí)符為例,它們的聲明代碼如下:

// $GOROOT/src/builtin/builtin.go// string is the set of all strings of 8-bit bytes, conventionally but not // necessarily representing UTF-8-encoded text. A string may be empty, but // not nil. Values of string type are immutable. type string string// int is a signed integer type that is at least 32 bits in size. It is a // distinct type, however, and not an alias for, say, int32. type int int// uint is an unsigned integer type that is at least 32 bits in size. It is a // distinct type, however, and not an alias for, say, uint32. type uint uint

同時(shí),我們利用go doc builtin.int也可以查看預(yù)定義標(biāo)識(shí)符int的文檔:

$go doc builtin.int package builtin // import "builtin"type int intint is a signed integer type that is at least 32 bits in size. It is adistinct type, however, and not an alias for, say, int32.func cap(v Type) int func copy(dst, src []Type) int func len(v Type) int

4. 內(nèi)建函數(shù)的源碼在哪里?

作為預(yù)聲明標(biāo)識(shí)符子集的內(nèi)建函數(shù)們?cè)赽uiltin.go中也都有自己的位置,比如:以append這個(gè)內(nèi)建函數(shù)為例,我們可以在Go安裝包的builtin.go中找到它的原型(Go 1.14):

// The append built-in function appends elements to the end of a slice. If // it has sufficient capacity, the destination is resliced to accommodate the // new elements. If it does not, a new underlying array will be allocated. // Append returns the updated slice. It is therefore necessary to store the // result of append, often in the variable holding the slice itself: // slice = append(slice, elem1, elem2) // slice = append(slice, anotherSlice...) // As a special case, it is legal to append a string to a byte slice, like this: // slice = append([]byte("hello "), "world"...) func append(slice []Type, elems ...Type) []Type

但我們驚奇的發(fā)現(xiàn):這里沒(méi)有append函數(shù)的實(shí)現(xiàn)。那么append內(nèi)建函數(shù)實(shí)現(xiàn)的源碼究竟在哪里呢?本質(zhì)上講append函數(shù),包括其他內(nèi)建函數(shù)其實(shí)并沒(méi)有自己的實(shí)現(xiàn)源碼。

內(nèi)建函數(shù)僅僅是一個(gè)標(biāo)識(shí)符,在Go源碼編譯期間,Go編譯器遇到內(nèi)建函數(shù)標(biāo)識(shí)符時(shí)會(huì)將其替換為若干runtime的調(diào)用,我們還以append函數(shù)為例,我們輸出下面代碼的匯編代碼(Go 1.14):

// append.go package mainimport "fmt"func main() {var s = []int{5, 6}s = append(s, 7, 8)fmt.Println(s) }$go tool compile -S append.go > append.s

匯編節(jié)選如下(append.s):

"".main STEXT size=277 args=0x0 locals=0x580x0000 00000 (xxx.go:5) TEXT "".main(SB), ABIInternal, $88-00x0000 00000 (xxx.go:5) MOVQ (TLS), CX0x0009 00009 (xxx.go:5) CMPQ SP, 16(CX)0x000d 00013 (xxx.go:5) PCDATA $0, $-20x000d 00013 (xxx.go:5) JLS 2670x0013 00019 (xxx.go:5) PCDATA $0, $-10x0013 00019 (xxx.go:5) SUBQ $88, SP0x0017 00023 (xxx.go:5) MOVQ BP, 80(SP)0x001c 00028 (xxx.go:5) LEAQ 80(SP), BP0x0021 00033 (xxx.go:5) PCDATA $0, $-20x0021 00033 (xxx.go:5) PCDATA $1, $-20x0021 00033 (xxx.go:5) FUNCDATA $0, gclocals·69c1753bd5f81501d95132d08af04464(SB)0x0021 00033 (xxx.go:5) FUNCDATA $1, gclocals·568470801006e5c0dc3947ea998fe279(SB)0x0021 00033 (xxx.go:5) FUNCDATA $2, gclocals·bfec7e55b3f043d1941c093912808913(SB)0x0021 00033 (xxx.go:5) FUNCDATA $3, "".main.stkobj(SB)0x0021 00033 (xxx.go:6) PCDATA $0, $10x0021 00033 (xxx.go:6) PCDATA $1, $00x0021 00033 (xxx.go:6) LEAQ type.[2]int(SB), AX0x0028 00040 (xxx.go:6) PCDATA $0, $00x0028 00040 (xxx.go:6) MOVQ AX, (SP)0x002c 00044 (xxx.go:6) CALL runtime.newobject(SB)0x0031 00049 (xxx.go:6) PCDATA $0, $10x0031 00049 (xxx.go:6) MOVQ 8(SP), AX0x0036 00054 (xxx.go:6) MOVQ $5, (AX)0x003d 00061 (xxx.go:6) MOVQ $6, 8(AX)0x0045 00069 (xxx.go:7) PCDATA $0, $20x0045 00069 (xxx.go:7) LEAQ type.int(SB), CX0x004c 00076 (xxx.go:7) PCDATA $0, $10x004c 00076 (xxx.go:7) MOVQ CX, (SP)0x0050 00080 (xxx.go:7) PCDATA $0, $00x0050 00080 (xxx.go:7) MOVQ AX, 8(SP)0x0055 00085 (xxx.go:7) MOVQ $2, 16(SP)0x005e 00094 (xxx.go:7) MOVQ $2, 24(SP)0x0067 00103 (xxx.go:7) MOVQ $4, 32(SP)0x0070 00112 (xxx.go:7) CALL runtime.growslice(SB)0x0075 00117 (xxx.go:7) PCDATA $0, $10x0075 00117 (xxx.go:7) MOVQ 40(SP), AX0x007a 00122 (xxx.go:7) MOVQ 48(SP), CX0x007f 00127 (xxx.go:7) MOVQ 56(SP), DX0x0084 00132 (xxx.go:7) MOVQ $7, 16(AX)0x008c 00140 (xxx.go:7) MOVQ $8, 24(AX)0x0094 00148 (xxx.go:8) PCDATA $0, $00x0094 00148 (xxx.go:8) MOVQ AX, (SP)0x0098 00152 (xxx.go:7) LEAQ 2(CX), AX0x009c 00156 (xxx.go:8) MOVQ AX, 8(SP)0x00a1 00161 (xxx.go:8) MOVQ DX, 16(SP)0x00a6 00166 (xxx.go:8) CALL runtime.convTslice(SB)... ...

我們可以看到:append并沒(méi)有以獨(dú)立的身份出現(xiàn)在CALL匯編指令的后面,而是被換成:runtime.growslice、runtime.convTslice以及相關(guān)匯編指令了。


Go技術(shù)專欄“改善Go語(yǔ)?編程質(zhì)量的50個(gè)有效實(shí)踐”主要滿足廣大gopher關(guān)于Go語(yǔ)言進(jìn)階的需求,圍繞如何寫出地道且高質(zhì)量Go代碼給出50條有效實(shí)踐建議,歡迎大家訂閱!

Gopher Daily(Gopher每日新聞)歸檔倉(cāng)庫(kù) - https://github.com/bigwhite/gopherdaily

我的聯(lián)系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公眾號(hào):iamtonybai
  • 博客:http://tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知識(shí)星球:https://public.zsxq.com/groups/51284458844544

總結(jié)

以上是生活随笔為你收集整理的slice 转byte go_一文告诉你神奇的Go内建函数源码在哪里的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。