Hi,
neither is *always* the case. One example of where no allocation is done is when converting a []byte into a string to use as a map-index, as long as a) it is done in one expression and b) the key doesn't have to be stored (i.e. the access is read-only):
b := []byte{70,111,111}
m := make(map[string]int)
v := m[string(b)] // does not allocate
And as always, a conversion might end on the stack, if the compiler can prove that the storage doesn't have to survive the call, e.g.
x := "Hello world"
os.Stdout.Write([]byte(x)) // does not escape
(note, that in this example, it's important that `os.Stdout` is an `*os.File`, not just an `io.Writer`, so the compiler actually knows the real function that is called).
But, in general, I think you can assume that such a conversion has to allocate and I'd guess that in most cases, it needs to go on the heap. You can use `-gcflags=-m` to see if a particular conversion allocates or not.