2 min read
Channel synchronization
I’ve made the case that channels are just data types, and non-magical. So why should we care about channels, rather than just using some sort of slice, array, or custom first-in-first-out queue? The reason is that channels provide us certain guarantees with regard to synchronization. The spec explains: Channel types … A single channel may be used in send statements, receive operations, and calls to the built-in functions cap and len by any number of goroutines without further synchronization.
1 min read
Closing channels
Channel types … A channel may be closed with the built-in function close. The multi-valued assignment form of the receive operator reports whether a received value was sent before the channel was closed. Closing a channel is a simple matter of using the built-in close function: // ch must be of type `chan T` or `chan<- T`. A receive-only channel (`<-chan T`) cannot be closed. close(ch) Calling close on a channel takes immediate effect, and prevents further values from being written to the channel (any items already in the channel may still be read).
2 min read
Creating channels
Channel types … A new, initialized channel value can be made using the built-in function make, which takes the channel type and an optional capacity as arguments: make(chan int, 100) Here we have the semi-magical make built-in function again. We’ve already seen it for use with arrays and slices. Consider this yet another clue that a channel is just another type, similar to array and slice, in that it “just” holds a bunch of values, and isn’t magical in any way.
2 min read
Directional channels
Channel types … The optional <- operator specifies the channel direction, send or receive. If a direction is given, the channel is directional, otherwise it is bidirectional. A channel may be constrained only to send or only to receive by assignment or explicit conversion. chan T // can be used to send and receive values of type T chan<- float64 // can only be used to send float64s <-chan int // can only be used to receive ints When you create a new channel, you get a bidirectional channel.
1 min read
Channel types
Channel types A channel provides a mechanism for concurrently executing functions to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil. ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType . Channels are one of the most confusing parts of Go, for many newcomers. But they don’t need to be. They’re actually quite simple. Think of a channel as an array, which can only be read from one end, and appended to the other.
2 min read
Map length and capacity
Maps, like arrays and slices, have length. Map types … The number of map elements is called its length. For a map m, it can be discovered using the built-in function len and may change during execution. … This should be straight forward, but let’s consider a couple examples for good measure: x := map[string]int{"a": 1, "b": 2, "c": 3} fmt.Println(len(x)) // 3 var y map[string]float64 fmt.Println(len(y)) // 0 And somewhat deceptively, their capacity can also be set, or at least hinted at, but not read.
2 min read
Using maps
Today I’m jumping around a bit, for the sake of coherence. Map types … [Map] elements may be added during execution using assignments and retrieved with index expressions; they may be removed with the delete built-in function. A new, empty map value is made using the built-in function make, … Let’s summarize with examples. We’ll dive into details as the relevant portions of the spec come up. To create a map, you use the built-in function make:
Subscribe to Boldly Go: Daily
Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.
Unsure? Browse the archive.
1 min read
Map Keys
The only restriction on map keys is that they must be comparable. The spec explains: Map types … The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
1 min read
Map types
Map types A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type. The value of an uninitialized map is nil. MapType = "map" "[" KeyType "]" ElementType . KeyType = Type . Maps should be familiar to just about anyone who’s familiar with programming, by one name or another. “Hashmaps,” “dictionaries,” “associative arrays,” or even simply “objects” in JavaScript or JSON.
2 min read
Implementing an interface
It feels like it’s been a month since we started on interfaces. Today we’re covering the final section on this topic! Implementing an interface A type T implements an interface I if T is not an interface and is an element of the type set of I; or T is an interface and the type set of T is a subset of the type set of I. A value of type T implements an interface if T implements the interface.
2 min read
Recursive interfaces
Check out this week’s episode of the Cup o’ Go podcast: What the ʕ◔ϖ◔ʔ? New merch, TDD book interview with Adelina Simion, and more You can probably guess Go’s rules about recursively embedding interfaces. In short: It’s not allowed. General interfaces … An interface type T may not embed a type element that is, contains, or embeds T, directly or indirectly. // illegal: Bad may not embed itself type Bad interface { Bad } // illegal: Bad1 may not embed itself using Bad2 type Bad1 interface { Bad2 } type Bad2 interface { Bad1 } // illegal: Bad3 may not embed a union containing Bad3 type Bad3 interface { ~int | ~string | Bad3 } // illegal: Bad4 may not embed an array containing Bad4 as element type type Bad4 interface { [10]Bad4 } Note however, that, an interface method may refer to the interface itself.