anonymous struct and empty struct

user2671513 picture user2671513 · Dec 27, 2013 · Viewed 30.4k times · Source

http://play.golang.org/p/vhaKi5uVmm

package main

import "fmt"

var battle = make(chan string)

func warrior(name string, done chan struct{}) {
    select {
    case opponent := <-battle:
        fmt.Printf("%s beat %s\n", name, opponent)
    case battle <- name:
        // I lost :-(
    }
    done <- struct{}{}
}

func main() {
    done := make(chan struct{})
    langs := []string{"Go", "C", "C++", "Java", "Perl", "Python"}
    for _, l := range langs { go warrior(l, done) }
    for _ = range langs { <-done }
}

[1st Question]

 done <- struct{}{}

How and Why do we need this weird-looking struct? Is it empty struct or anonymous struct? I googled it but couldn't find the right answer or documentation to explain about this.

The original source is from Andrew Gerrand's talk http://nf.wh3rd.net/10things/#10

Here

 make(chan struct{})

done is a channel of type struct{}

So I tried with

 done <- struct{}

But it is not working. Why do I need an extra brackets for this line?

 done <- struct{}{}

[2nd Question]

 for _ = range langs { <-done }

Why do I need this line? I know that this line is necessary because without this line, no output. But Why and what does this line do? And what makes it necessary in this code? I know that <-done is to receive values from the channel done and discard the received values. But why do I need to do this?

Answer

VonC picture VonC · Mar 25, 2014

Note that one interesting aspect of using struct{} for the type pushed to a channel (as opposed to int or bool), is that the size of an empty struct is... 0!

See the recent article "The empty struct" (March 2014) by Dave Cheney.

You can create as many struct{} as you want (struct{}{}) to push them to your channel: your memory won't be affected.
But you can use it for signaling between go routines, as illustrated in "Curious Channels".

finish := make(chan struct{})

As the behaviour of the close(finish) relies on signalling the close of the channel, not the value sent or received, declaring finish to be of type chan struct{} says that the channel contains no value; we’re only interested in its closed property.

And you retain all the other advantages linked to a struct:

  • you can define methods on it (that type can be a method receiver)
  • you can implement an interface (with said methods you just define on your empty struct)
  • as a singleton

in Go you can use an empty struct, and store all your data in global variables. There will only be one instance of the type, since all empty structs are interchangeable.

See for instance the global var errServerKeyExchange in the file where the empty struct rsaKeyAgreement is defined.