In Go, what does `[32]byte(b)` do when `b` is a `[]byte` of length 17?
answer
- the array length is fixed, the slice's is not
- which of the two lengths can the compiler see
- it is checked against len, not cap
- too short means a run-time failure
basics
~20 sIt panics at run time. Converting a slice to an array is a length-checked copy: the array's length must be no greater than the slice's length, and 17 is short of 32, so the conversion fails with a run-time panic rather than a compile error.
solid answer
~40 s`[32]byte(b)` converts the slice `b` to an array value, copying 32 bytes out of it. The check is on `len(b)`, not `cap(b)`, and it happens at run time because the compiler cannot know a slice's length — so with `len(b) == 17` the program panics, and the panic message names both the slice length and the array length. The pointer form `(*[32]byte)(b)` panics under the same condition, but on success it aliases `b`'s storage instead of copying it. Going the other way, `arr[:]` slices an array, and the array must be addressable, which is why `sha256.Sum256(data)[:]` does not compile and you assign the digest to a variable first. If short input is possible, check the length yourself, or fill the array with `io.ReadFull` into `arr[:]` rather than converting a possibly-short read.
code
go · 5 linesb := []byte{1, 2, 3}
_ = [3]byte(b) // ok: copies the three bytes
_ = [2]byte(b) // ok: copies the first two bytes
_ = [4]byte(b) // panics: the slice is shorter than the array
_ = (*[3]byte)(b) // ok: a pointer to b's storage, no copygo deeper
Know that the two directions exist at all: arr[:] gives you a slice over an array, and a slice can be converted back to a fixed-size array. Remember that the second one can fail at run time.
Explain why the check is at run time rather than compile time, that it uses len and not cap, and how the value conversion differs from the array-pointer conversion in whether it copies or aliases.
Tie it to a real failure: a short read converted straight into a fixed-size array panics intermittently and takes the process down. Reach for io.ReadFull or an explicit length check on any input you do not control.
Decide the convention for your codebase: whether fixed-size input is a type-level guarantee at package boundaries or a validated error path, and make sure the panic can never be reachable from untrusted input.
## Converting between arrays and slices, in both directions Go lets you move between a fixed-size array and a slice explicitly, and each direction has one rule worth memorising. ### Array to slice: `arr[:]`, and addressability Given a variable `var arr [32]byte`, the slice expression `arr[:]` produces a `[]byte` of length 32 and capacity 32 whose elements *are* `arr`'s elements. Nothing is copied, and a later write through the slice changes the array. The one restriction is that the array being sliced must be **addressable** — roughly, it must be something you could take the address of. A variable is; a value returned straight from a function call is not. That is the reason this fails to compile: ```go h := sha256.Sum256(data)[:] // invalid: the returned [32]byte is not addressable ``` and the reason the idiomatic fix is a temporary variable: ```go sum := sha256.Sum256(data) h := sum[:] ``` ### Slice to array: a length-checked copy Go also converts the other way. `[32]byte(b)` yields an array **value** containing a copy of the first 32 elements of `b`. Two things about the check: - It compares the array length against `len(b)`, not `cap(b)`. A slice with capacity 64 but length 17 still fails. - It is a run-time check. The compiler knows the array length from the type but cannot know the slice's length, so a too-short slice is a panic, not a compile error. The panic message reports both lengths, which makes it easy to read off a stack trace. A conversion where the array length is smaller than the slice length is fine — `[2]byte(b)` on a length-17 slice takes the first two bytes. And converting any slice, including a nil one, to `[0]T` is legal because zero elements are always available. ### The pointer form aliases instead of copying `(*[32]byte)(b)` converts the slice to a pointer to an array occupying the same memory. The length rule is identical — a slice shorter than 32 panics — but the result shares storage with `b`, so writing `(*[32]byte)(b)[0] = 1` changes `b[0]`. Use the value form when you want an independent copy with the size fixed in the type; use the pointer form when you want to view an existing buffer as a fixed-size array without copying. ### Where the panic actually comes from in practice The common source is a short read. A daemon that reads fixed-size frames from a device or a stream will write into a `[]byte` and convert: ```go buf := make([]byte, 32) n, err := r.Read(buf) _ = err frame := [32]byte(buf[:n]) // panics whenever n < 32 ``` `io.Reader.Read` is allowed to return fewer bytes than the buffer holds without that being an error, so this panics intermittently under load or on a slow link — the worst kind of bug to find in production. The fix is `io.ReadFull(r, buf)`, which returns an error rather than a short buffer, and then converting the full slice. If short input is a legitimate case, compare `len(b)` against the array length yourself and return an error. ### Reading the stack trace When it does fire, the panic is a run-time error whose message names both lengths, and the top frame of the goroutine's stack trace is the line holding the conversion. There is no wrapping and no recovery inside the runtime: an unrecovered panic in any goroutine takes the whole process down, so the conversion belongs behind an explicit length check in any code that touches untrusted or streamed input. ### Before this conversion existed Older Go had no direct slice-to-array conversion; you declared the array and copied into it: ```go var arr [32]byte if copy(arr[:], b) != len(arr) { // b was too short } ``` `copy` returns the number of elements copied, which is the minimum of the two lengths, so this is the check-and-copy version of the same operation and is still a perfectly good way to write it when you want an error instead of a panic.
- Does `[32]byte(b)` share memory with `b`?No. The value form copies 32 bytes into a fresh array, so later writes to `b` do not show up in the array and vice versa. The pointer form `(*[32]byte)(b)` is the aliasing one: it produces a `*[32]byte` over `b`'s own storage, so writes through it are visible in `b`.
- Why does `sha256.Sum256(data)[:]` fail to compile?`Sum256` returns a `[32]byte` value, and slicing an array requires an addressable operand. A function's return value is not addressable, so there is nothing to take a slice over. Assign it first — `sum := sha256.Sum256(data)` then `sum[:]` — which also makes the lifetime of the array you are aliasing explicit.
- How would you convert a possibly-short slice without risking a panic?Check the length yourself and return an error, or use `copy(arr[:], b)` and compare its result against `len(arr)` — `copy` moves the minimum of the two lengths and never panics. When the bytes come from a stream, `io.ReadFull` is the right primitive: it fills the buffer or reports `io.ErrUnexpectedEOF`.
saying these in an interview costs you the question
- Expects a compile error rather than a run-time panic
- Thinks a too-short slice is zero-padded into the array
- Says the conversion checks cap rather than len
- Believes the value conversion aliases the slice's memory
- Converts the result of a Read call without checking n