conn.Read() works only with make([]byte,length) and not with []byte

Hi!
So I have a program that uses sockets in GO. When I try to use the following snippet to read bytes from a connection, it does not work :

buffer := []byte{}
_, err := conn.Read(buffer)
if err != nil {
	fmt.Println(err)
	break
}

But works only when I do :

buffer := make([]byte, 2048)
_, err := conn.Read(buffer)
if err != nil {
	fmt.Println(err)
	break
}

I thought slices are dynamic in nature so allocation of memory should be handled by the system.

In this case you are supposed to tell the system how many bytes you want read by allocating a buffer of a length of your choice. This is consistent with socket APIs in other languages.

2 Likes

Imagine if it’s dynamic, and when the underlying layer requests a huge amount of memory, then you’re complaining about the underlying design issues (like reading a large file, which will load everything into memory at once), so it’s better to give control to the caller than dynamic.

dynamic just means memory is allocated to the heap on the fly during runtime instead of being fixed at compile time.

slices are dynamic but they only grow when you use append(), which tells go to pre-allocate memory for the backing array and to double the capacity. without append() the backing array wont increase in size

this []byte{} is the same as make([]byte, 0, 1)

where 0 = length and 1 = capacity.

meaning []byte{} can only store 1 byte before running out of space, but it wont automatically create the new backing array unless you use append()

note the distinction between length and capacity

make([]byte, 2048) is same as make([]byte, 2048, 2048). it creates a slice with 2048 items each initialized to 0.

on the other hand, make([]byte, 0, 2048) is an empty slice with no initialized items, but can hold append up to 2048 because memory reallocation is needed. this is what you should use for your buffer

1 Like

correction: use bytes.Buffer instead of a slice for an open-ended buffer

import ("bytes")

buffer := bytes.Buffer

_, err:= buffer.ReadFrom(stream) // stream is your connection reader
if err != nil {
    // do something
}

data := buffer.Bytes()

another way is just create a static array of fixed capacity if you already know the stream will be under a certain size.

Arrays are better than slices in this case because its memory is allocated at compile time. so the buffer space will already be there when the process runs, and the cpu wont have to spend time allocating new memory for a slice that wont grow anyway