
1 min read
Uniqueness of identifiers
Uniqueness of identifiers Given a set of identifiers, an identifier is called unique if it is different from every other in the set. Two identifiers are different if they are spelled differently, or if they appear in different packages and are not exported. Otherwise, they are the same. This is pretty simple stuff, but it’s obviously worth being explicit. foo and bar are obviously different identifiers. Further, a in package foo, and a in package bar are different identifiers, because although they are spelled the same, they are not exported, and are in different packages.

2 min read
Exported identifiers
Exported identifiers An identifier may be exported to permit access to it from another package. An identifier is exported if both: the first character of the identifier’s name is a Unicode uppercase letter (Unicode character category Lu); and the identifier is declared in the package block or it is a field name or method name. All other identifiers are not exported. The main surprising thing to take out of this section is that an exported field or method may be accessible outside of the package even if the type it’s defined on is not!

1 min read
Predeclared identifiers
Predeclared identifiers The following identifiers are implicitly declared in the universe block: Types: any bool byte comparable complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr Constants: true false iota Zero value: nil Functions: append cap close complex copy delete imag len make new panic print println real recover Perhaps confusingly, any of these can be shadowed. That is, you can bind these names to your own variables, constants, functions, etc.

1 min read
Blank identifier
Blank identifier The blank identifier is represented by the underscore character _. It serves as an anonymous placeholder instead of a regular (non-blank) identifier and has special meaning in declarations, as an operand, and in assignment statements. Ah, the blank identifier! We’ve talked about it in a few contexts already. Namely, struct field names, as well as binding variables. But it can be used in many places… Including a few surprising places, where it never serves a purpose.
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.

3 min read
Label scopes
Last Monday we had a great time on the Boldly Go: Live livestream, as we built a simple linter by following an online tutorial. For the next live stream, I intend to build a real linter, to solve some real world problems on one of my open source projects. Normally, I would do that today, but my office is undergoing some serious rennovation (three walls and the ceiling are being removed and replaced), so I don’t have anywhere to record from.

3 min read
Scope of the package clause
If you’ve written any code in Go, you’ve seen the package clause: package main So what is the scope of this clause? Declarations and scope … The package clause is not a declaration; the package name does not appear in any scope. Its purpose is to identify the files belonging to the same package and to specify the default package name for import declarations. If it has no scope, why is it needed?

1 min read
Shadowing
The concept of shadowing should be familiar to many readers. But here we see how Go defines it… Declarations and scope … An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration. Notice that shadowing is not limited to variables. You can shadow function names, types, constants, or variables.

1 min read
Scope within functions
Today we’re rounding out the list of scoping rules, with two more: Declarations and scope … The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block. The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.

1 min read
Scope of type parameters
If you missed it, we had a great Boldly Go: Live livestream yesterday. I built a basic linter from scratch. It was easier than I expected, and we all learned a few things. It’s not too late to catch the replay if you’re interested! Type parameters are what power generics, and they have two specific scoping rules: Declarations and scope … The scope of an identifier denoting a type parameter of a function or declared by a method receiver begins after the name of the function and ends at the end of the function body.

1 min read
Scope of the function block
Join me later today for my second Boldly Go Live stream! Declarations and scope … The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body. This is pretty intuitive. When declaring a function or method: func sum(a, b int) (result int) { /* ... */ } func (a Animal) Speak() { /* ... */ } The scope of any variables mentioned in the function signature (method receiver, function parameter, or result variables), are the function body.