Struct literals

Composite literals … For struct literals the following rules apply: A key must be a field name declared in the struct type. Probably self-evident. You can’t use field names that aren’t defined in the struct type. An element list that does not contain any keys must list an element for each struct field in the order in which the fields are declared. If any element has a key, every element must have a key.


Duplicate map keys

It’s Monday again. That means I’ll be live-coding again! I hope you can join me. Composite literals … For map literals, all elements must have a key. It is an error to specify multiple elements with the same field name or constant key value. For non-constant map keys, see the section on evaluation order. I expect we can all agree this makes sense. Keys in a map literal must be unique.


Composite keys

This week’s episode of the Cup o’ Go podcast is out! Keep up with the Go community in just 15 minutes per week! Have a listen! Composite literals … The key is interpreted as a field name for struct literals, an index for array and slice literals, and a key for map literals. For map literals, all elements must have a key. If you’ve written any Go code, you probably already know about keys in maps:


Assignability of composite components

Composite literals … The types of the elements and keys must be [assignable(https://go.dev/ref/spec#Assignability)] to the respective field, element, and key types of type T; there is no additional conversion. This shouldn’t be surprising, but let’s examine the implications just the same. type myStr string s := myStr("my string") var x = map[int]string{ 3: "oink", // Valid, untyped numeric constant 3 is assignable to an int. int(4): "quack", // Valid, int(4) is of type int int64(12): "moo", // Invalid, int64(12) is not converted to int 8: s, // Invalid, type myStr is type string 9: string(s), // Valid; explicit conversion to type string } Quotes from The Go Programming Language Specification Version of August 2, 2023

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.


Composite literals

Earlier this year, near the beginning of this series on the Go spec, we went through literal representations of all of the basic types in Go: ints, strings, etc. If this were an Intro to Go style book, the very next section would have been on composite literals. But it’s not. So we had to wait nearly 6 months to get to that topic… But here we are, at long last!


Operator constraints

Last week I inconspicuously skipped over one sentence in the spec, the last sentence in the section on Operands, and jumped straight ahead to the section on Qualified identifiers. This is because the sentence didn’t make immediate sense to me, and I needed time to research it. I’ve done that research now, so, let’s jump back and cover the missed territory. Operands … Implementation restriction: A compiler need not report an error if an operand’s type is a type parameter with an empty type set.


Qualified identifiers

One of the features of Go I found most discomforting when I started using the language, was that of qualifiers. Depending on which previous languages you may have experience with, you may find them perfectly natural, or entirely strange. Let’s see what they are… Qualified identifiers A qualified identifier is an identifier qualified with a package name prefix. Both the package name and the identifier must not be blank. QualifiedIdent = PackageName ".


Blank operands

Don’t you just love the blank identifier? I sure do! And it the blank identifier can be an operand, too! But with a limitation: Operands … The blank identifier may appear as an operand only on the left-hand side of an assignment statement. So this means that _ = 3 is valid, but var x = _ Is not. And I hope it’s pretty obvious why that is the case. What would the value of x be in such an example?


Generic functions as operands

Operands … An operand name denoting a generic function may be followed by a list of type arguments; the resulting operand is an instantiated function. So first off, recall that an operand may be a function literal: var x = func() { /* ... */ } Or a variable that represents a function: var F = func() { /* ... */ } var f = F // <--- `F` is a variable that represents a function Or another expression that evaluates to a function:


Operands

I’ll be live coding again today! I hope you can join me! I’ll be continuing where I left off, working on a new feature for my open-source CouchDB SDK, https://kivik.io/. Join me to see how many mistakes a senior Go dev makes while coding. To kick off our dissection of expressions, we’ll look at the term “operand”. You may recall from your studies of algebra that an operand is the “object upon which an operator acts.


Expressions

There are a number of terms that get thrown around, often semi-interchangeably by the less initiated (such as myself). “Declaration”, “definition”, “statement”, … and today’s topic “expressions”, just to name a few. But, at least within the context of the Go spec, most such terms have very specific meanings. Expressions An expression specifies the computation of a value by applying operators and functions to operands. So: type foo int and var foo int are not an expressions.