Go: Variadic func changes []byte(s) cap

Created on 20 Apr 2018  路  7Comments  路  Source: golang/go

What version of Go are you using (go version)?

Go 1.10.1

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

darwin/amd64

What did you do?

When you call a variadic func with a byte slice, calling cap is creating different results.

x := []byte("a")

// without this, Println prints 32 32
func(a ...[]byte) {}(x)

fmt.Println(cap(x), cap([]byte("a"))) // 8 32

https://play.golang.org/p/ZcrsUNAbPZr

What did you expect to see?

32 32

What did you see instead?

8 32

FrozenDueToAge

Most helpful comment

This is an implementation detail. You're seeing differences in how the compiler chooses to implement things.

The language doesn't guarantee the the capacity on a conversion from a string.

See #24163 and #24204.

For now, if the capacity is important for your application, use make and set the capacity explicitly.

All 7 comments

This is an implementation detail. You're seeing differences in how the compiler chooses to implement things.

The language doesn't guarantee the the capacity on a conversion from a string.

See #24163 and #24204.

For now, if the capacity is important for your application, use make and set the capacity explicitly.

Thanks @bradfitz I just found it and wanted to let you know. It's not that I was using this in my application, I was just experimenting with it because of curiosity.

Do you know which part of the implementation changes the cap of the passed [][]byte?

If the backing array for the slice is allocated on the heap, it gets its capacity by rounding up to the next object size, in this case 8.
If the backing array for the slice is allocated on the stack, it gets its capacity from the temporary buffer we allocate on the stack, which has capacity 32.
So the difference in your two cases is whether escape analysis decides to allocate the backing array on the heap or the stack.
See src/runtime/string.go:stringtoslicebyte and friends.

@randall77 That's great, you've explained all in detail! I was looking for its assembly output and I was suspecting of stringtoslicebyte, tmpBuf, and rawbyteslice etc. Thanks for validating it!

For clarity, I think that the spec might say something about this: "Capacity of a slice is implementation specific when it's not specified explicitly by a make call.".

@inancgumus, that's what #24163 is about.

Ah OK, sorry, I read the whole conversation now. Thank you.

Was this page helpful?
0 / 5 - 0 ratings