You would use an empty struct when you would want to save some memory. Empty structs do not take any memory for its value.

a := struct{}{}
println(unsafe.Sizeof(a))
// Output: 0

This saving is usually insignificant and is dependent on the size of the slice or a map. Although, more important use of an empty struct is to show a reader you do not need a value at all. Its purpose in most cases is mainly informational. Here are a few examples where it can be useful:

When building an object, and only being interested in a grouping of methods and no intermediary data, or when you do not plan to retain the object state. In the example below it does not make a difference whether the method is called on the same (case #1) or on two different objects (case #2):

The swap operation in Go is guaranteed from side effects. The values to be assigned are guaranteed to be stored in temporary variables before starting the actual assigning, so the order of assignment does not matter. The result of the following operation: a := 1; b := 2; a, b, a = b, a, b is still a = 2 and b = 1, without the risk of changing the value a to the new re-assigned value. This is useful to rely on in many algorithm implementations.

You can compare two structs with the == operator, as you would do with other simple types. Just make sure they do not contain any slices, maps, or functions, in which case the code will not be compiled.

For comparing byte slices, there are nice helper functions in the bytes package: bytes.Equal(), bytes.Compare(), and bytes.EqualFold(). The latter is for comparing text strings disregarding the case, which are much faster than the reflect.DeepEqual().

This is a trick question because you might think this has something to do with the member variable Quantity being set incorrectly, but actually, it will be set to 5 as expected. The real problem here, which is easy to overlook, is that the String() method that implements the fmt.Stringer() interface will not be invoked when the object orange is being printed with fmt.Println() function, because the method String() is not being defined on a value but only on a pointer:

Another possibility to implement a queue is to use buffered channels, but this is never a good idea, because:

The buffer size is determined at the channel creation and cannot be increased.

It is impossible to peek at the next queue element without retrieving it from the queue.

There is a risk of deadlock: “Novices are sometimes tempted to use buffered channels within a single goroutine as a queue, lured by their pleasingly simple syntax, but this is a mistake. Channels are deeply connected to goroutine scheduling, and without another goroutine receiving from the channel, a sender—and perhaps the whole program—risks becoming blocked forever. If all you need is a simple queue, make one using a slice.”, Brian Kernighan.

First, it is not necessary to collect the input in the string before putting it out to standard output. This example is slightly contrived.

Second, the string text is not modified with the += operator, it is created anew for every line. This is a significant difference between strings and []byte slices — strings in Go are non-modifiable. If you need to modify a string, use a []byte slice.

Most of the time, you do not need them both. You need only the GOPATH variable set pointing to the Go packages tree or trees.

GOROOT points to the root of the Go language home directory, but it is most probably already set to the directory of the current Go language installation. It is easy to check whether it is so with the go env command:

$ go env
…
GOROOT=“/home/zabb/go”
…

It is necessary to set the GOROOT variable if there are multiple Go language versions on the same system or if the Go language has been downloaded as a binary package taken from the internet or transferred from another system.

We are going to review the comment and get back to you as soon as possible.

* There is more to interviewing than tricky technical questions, so these are intended merely as a guide.
Not every “A” candidate worth hiring will be able to answer them all, nor does answering them all guarantee an “A” candidate.
At the end of the day, hiring remains an art, a science — and a lot of work.

Submit an interview question

Submitted questions and answers are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.

Our editorial staff will review it shortly. Please note that submitted questions and answers are subject to review and editing, and may or may not be selected for posting, at the sole discretion of Toptal, LLC.

Matt has worked on everything from web development in .NET and embedded development in C to low-level Windows development, rich client development in JavaScript using EmberJS, web applications in Go, and mobile applications in iOS. He is very quality-focused and gets things done efficiently. As a startup veteran, he knows how to start from nothing and build impossible things on impossible schedules.

Sergey is a professional Corona SDK and Defold developer. With a strong background in computer graphics, networking, and low level programming, he always delivers high quality code. Sergey specializes in making cross-platform products: games and apps for iOS, Android, macOS, Linux, and Windows. He also makes native plugins and extensions for both Corona SDK and Defold. Additionally Sergey often talks at various developer conferences.

Mahmud is a software developer with a knack for efficiency, scalability, and stable solutions. With years of experience working with a wide range of technologies, he is still interested in exploring, encountering, and solving new and interesting programming problems.