群里看到的一道题,大家帮忙分析分析。

package main

import (
    "fmt"
)

func main() {
    s := []byte("")
    s1 := append(s, 'a')

    s2 := append(s, 'b')

    fmt.Print(string(s1), string(s2))

}

输出是:
ab
aa
bb
abab

用dlv调试下:


Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x49c22b for main.main() ./t1.go:7
(dlv) continue
> main.main() ./t1.go:7 (hits goroutine(1):1 total:1) (PC: 0x49c22b)
     2:
     3: import (
     4:         "fmt"
     5: )
     6:
=>   7: func main() {
     8:         s := []byte("")
     9:         s1 := append(s, 'a')
    10:
    11:         s2 := append(s, 'b')
    12:
(dlv) print s
Command failed: could not find symbol value for s
(dlv) next
> main.main() ./t1.go:8 (PC: 0x49c242)
     3: import (
     4:         "fmt"
     5: )
     6:
     7: func main() {
=>   8:         s := []byte("")
     9:         s1 := append(s, 'a')
    10:
    11:         s2 := append(s, 'b')
    12:
    13:         fmt.Print(string(s1), string(s2))
(dlv) print s
[]uint8 len: 0, cap: 842350772072, []
(dlv) next
> main.main() ./t1.go:9 (PC: 0x49c27f)
     4:         "fmt"
     5: )
     6:
     7: func main() {
     8:         s := []byte("")
=>   9:         s1 := append(s, 'a')
    10:
    11:         s2 := append(s, 'b')
    12:
    13:         fmt.Print(string(s1), string(s2))
    14:
(dlv) print s
[]uint8 len: 0, cap: 32, []
(dlv) next
> main.main() ./t1.go:11 (PC: 0x49c2ac)
     6:
     7: func main() {
     8:         s := []byte("")
     9:         s1 := append(s, 'a')
    10:
=>  11:         s2 := append(s, 'b')
    12:
    13:         fmt.Print(string(s1), string(s2))
    14:
    15: }
(dlv) print s
[]uint8 len: 0, cap: 32, []
(dlv) print s1
[]uint8 len: 1, cap: 32, [97]
(dlv) next
> main.main() ./t1.go:13 (PC: 0x49c2f1)
     8:         s := []byte("")
     9:         s1 := append(s, 'a')
    10:
    11:         s2 := append(s, 'b')
    12:
=>  13:         fmt.Print(string(s1), string(s2))
    14:
    15: }
(dlv) print s
[]uint8 len: 0, cap: 32, []
(dlv) print s1
[]uint8 len: 1, cap: 32, [98]
(dlv) print s2
[]uint8 len: 1, cap: 32, [98]
(dlv)

最后的输出结果出乎为什么是bb呢?

已邀请:

h12 - https://h12.io/about

赞同来自:

因为[]byte("")的capacity是32,所以append判断能装下的情况不会重新分配,导致第二次append会覆盖第一次的结果,且s1和s2指向同一个地址:

package main

import (
    "fmt"
)

func main() {
    s := []byte("")
    fmt.Println(len(s), cap(s))
}

h12 - https://h12.io/about

赞同来自:

这道题不严谨,因为[]byte("")的cap到底应该是多少,属于未定义行为,允许编译器根据上下文做优化和调整。所以不用纠结题目本身。

如果我们显式指定s的cap,需要关注的是append得到的slice底层对应的地址,以及每个slice的len和cap:

package main

import (
    "fmt"
)

func main() {
    s := make([]byte, 0, 32)
    fmt.Println(len(s), cap(s))

    s1 := append(s, 'a', 'c')
    s2 := append(s, 'b')

    fmt.Printf("len=%d, cap=%d, addr=%p, val=%s\n", len(s1), cap(s1), &s1[0], string(s1))
    fmt.Printf("len=%d, cap=%d, addr=%p, val=%s\n", len(s2), cap(s2), &s2[0], string(s2))
}

chai2010 - 数盲患者

赞同来自:

这是一个烂题

tt_0411 - Less is better.

赞同来自:

这个是考察slice内部实现原理, 其中的关键点也确实是一个容易踩坑的地方, 导致的bug也比较隐蔽. 另外, 答案也可能是 aa.

sheepbao - https://sheepbao.github.io 爱go,爱编程,领域网络开发,流媒体、分布式、网络加速

赞同来自:

https://sheepbao.github.io/post/understand_golang_slice/ 可以看看我这篇博客,s1和s2共用一个内存地址,而导致s2更改了s1的内容。

hej8875

赞同来自:

package main

import "fmt"

func main() {
s := []byte("")
s1 := append(s, 'a')
s2 := append(s, 'b')

//fmt.Println(s1, "==========", s2)
fmt.Println(string(s1), "==========", string(s2))
}

出现个让我理解不了的现象, 注释时候输出是 b ========== b 取消注释输出是 [97] ========== [98] a ========== b

要回复问题请先登录注册