【Golang】遇到的有趣的Go賦值問題並附帶以下不負責任的解析
阿新 • • 發佈:2020-12-23
今天在做一道題的時候發現了這麼一個有趣的題目:
func main() {
index := 1
a := []string{"f", "ff", "fff"}
index, a[index-1] = 88888, "ffff"
fmt.Println(a)
}
這個輸出是什麼呢?我第一眼看的時候感覺會輸出panic,因為下標超界,但是執行之後發現沒這麼簡單,執行結果如下
執行之後我驚了,不知道為什麼會這樣,然後我就輸出了彙編看了一下(去掉了一些多餘的彙編程式碼,我們只看賦值那行的彙編):
本篇文章基於go1.15+版本以及mac os 作業系統
//把index的值複製到DX暫存器中
0x00f2 00242 MOVQ "".index+48(SP), DX
// DX暫存器的值-1 在此能看出是先對其進行了-1
0x00f7 00247 DECQ DX
// 把DX暫存器裡的值複製autotmp_4+56這個地址上
0x00fa 00250 MOVQ DX, ""..autotmp_4+56(SP)
// 把88888賦值給index+48地址即賦值88888給index
0x00ff 00255 MOVQ $88888, "".index+ 48(SP)
// 把剛才-1了的值放在AX暫存器中
0x0108 00264 MOVQ ""..autotmp_4+56(SP), AX
// 把a就是那個陣列的偏移104個地址的值放入DX暫存器
0x010d 00269 MOVQ "".a+104(SP), DX
// 把a就是那個陣列的偏移112個地址的值放入DX暫存器
0x0112 00274 MOVQ "".a+112(SP), CX
// 比較AX暫存器和CX暫存器
0x0117 00279 CMPQ AX, CX
// 如果沒溢位就跳到293
0x011a 00282 JCS 293
// 否則
0x011c 00284 NOP
// 跳到605
0x0120 00288 JMP 605
// 邏輯移位(好像是)
0x0125 00293 SHLQ $4, AX
// 把DX的AX*1的地址給CX Ax就是被-1後的那個值存放的地方
0x0129 00297 LEAQ (DX)(AX*1), CX
0x012d 00301 LEAQ 8(CX), CX
0x0131 00305 MOVQ $4, (CX)
// 反正就是之前做了一堆複製和傳地址操作把DX的AX*1的地址給了DI
0x0138 00312 LEAQ (DX)(AX*1), DI
·····
// 把ffff這個字串放到AX暫存器內
0x014a 00330 LEAQ go.string."ffff"(SB), AX
// 從AX暫存器複製出ffff複製到DI就是要修改的陣列的那個位置
0x0151 00337 MOVQ AX, (DI)
大概就是這樣,其實最根本的原因就是
對
index-1
這個操作早於給index
賦值這個操作,並且提前將其放到了某塊地址中。所以後續的陣列下標賦值操作是根據這個放在某個地址中的index-1
的值進行的賦值。
作者對彙編不甚瞭解,如果哪裡有錯誤請大佬指正。