ProgrammingMiddle Backend Go Developer

What happens when passing values through a channel in Go: how is copying done, which types are passed by value, how can you accidentally get a race condition when passing complex structures or pointers?

Pass interviews with Hintsage AI assistant

Answer

In Go, it is possible to send values of any type through channels: int, struct, pointers, interfaces, etc.

  • Pass by value: standard types and structures (without pointers) are copied, and the receiver gets its own copy, with changes not affecting the original.
  • Race check: if a pointer is passed through the channel, both sides (sender and receiver) operate on the same area of memory — a data race is possible!
  • Complex structures with nested pointers: even if the main structure is passed by value, the nested pointers are copied as references, and a race can occur at the level of nested objects.

Code and example:

type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // the entire structure is copied p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // a pointer to the same object was sent through the channel

Trick question

If a structure is sent through the channel that contains a pointer field — will there be a race condition when modifying this field from both ends of the channel?

Answer:

  • Race is possible! The structure is copied, but the nested pointer references the same area of memory. If both sides modify the data by reference, a race condition occurs.

Example:

type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // both sender and receiver have access to x!

Examples of real bugs due to ignorance of the topic's nuances


Story

In a distributed queue, there were frequent "random" crashes and mysterious values in the task structure. It turned out that pointers to shared structures were being passed through the channel, which were simultaneously modified in several goroutines. The decision was made to change to passing copies of the data.


Story

Asynchronous message processing worked with structures that contained slices-pointers to a shared array. During parallel passing through the channel, parts of the same memory were modified from different places, leading to hidden bugs and data corruption.


Story

In a push notification service, references to objects were passed through the channel, which were then processed by goroutines. When simultaneous completion and channel closure occurred, some structures were still being modified, causing panic or data race. Switching to copying the structure before sending helped.