A declaration binds a non-blank identifier to a constant, type, type parameter, variable, function, label or package (spec: Declarations and scope). Every identifier in a program must be declared, and none may be declared twice in the same block. This page covers blocks, scope, and the constant, variable and type declarations. Functions and methods have their own page.
Declaration = ConstDecl | TypeDecl | VarDecl .
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
Blocks
Block = "{" StatementList "}" .
StatementList = { Statement ";" } .
A block is a possibly empty sequence of declarations and statements in matching braces. There are also implicit blocks (spec: Blocks):
- The universe block holds all Go source text.
- Each package has a package block with all its source text.
- Each file has a file block with all its source text.
- Each
if,forandswitchstatement is in its own implicit block. - Each clause in a
switchorselectstatement is an implicit block.
Scope
Go is lexically scoped using blocks. The scope of an identifier is the extent of source in which it denotes the declared thing.
| Identifier | Scope |
|---|---|
| Predeclared identifier | The universe block |
| Constant, type, variable or function (not method) at top level | The package block |
| Package name of an import | The file block of the importing file |
| Method receiver, function parameter or result variable | The function body |
| Type parameter of a function, or declared by a method receiver | From after the function name to the end of the function body |
| Type parameter of a type | From after the type name to the end of the TypeSpec |
| Constant or variable declared inside a function | From the end of the ConstSpec, VarSpec or ShortVarDecl to the end of the innermost block |
| Type declared inside a function | From the identifier in the TypeSpec to the end of the innermost block |
- An identifier may be redeclared in an inner block. While the inner declaration is in scope, it hides the outer one.
- Top-level declarations are visible throughout the package, regardless of order, in all its files. An identifier may not be declared in both the file block and the package block.
- The scope of a local variable starts after its declaration, so
x := x + 1in an inner block uses the outerxon the right. The scope of a local type starts at its name, so a local type can refer to itself. initmay be used in the package block only to declare init functions, and introduces no binding (see Packages and modules).
x := 1
if x := 2; x > 0 { // a new x, in the if statement's implicit block
fmt.Println(x) // prints 2
}
fmt.Println(x) // prints 1
for i := 0; i < 3; i++ {
i := i * 10 // a new i in the body; the loop's i is untouched
fmt.Println(i)
}
Label scopes
Labels are declared by labeled statements and used by break,
continue and goto. It is an error to define a label that is
never used. Labels are not block-scoped and do not conflict with other identifiers. The
scope of a label is the body of the function that declares it, excluding nested
functions. See Statements.
The blank identifier
The blank identifier _ is an anonymous placeholder. It may be used in a
declaration, as an operand on the left of an assignment, and in other places where a name
is required, but it binds nothing.
var _ io.Reader = (*File)(nil) // compile-time check that *File implements io.Reader
_, err := os.Open(name) // ignore the first result
import _ "net/http/pprof" // import only for its side effects
Predeclared identifiers
These are implicitly declared in the universe block (spec: Predeclared identifiers). They are not keywords and can be redeclared, though a declaration that hides one can make code confusing.
| Kind | Identifiers |
|---|---|
| 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 clear close complex copy delete imag len make max min new panic print println real recover |
The functions are described on the Built-ins page.
Exported identifiers
An identifier is exported if its first character is a Unicode upper-case letter (category Lu) and it is declared in the package block, or is a field or method name. All other identifiers are not exported. Only exported identifiers can be reached from another package. Two identifiers are different if they are spelled differently, or if they are in different packages and not exported (spec: Uniqueness of identifiers).
Constants
Constants are boolean, rune, integer, floating-point, complex or string. A constant may
be written as a literal, a constant identifier, a constant expression, a conversion that
yields a constant, or a call to certain built-in functions such as min,
max, len or unsafe.Sizeof (spec: Constants).
- Numeric constants are exact values of arbitrary precision and do not overflow. There are no constants for negative zero, infinity or NaN. Implementations must hold integers with at least 256 bits.
- A constant may be typed or untyped. Literals,
true,false,iotaand many constant expressions are untyped. - An untyped constant has a default type:
bool,rune,int,float64,complex128orstring, used when a typed value is needed. - A typed constant must be representable in its type:
uint(-1)andint(3.14)are errors. An untyped constant is not bound until used, soconst Huge = 1 << 100is valid. See Constant expressions.
Constant declarations
ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .
The identifiers and expressions must match in number. With a type, the values must be assignable to it, and it must not be a type parameter. Without a type, constants take the types of the expressions and stay untyped if the expressions are. Inside a parenthesised list, the expression list may be omitted from any but the first ConstSpec: the empty list repeats the previous one, with its type.
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // untyped floating-point constant
const (
size int64 = 1024
eof = -1 // untyped integer constant
)
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo"
const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Iota
Inside a constant declaration, iota is the index of the ConstSpec within
that declaration, starting at zero, and an untyped integer constant. Multiple uses of
iota in one ConstSpec all have the same value. Combined with implicit
repetition it produces sequences.
const (
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota == 0)
b = 1 << iota // b == 2 (iota == 1)
c = 3 // c == 3 (iota == 2, unused)
d = 1 << iota // d == 8 (iota == 3)
)
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0)
bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1)
_, _ // (iota == 2, unused)
bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3)
)
const x = iota // x == 0: iota restarts at each const declaration
const y = iota // y == 0
A typical enumeration gives iota a named type:
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
)
Monday repeats Weekday = iota with iota at 1Variable declarations
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (
u, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1)
var _, found = entries[name] // map lookup; only interested in "found"
- With a list of expressions, the variables are initialised by the assignment rules. Without one, each gets its zero value.
- Without a type, each variable takes the type of its initial value. An untyped constant
takes its default type first; an untyped boolean value becomes
bool.nilcannot initialise a variable with no type. - A compiler may reject a variable declared in a function body and never used. The
gccompiler does.
Short variable declarations
ShortVarDecl = IdentifierList ":=" ExpressionList .
A short variable declaration is shorthand for a variable declaration with initial values and no types. It may appear only inside functions. It can redeclare a variable that was declared earlier in the same block (or the parameter list, if the block is the function body) with the same type, provided at least one non-blank variable on the left is new. Redeclaration assigns to the original variable; it does not make a new one. The non-blank names on the left must be unique.
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w, _ := os.Pipe()
field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset) // redeclares offset
x, y, x := 1, 2, 3 // illegal: x repeated on left side of :=
Short declarations are also used in the headers of if, for and
switch statements to declare variables local to them.
Type declarations
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
TypeSpec = AliasDecl | TypeDef .
Alias declarations
AliasDecl = identifier [ TypeParameters ] "=" Type .
An alias declaration (Go 1.9) binds a name to an existing type. The name is another spelling of that type, and the two are identical. An alias may declare type parameters (Go 1.24), in which case it is a generic alias that must be instantiated when used.
type (
nodeList = []*Node // nodeList and []*Node are identical types
Polar = polar // Polar and polar denote identical types
)
type set[P comparable] = map[P]bool
In an alias declaration the given type cannot be a type parameter declared in the same declaration.
Type definitions
TypeDef = identifier [ TypeParameters ] Type .
A type definition creates a new, distinct defined type with the same underlying type and operations as the given type. It does not inherit methods bound to the given type, but the method set of an interface type, or of the elements of a composite type, is unchanged. A defined type can have its own methods.
type (
Point struct{ x, y float64 } // Point and struct{ x, y float64 } are different types
polar Point // polar and Point denote different types
)
type TimeZone int
const (
EST TimeZone = -(5 + iota)
CST
MST
PST
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}
// NewMutex has the same composition as Mutex but its method set is empty.
type NewMutex Mutex
// The method set of PtrMutex's underlying type *Mutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex
// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
type PrintableMutex struct {
Mutex
}
A type definition may declare type parameters, making a generic type. The given type may not be a type parameter, whether declared in the same definition or by an enclosing function.