Where declarations are allowed

June 20, 2023

First, a big thanks to everyone who showed up for yesterday’s first Boldly Go Live stream. We had some audio problems, which I promise to fix before the next one. But otherwise it was a success, with some great discussion. You can catch the replay if you missed it.


Here we are at the formal description of declaration syntax.

Declarations and scope

Declaration   = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl  = Declaration | FunctionDecl | MethodDecl .

The interesting thing to notice here is that there are two types of declarations. The simple Declaration, then the TopLevelDecl, which is a superset of the former.

In simple terms, this just means that “normal” declarations, those for constants, types, and variables, can go anywhere, while the top-level declarations are restricted to the, well, “top-level”, or in other words, they must go directly into the file block.

Let’s illustrate:

package main

// Top-level declarations, all valid
const pi = 3.1415926535859  // Someone check my memory on this
type radius float64
var pieVolume = radius(9) * pi

// This is a declaration, too
func main() {
  // These declarations are allowed within a function, too
  const filling = "lemon"
  type topping string
  var meringue = topping("meringue")

  // But these are invalid, because they are only allowed at the top level, not
  // within a function defintion.
  func slice(count int) {
    fmt.Printf("We now have %v slices of %v %v pie", count, filling, meringue)
  }

  func (t topping) color() string {
    switch topping {
      case "meringue":
        return "white"
    }
  }
}

// Diameter returns the diamter of a circle with radius r.
func (r radius) Diameter() float64 {
  return r * 2
}

Other invalid declaration placements would be those for functions or methods within a var, type, or constant block, such as:

var {
  x = 1
  // func() cannot be declared within any other block
  func() y {}
}

Quotes from The Go Programming Language Specification Version of December 15, 2022


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


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.


The universe and package blocks

Let’s now dive into the specific scoping rules in Go. There are 8 rules here, and we’ll take one or two per day… Declarations and scope … Go is lexically scoped using blocks: The scope of a predeclared identifier is the universe block. The “universe block”, which encompasses all Go source text, only contains the predeclared identifiers defined in the specification. Specifically, these identifiers are the names of predeclared types, the constants true, false, and iota, the zero value nil, and the built-in functions.


Declaring variable types

Today I’ll be love coding again. I hope you can join me! I’ll be working on the backlog for my open-source CouchDB SDK, https://kivik.io/. First some light refactoring, then adding a long-missing feature. Join me to see how many mistakes a senior Go dev makes while coding. We ended last week with a look at variable declarations. Today we continue that, with a look at how a variable’s type is determined.

Get daily content like this in your inbox!

Subscribe