A parameter is a named variable passed into a function. Parameter variables are used to import arguments into functions. For example: Note the difference between parameters and arguments:
Two kinds of parameters: input parametersthe most common kind; they pass values into functions. Depending on the programming language, input parameters can be passed in several ways (e.g., call-by-value, call-by-address, call-by-reference). output/return parametersprimarily return multiple values from a function, but are not recommended since they cause confusion See also This is the reference manual for the Go programming language. The pre-Go1.18 version, without generics, can be found here. For more information and other documents, see golang.org. Go is a general-purpose language designed with systems programming in mind. It is strongly typed and
garbage-collected and has explicit support for concurrent programming. Programs are constructed from packages, whose properties allow efficient management of dependencies. The syntax is compact and simple to parse, allowing for easy analysis by automatic tools such as integrated development environments. The syntax is specified using a variant of Extended
Backus-Naur Form (EBNF): Productions are expressions constructed from terms and the following operators, in increasing precedence: Lowercase production names are used to identify lexical (terminal) tokens. Non-terminals are in CamelCase. Lexical tokens are enclosed in double quotes The form Source code is Unicode text encoded in UTF-8. The text is not canonicalized, so a single accented code point is distinct from the same
character constructed from combining an accent and a letter; those are treated as two code points. For simplicity, this document will use the unqualified term character to refer to a Unicode code point in the source text. Each code point is distinct; for instance, uppercase and lowercase letters are different characters. Implementation restriction: For compatibility with other tools, a compiler may disallow the NUL character (U+0000) in the source text.
Implementation restriction: For compatibility with other tools, a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) if it is the first Unicode code point in the source text. A byte order mark may be disallowed anywhere else in the source. The following terms are used to denote specific Unicode character categories: In The Unicode Standard 8.0, Section
4.5 "General Category" defines a set of character categories. Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo as Unicode letters, and those in the Number category Nd as Unicode digits. The underscore character Comments serve as program documentation. There are two forms: A comment cannot start inside a rune or string literal, or inside a comment. A general comment containing no newlines
acts like a space. Any other comment acts like a newline. Tokens form the vocabulary of the Go language. There are four classes: identifiers, keywords, operators and punctuation, and literals. White space, formed from spaces (U+0020), horizontal tabs (U+0009), carriage returns (U+000D), and newlines (U+000A), is ignored except as it separates tokens that would otherwise combine into a single token. Also, a newline or end of
file may trigger the insertion of a semicolon. While breaking the input into tokens, the next token is the longest sequence of characters that form a valid token. The formal syntax uses semicolons To reflect idiomatic use, code examples in this document elide semicolons using these rules. Identifiers name program entities such as variables and types. An identifier is a sequence of one or more letters and digits. The first character in an identifier must be a letter. Some identifiers are
predeclared. The following keywords are reserved and may not be used as identifiers. The following character sequences represent operators (including assignment
operators) and punctuation: An integer literal is a sequence of digits representing an integer constant. An optional prefix sets a non-decimal base: For readability, an underscore character A floating-point literal is a decimal or hexadecimal representation of a floating-point constant.
A decimal floating-point literal consists of an integer part (decimal digits), a decimal point, a fractional part (decimal digits), and an exponent part ( A hexadecimal floating-point literal consists of a
For readability, an underscore character An imaginary literal represents the imaginary part of a complex constant. It consists of an integer or floating-point literal followed by the lowercase letter For backward compatibility, an imaginary literal's integer part consisting entirely of decimal digits (and possibly underscores) is considered a decimal integer, even if it starts with a leading
A rune literal represents a rune constant, an integer value identifying a Unicode code point. A rune literal is expressed as one or more characters enclosed in single quotes, as in The simplest form represents the single character within the quotes; since Go source text is Unicode characters encoded in UTF-8, multiple UTF-8-encoded bytes may represent a single integer value. For instance, the literal Several backslash escapes allow arbitrary values to be encoded as ASCII text. There are four ways to represent the integer value as a numeric constant: Although these representations all result in an integer, they have different valid ranges. Octal escapes must represent a value between 0 and 255 inclusive. Hexadecimal escapes satisfy this condition by construction. The escapes After a backslash, certain single-character escapes represent
special values: An unrecognized character following a backslash in a rune literal is illegal. A string literal represents a string constant obtained from concatenating a sequence of characters. There are two forms: raw string literals and interpreted string literals. Raw string literals are character sequences between back quotes, as in
Interpreted string literals are character sequences between double quotes, as in
These examples all represent the same string: If the source code represents a
character as two code points, such as a combining form involving an accent and a letter, the result will be an error if placed in a rune literal (it is not a single code point), and will appear as two code points if placed in a string literal. There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants. Rune, integer, floating-point, and complex
constants are collectively called numeric constants. A constant value is represented by a rune, integer, floating-point, imaginary, or
string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as In general, complex constants are a form of
constant expression and are discussed in that section. Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values. Constants may be typed or untyped. Literal constants, A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a
variable declaration or an assignment statement or as an operand in an expression. It is an error if the constant value cannot be represented as a value of the respective type. If the type is a type parameter,
the constant is converted into a non-constant value of the type parameter. An untyped constant has a default type which is the type to which the constant is implicitly converted in contexts where a typed value is required, for instance, in a short variable declaration such as Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must: These requirements apply both to literal constants and to the
result of evaluating constant expressions. A variable is a storage location for holding a value. The set of permissible values is determined by the variable's type. A variable declaration or, for function parameters and
results, the signature of a function declaration or function literal reserves storage for a named variable. Calling the built-in function Structured variables of array, slice, and struct types have elements and fields that may be
addressed individually. Each such element acts like a variable. The static type (or just type) of a variable is the type given in its declaration, the type provided in the A variable's value is retrieved by referring to the variable in an expression; it is the most recent value
assigned to the variable. If a variable has not yet been assigned a value, its value is the zero value for its type. A type determines a set of values together with operations and methods specific to those values. A type may be denoted by a type name, if it has one, which must be followed by
type arguments if the type is generic. A type may also be specified using a type literal, which composes a type from existing types. The language predeclares certain type names. Others are introduced with type declarations or
type parameter lists. Composite types—array, struct, pointer, function, interface, slice, map, and channel types—may be constructed using type literals. Predeclared types, defined types, and type parameters are called named types. An alias denotes a named type if the type given in the alias declaration is a named type. A boolean type
represents the set of Boolean truth values denoted by the predeclared constants An integer, floating-point, or complex type represents the set of integer, floating-point, or complex values, respectively. They are collectively called numeric types. The predeclared
architecture-independent numeric types are: The value of an n-bit integer is n bits wide and represented using two's complement arithmetic. There is also a set of predeclared integer types with implementation-specific sizes: To avoid portability issues all numeric types are defined types and thus
distinct except A string type represents the set of
string values. A string value is a (possibly empty) sequence of bytes. The number of bytes is called the length of the string and is never negative. Strings are immutable: once created, it is impossible to change the contents of a string. The predeclared string type is The length of a string An array is a numbered sequence of
elements of a single type, called the element type. The number of elements is called the length of the array and is never negative. The length is part of the array's type; it must evaluate to a non-negative constant representable by a value of type A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of
elements from that array. A slice type denotes the set of all slices of arrays of its element type. The number of elements is called the length of the slice and is never negative. The value of an uninitialized slice is The length of a slice A slice, once initialized, is always associated with an underlying array that holds its elements. A slice therefore shares storage with its array and with other slices of the same array; by contrast, distinct arrays always represent distinct storage. The array underlying a
slice may extend past the end of the slice. The capacity is a measure of that extent: it is the sum of the length of the slice and the length of the array beyond the slice; a slice of length up to that capacity can be created by slicing a new one from the original slice. The capacity of a slice A new, initialized slice value for a given element type produces the same slice as allocating an array and slicing it, so these two expressions are equivalent: Like arrays, slices are always one-dimensional but may be composed to construct higher-dimensional objects. With arrays of arrays, the inner arrays are, by construction, always the same length; however with slices of slices (or arrays of slices), the inner lengths may vary
dynamically. Moreover, the inner slices must be initialized individually. A struct is a sequence of named elements, called fields, each of which has a name and a type. Field names may be specified explicitly (IdentifierList) or implicitly (EmbeddedField). Within a struct, non-blank field names must be
unique. A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name The following declaration is illegal because field names must be unique
in a struct type: A field or method Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in
composite literals of the struct. Given a struct type A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an
absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored. A pointer type denotes the set of all pointers to variables of a given type, called the base type
of the pointer. The value of an uninitialized pointer is A function type denotes the set of all functions with the same parameter and result types. The value of an uninitialized variable of function type is Within a list of parameters or results, the names (IdentifierList) must either all be present or all be absent. If present, each name stands for one item (parameter or result) of the specified
type and all non-blank names in the signature must be unique. If absent, each type stands for one item of that type. Parameter and result lists are always parenthesized except that if there is exactly one unnamed result it may be written as an unparenthesized type. The final incoming parameter in a function signature may have a type
prefixed with An interface type defines a type set. A variable of interface type can store a value of any type that is in the type set of the interface. Such a type is said to implement the interface. The value of an
uninitialized variable of interface type is An interface type is specified by a list of interface elements. An interface element is either a method or a type element, where a type element is a union of one or more type terms. A type term is either a single type or a single underlying type. In its most basic form an interface specifies a (possibly empty) list of methods. The type set
defined by such an interface is the set of types which implement all of those methods, and the corresponding method set consists exactly of the methods specified by the interface. Interfaces whose type sets can be defined entirely by a list of methods are called basic interfaces. The name of each explicitly specified method must be
unique and not blank. More than one type may implement an interface. For instance, if two types (where Every type that is a member of the type set of an interface implements that interface. Any given type may implement several distinct interfaces. For instance, all types implement the empty interface which stands for the set of all (non-interface) types: For convenience, the predeclared type Similarly, consider this interface specification, which appears within a
type declaration to define an interface called If they implement the In a slightly more general form an interface When embedding interfaces, methods with the
same names must have identical signatures. In their most general form, an interface element may also be an arbitrary type term The quantification "the set of all non-interface types" refers not just to all (non-interface) types declared in the program at hand, but all possible types in all possible programs, and hence is infinite. Similarly, given the set of all non-interface types that implement a
particular method, the intersection of the method sets of those types will contain exactly that method, even if all types in the program at hand always pair that method with another method. By construction, an interface's type set never contains an interface type. In a term of the form Union elements denote unions of type sets: The type Implementation restriction: A union (with more than one term) cannot contain the predeclared
identifier Interfaces that are not basic may only be used as type constraints, or as elements of other interfaces used as constraints. They cannot be the types of values or variables, or components of other, non-interface types. An interface type A type
A value of type 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 MapType = "map" "[" KeyType "]" ElementType . KeyType = Type . The comparison operators map[string]int map[*T]struct{ x, y float64 } map[string]interface{} The number of map elements is called its length. For a map A new, empty map value is made using the built-in function make(map[string]int) make(map[string]int, 100) The initial capacity does not bound its size: maps grow to accommodate the number of items stored in them, with the exception of 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 ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType . The optional 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 The chan<- chan int // same as chan<- (chan int) chan<- <-chan int // same as chan<- (<-chan int) <-chan <-chan int // same as <-chan (<-chan int) chan (<-chan int) A new, initialized channel value can be made using the built-in function make(chan int, 100) The capacity, in number of elements, sets the size of the buffer in the channel. If the capacity is zero or absent, the channel is unbuffered and communication succeeds only when both a sender and receiver are ready. Otherwise, the channel is buffered and communication succeeds without blocking if the buffer is not full (sends) or not empty (receives). A
A channel may be closed with the built-in function A single channel may be used in send statements,
receive operations, and calls to the built-in functions Properties of types and valuesUnderlying types Each type type ( A1 = string A2 = A1 ) type ( B1 string B2 B1 B3 []B1 B4 B3 ) func f[P any](x P) { … } The underlying type of Core types Each non-interface type An interface
No other interfaces have a core type. The core type of an interface is, depending on the condition that is satisfied, either:
By definition, a core type is never a defined type, type parameter, or interface type. Examples of interfaces with core types: type Celsius float32 type Kelvin float32 interface{ int } // int interface{ Celsius|Kelvin } // float32 interface{ ~chan int } // chan int interface{ ~chan int|~chan<- int } // chan<- int interface{ ~[]*data; String() string } // []*data Examples of interfaces without core types: interface{} // no single underlying type interface{ Celsius|float64 } // no single underlying type interface{ chan int | chan<- string } // channels have different element types interface{ <-chan int | chan<- int } // directional channels have different directions Some
operations (slice expressions, Examples of interfaces with interface{ int } // int (same as ordinary core type) interface{ []byte | string } // bytestring interface{ ~[]byte | myString } // bytestring Note that Type identityTwo types are either identical or different. A named type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types. In detail:
Given the declarations type ( A0 = []string A1 = A0 A2 = struct{ a, b int } A3 = int A4 = func(A3, float64) *A0 A5 = func(x int, _ float64) *[]string B0 A0 B1 []string B2 struct{ a, b int } B3 struct{ a, c int } B4 func(int, float64) *B0 B5 func(x int, y float64) *A1 C0 = B0 D0[P1, P2 any] struct{ x P1; y P2 } E0 = D0[int, string] ) these types are identical: A0, A1, and []string A2 and struct{ a, b int } A3 and int A4, func(int, float64) *[]string, and A5 B0 and C0 D0[int, string] and E0 []int and []int struct{ a, b *B5 } and struct{ a, b *B5 } func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5 Assignability A value
Additionally, if
Representability A constant
If x T x is representable by a value of T because 'a' byte 97 is in the set of byte values 97 rune rune is an alias for int32, and 97 is in the set of 32-bit integers "foo" string "foo" is in the set of string values 1024 int16 1024 is in the set of 16-bit integers 42.0 byte 42 is in the set of unsigned 8-bit integers 1e10 uint64 10000000000 is in the set of unsigned 64-bit integers 2.718281828459045 float32 2.718281828459045 rounds to 2.7182817 which is in the set of float32 values -1e-1000 float64 -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0 0i int 0 is an integer value (42 + 0i) float32 42.0 (with zero imaginary part) is in the set of float32 values x T x is not representable by a value of T because 0 bool 0 is not in the set of boolean values 'a' string 'a' is a rune, it is not in the set of string values 1024 byte 1024 is not in the set of unsigned 8-bit integers -1 uint16 -1 is not in the set of unsigned 16-bit integers 1.1 int 1.1 is not an integer value 42i float32 (0 + 42i) is not in the set of float32 values 1e1000 float64 1e1000 overflows to IEEE +Inf after rounding Method setsThe method set of a type determines the methods that can be called on an operand of that type. Every type has a (possibly empty) method set associated with it:
Further rules apply to structs (and pointer to structs) containing embedded fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name. BlocksA block is a possibly empty sequence of declarations and statements within matching brace brackets. Block = "{" StatementList "}" . StatementList = { Statement ";" } . In addition to explicit blocks in the source code, there are implicit blocks:
Blocks nest and influence scoping. Declarations and scopeA declaration binds a non-blank identifier to a constant, type, type parameter, variable, function, label, or package. Every identifier in a program must be declared. No identifier may be declared twice in the same block, and no identifier may be declared in both the file and package block. The
blank identifier may be used like any other identifier in a declaration, but it does not introduce a binding and thus is not declared. In the package block, the identifier Declaration = ConstDecl | TypeDecl | VarDecl . TopLevelDecl = Declaration | FunctionDecl | MethodDecl . The scope of a declared identifier is the extent of source text in which the identifier denotes the specified constant, type, variable, function, label, or package. Go is lexically scoped using blocks:
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. 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. Label scopesLabels are declared by labeled statements and are used in the "break", "continue", and "goto" statements. It is illegal to define a label that is never used. In contrast to other identifiers, labels are not block scoped and do not conflict with identifiers that are not labels. The scope of a label is the body of the function in which it is declared and excludes the body of any nested function. Blank identifier The blank identifier is represented by the underscore
character Predeclared identifiersThe 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 Exported identifiersAn identifier may be exported to permit access to it from another package. An identifier is exported if both:
All other identifiers are not exported. Uniqueness of identifiersGiven 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. Constant declarationsA constant declaration binds a list of identifiers (the names of the constants) to the values of a list of constant expressions. The number of identifiers must be equal to the number of expressions, and the nth identifier on the left is bound to the value of the nth expression on the right. ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . IdentifierList = identifier { "," identifier } . ExpressionList = Expression { "," Expression } . If the type is present, all constants take the type specified, and the expressions must be assignable to that type, which must not be a type parameter. If the type is omitted, the constants take the individual types of the corresponding expressions. If the expression values are untyped constants, the declared constants remain untyped and the constant identifiers denote the constant values. For instance, if the expression is a floating-point literal, the constant identifier denotes a floating-point constant, even if the literal's fractional part is zero. 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", untyped integer and string constants const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Within a parenthesized const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // this constant is not exported ) Iota Within a constant declaration, the predeclared identifier 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 ( u = iota * 42 // u == 0 (untyped integer constant) v float64 = iota * 42 // v == 42.0 (float64 constant) w = iota * 42 // w == 84 (untyped integer constant) ) const x = iota // x == 0 const y = iota // y == 0 By definition, multiple uses of 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) ) This last example exploits the implicit repetition of the last non-empty expression list. Type declarationsA type declaration binds an identifier, the type name, to a type. Type declarations come in two forms: alias declarations and type definitions. TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . TypeSpec = AliasDecl | TypeDef . Alias declarationsAn alias declaration binds an identifier to the given type. AliasDecl = identifier "=" Type . Within the scope of the identifier, it serves as an alias for the type. type ( nodeList = []*Node // nodeList and []*Node are identical types Polar = polar // Polar and polar denote identical types ) Type definitionsA type definition creates a new, distinct type with the same underlying type and operations as the given type and binds an identifier, the type name, to it. TypeDef = identifier [ TypeParameters ] Type . The new type is called a defined type. It is different from any other type, including the type it is created from. type ( Point struct{ x, y float64 } // Point and struct{ x, y float64 } are different types polar Point // polar and Point denote different types ) type TreeNode struct { left, right *TreeNode value any } type Block interface { BlockSize() int Encrypt(src, dst []byte) Decrypt(src, dst []byte) } A defined type may have methods associated with it. It does not inherit any methods bound to the given type, but the method set of an interface type or of elements of a composite type remains unchanged: // A Mutex is a data type with two methods, Lock and Unlock. type Mutex struct { /* Mutex fields */ } func (m *Mutex) Lock() { /* Lock implementation */ } func (m *Mutex) Unlock() { /* Unlock implementation */ } // 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 } // MyBlock is an interface type that has the same method set as Block. type MyBlock Block Type definitions may be used to define different boolean, numeric, or string types and associate methods with them: type TimeZone int const ( EST TimeZone = -(5 + iota) CST MST PST ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT%+dh", tz) } If the type definition specifies type parameters, the type name denotes a generic type. Generic types must be instantiated when they are used. type List[T any] struct { next *List[T] value T } In a type definition the given type cannot be a type parameter. type T[P any] P // illegal: P is a type parameter func f[T any]() { type L T // illegal: T is a type parameter declared by the enclosing function } A generic type may also have methods associated with it. In this case, the method receivers must declare the same number of type parameters as present in the generic type definition. // The method Len returns the number of elements in the linked list l. func (l *List[T]) Len() int { … } Type parameter declarationsA type parameter list declares the type parameters of a generic function or type declaration. The type parameter list looks like an ordinary function parameter list except that the type parameter names must all be present and the list is enclosed in square brackets rather than parentheses. TypeParameters = "[" TypeParamList [ "," ] "]" . TypeParamList = TypeParamDecl { "," TypeParamDecl } . TypeParamDecl = IdentifierList TypeConstraint . All non-blank names in the list must be unique. Each name declares a type parameter, which is a new and different named type that acts as a place holder for an (as of yet) unknown type in the declaration. The type parameter is replaced with a type argument upon instantiation of the generic function or type. [P any] [S interface{ ~[]byte|string }] [S ~[]E, E any] [P Constraint[int]] [_ any] Just as each ordinary function parameter has a parameter type, each type parameter has a corresponding (meta-)type which is called its type constraint. A parsing ambiguity arises when the type parameter list for a
generic type declares a single type parameter type T[P *C] … type T[P (C)] … type T[P *C|Q] … … In these rare cases, the type parameter list is indistinguishable from an expression and the type declaration is parsed as an array type declaration. To resolve the ambiguity, embed the constraint in an interface or use a trailing comma: type T[P interface{*C}] … type T[P *C,] … Type parameters may also be declared by the receiver specification of a method declaration associated with a generic type. Type constraintsA type constraint is an interface that defines the set of permissible type arguments for the respective type parameter and controls the operations supported by values of that type parameter. TypeConstraint = TypeElem . If the constraint is an interface literal of the form [T []P] // = [T interface{[]P}] [T ~int] // = [T interface{~int}] [T int|string] // = [T interface{int|string}] type Constraint ~int // illegal: ~int is not inside a type parameter list The predeclared interface type
Even though interfaces that are not type parameters can be
compared (possibly causing a run-time panic) they do not implement int // implements comparable []byte // does not implement comparable (slices cannot be compared) interface{} // does not implement comparable (see above) interface{ ~int | ~string } // type parameter only: implements comparable interface{ comparable } // type parameter only: implements comparable interface{ ~int | ~[]byte } // type parameter only: does not implement comparable (not all types in the type set are comparable) The Variable declarationsA variable declaration creates one or more variables, binds corresponding identifiers to them, and gives each a type and an initial value. 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 ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // map lookup; only interested in "found" If a list of expressions is given, the variables are initialized with the expressions following the rules for assignment statements. Otherwise, each variable is initialized to its zero value. If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first implicitly converted to its default type; if it is an untyped boolean
value, it is first implicitly converted to type var d = math.Sin(0.5) // d is float64 var i = 42 // i is int var t, ok = x.(T) // t is T, ok is bool var n = nil // illegal Implementation restriction: A compiler may make it illegal to declare a variable inside a function body if the variable is never used. Short variable declarationsA short variable declaration uses the syntax: ShortVarDecl = IdentifierList ":=" ExpressionList . It is shorthand for a regular variable declaration with initializer expressions but no types: "var" IdentifierList "=" ExpressionList . i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) r, w, _ := os.Pipe() // os.Pipe() returns a connected pair of Files and an error, if any _, y, _ := coord(p) // coord() returns three values; only interested in y coordinate Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the
non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original. The non-blank variable names on the left side of 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 variable declarations may appear only inside functions. In some contexts such as the initializers for "if", "for", or "switch" statements, they can be used to declare local temporary variables. Function declarationsA function declaration binds an identifier, the function name, to a function. FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] . FunctionName = identifier . FunctionBody = Block . If the function's signature declares result parameters, the function body's statement list must end in a terminating statement. func IndexRune(s string, r rune) int { for i, c := range s { if c == r { return i } } // invalid: missing return statement } If the function declaration specifies type parameters, the function name denotes a generic function. A generic function must be instantiated before it can be called or used as a value. func min[T ~int|~float64](x, y T) T { if x < y { return x } return y } A function declaration without type parameters may omit the body. Such a declaration provides the signature for a function implemented outside Go, such as an assembly routine. func flushICache(begin, end uintptr) // implemented externally Method declarationsA method is a function with a receiver. A method declaration binds an identifier, the method name, to a method, and associates the method with the receiver's base type. MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] . Receiver = Parameters . The receiver is specified via an extra parameter section preceding the method name. That parameter section must declare a single non-variadic parameter, the receiver. Its type must be a
defined type A non-blank receiver identifier must be unique in the method signature. If the receiver's value is not referenced inside the body of the method, its identifier may be omitted in the declaration. The same applies in general to parameters of functions and methods. For a base type, the non-blank names of methods bound to it must be unique. If the base type is a struct type, the non-blank method and field names must be distinct. Given defined type func (p *Point) Length() float64 { return math.Sqrt(p.x * p.x + p.y * p.y) } func (p *Point) Scale(factor float64) { p.x *= factor p.y *= factor } bind the methods If the receiver base type is a generic type, the receiver specification must declare corresponding type parameters for the method to use. This makes the receiver type parameters available to the method. Syntactically, this type parameter declaration looks like an instantiation of the receiver base type: the type arguments must be identifiers denoting the type parameters being declared, one for each type parameter of the receiver base type. The type parameter names do not need to match their corresponding parameter names in the receiver base type definition, and all non-blank parameter names must be unique in the receiver parameter section and the method signature. The receiver type parameter constraints are implied by the receiver base type definition: corresponding type parameters have corresponding constraints. type Pair[A, B any] struct { a A b B } func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair ExpressionsAn expression specifies the computation of a value by applying operators and functions to operands. OperandsOperands denote the elementary values in an expression. An operand may be a literal, a (possibly qualified) non-blank identifier denoting a constant, variable, or function, or a parenthesized expression. Operand = Literal | OperandName [ TypeArgs ] | "(" Expression ")" . Literal = BasicLit | CompositeLit | FunctionLit . BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . OperandName = identifier | QualifiedIdent . An operand name denoting a generic function may be followed by a list of type arguments; the resulting operand is an instantiated function. The blank identifier may appear as an operand only on the left-hand side of an assignment statement. Implementation restriction: A compiler need not report an error if an operand's type is a type parameter with an empty type set. Functions with such type parameters cannot be instantiated; any attempt will lead to an error at the instantiation site. Qualified identifiersA qualified identifier is an identifier qualified with a package name prefix. Both the package name and the identifier must not be blank. QualifiedIdent = PackageName "." identifier . A qualified identifier accesses an identifier in a different package, which must be imported. The identifier must be exported and declared in the package block of that package. math.Sin // denotes the Sin function in package math Composite literalsComposite literals construct new composite values each time they are evaluated. They consist of the type of the literal followed by a brace-bound list of elements. Each element may optionally be preceded by a corresponding key. CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName [ TypeArgs ] . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = KeyedElement { "," KeyedElement } . KeyedElement = [ Key ":" ] Element . Key = FieldName | Expression | LiteralValue . FieldName = identifier . Element = Expression | LiteralValue . The LiteralType's core type
For struct literals the following rules apply:
Given the declarations type Point3D struct { x, y, z float64 } type Line struct { p, q Point3D } one may write origin := Point3D{} // zero value for Point3D line := Line{origin, Point3D{y: -4, z: 12.3}} // zero value for line.q.x For array and slice literals the following rules apply:
Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value. var pointer *Point3D = &Point3D{y: 1000} Note that the zero value for a slice or map type is not the same as an initialized but empty value of the same type. Consequently, taking the address of an empty slice or map composite literal does not have the same effect as allocating a new slice or map value with new. p1 := &[]int{} // p1 points to an initialized, empty slice with value []int{} and length 0 p2 := new([]int) // p2 points to an uninitialized slice with value nil and length 0 The length of an array literal is the length specified in the literal type. If
fewer elements than the length are provided in the literal, the missing elements are set to the zero value for the array element type. It is an error to provide elements with index values outside the index range of the array. The notation buffer := [10]string{} // len(buffer) == 10 intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6 days := [...]string{"Sat", "Sun"} // len(days) == 2 A slice literal describes the entire underlying array literal. Thus the length and capacity of a slice literal are the maximum element index plus one. A slice literal has the form []T{x1, x2, … xn} and is shorthand for a slice operation applied to an array: tmp := [n]T{x1, x2, … xn} tmp[0 : n] Within a composite literal of array, slice, or map type [...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}} [][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}} [][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}} map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}} map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"} type PPoint *Point [2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}} [2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})} A parsing ambiguity arises when a composite literal using the TypeName form of the LiteralType appears as an operand between the keyword and the opening brace of the block of an "if", "for", or "switch" statement, and the composite literal is not enclosed in parentheses, square brackets, or curly braces. In this rare case, the opening brace of the literal is erroneously parsed as the one introducing the block of statements. To resolve the ambiguity, the composite literal must appear within parentheses. if x == (T{a,b,c}[i]) { … } if (x == T{a,b,c}[i]) { … } Examples of valid array, slice, and map literals: // list of prime numbers primes := []int{2, 3, 5, 7, 9, 2147483647} // vowels[ch] is true if ch is a vowel vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true} // the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1} // frequencies in Hz for equal-tempered scale (A4 = 440Hz) noteFrequency := map[string]float32{ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83, "G0": 24.50, "A0": 27.50, "B0": 30.87, } Function literalsA function literal represents an anonymous function. Function literals cannot declare type parameters. FunctionLit = "func" Signature FunctionBody . func(a, b int, z float64) bool { return a*b < int(z) } A function literal can be assigned to a variable or invoked directly. f := func(x, y int) int { return x + y } func(ch chan int) { ch <- ACK }(replyChan) Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible. Primary expressionsPrimary expressions are the operands for unary and binary expressions. PrimaryExpr = Operand | Conversion | MethodExpr | PrimaryExpr Selector | PrimaryExpr Index | PrimaryExpr Slice | PrimaryExpr TypeAssertion | PrimaryExpr Arguments . Selector = "." identifier . Index = "[" Expression "]" . Slice = "[" [ Expression ] ":" [ Expression ] "]" | "[" [ Expression ] ":" Expression ":" Expression "]" . TypeAssertion = "." "(" Type ")" . Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . x 2 (s + ".txt") f(3.1415, true) Point{1, 2} m["foo"] s[i : j + 1] obj.color f.p[i].x() Selectors For a primary
expression x.f denotes the field or method A selector The following rules apply to selectors:
For example, given the declarations: type T0 struct { x int } func (*T0) M0() type T1 struct { y int } func (T1) M1() type T2 struct { z int T1 *T0 } func (*T2) M2() type Q *T2 var t T2 // with t.T0 != nil var p *T2 // with p != nil and (*p).T0 != nil var q Q = p one may write: t.z // t.z t.y // t.T1.y t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y p.x // (*(*p).T0).x q.x // (*(*q).T0).x (*q).x is a valid field selector p.M0() // ((*p).T0).M0() M0 expects *T0 receiver p.M1() // ((*p).T1).M1() M1 expects T1 receiver p.M2() // p.M2() M2 expects *T2 receiver t.M2() // (&t).M2() M2 expects *T2 receiver, see section on Calls but the following is invalid: q.M0() // (*q).M0 is valid but not a field selector Method expressions If MethodExpr = ReceiverType "." MethodName . ReceiverType = Type . Consider a struct type type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T The expression T.Mv yields a function equivalent to func(tv T, a int) int That function may be called normally with an explicit receiver, so these five invocations are equivalent: t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7) Similarly, the expression (*T).Mp yields a function value representing func(tp *T, f float32) float32 For a method with a value receiver, one can derive a function with an explicit pointer receiver, so (*T).Mv yields a function value representing func(tv *T, a int) int Such a function indirects through the receiver to create a value to pass as the receiver to the underlying method; the method does not overwrite the value whose address is passed in the function call. The final case, a value-receiver function for a pointer-receiver method, is illegal because pointer-receiver methods are not in the method set of the value type. Function values derived from methods are called with function call syntax; the receiver is provided as the first argument to the call. That is, given It is legal to derive a function value from a method of an interface type. The resulting function takes an explicit receiver of that interface type. Method values If the expression type S struct { *T } type T int func (t T) M() { print(t) } t := new(T) s := S{T: t} f := t.M // receiver *t is evaluated and stored in f g := s.M // receiver *(s.T) is evaluated and stored in g *t = 42 // does not affect stored receivers in f and g The type As in the discussion of method expressions above, consider a struct type type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T var pt *T func makeT() T The expression t.Mv yields a function value of type func(int) int These two invocations are equivalent: t.Mv(7) f := t.Mv; f(7) Similarly, the expression pt.Mp yields a function value of type func(float32) float32 As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: f := t.Mv; f(7) // like t.Mv(7) f := pt.Mp; f(7) // like pt.Mp(7) f := pt.Mv; f(7) // like (*pt).Mv(7) f := t.Mp; f(7) // like (&t).Mp(7) f := makeT().Mp // invalid: result of makeT() is not addressable Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type. var i interface { M(int) } = myVal f := i.M; f(7) // like i.M(7) Index expressionsA primary expression of the form a[x] denotes the element of the array, pointer to array, slice, string or map If
For
For
For
For
For
For
Otherwise An index expression on a map v, ok = a[x] v, ok := a[x] var v, ok = a[x] yields an additional untyped boolean value. The value of Assigning to an element of a Slice expressionsSlice expressions construct a substring or slice from a string, array, pointer to array, or slice. There are two variants: a simple form that specifies a low and high bound, and a full form that also specifies a bound on the capacity. Simple slice expressionsThe primary expression a[low : high] constructs a substring or slice. The
core type of a := [5]int{1, 2, 3, 4, 5} s := a[1:4] the slice s[0] == 2 s[1] == 3 s[2] == 4 For convenience, any of the indices may be omitted. A missing a[2:] // same as a[2 : len(a)] a[:3] // same as a[0 : 3] a[:] // same as a[0 : len(a)] If For arrays or strings, the indices are in range if Except for untyped strings, if the sliced operand is a string or slice, the result of the slice operation is a non-constant value of the same type as the operand. For untyped string operands the result is a non-constant value of type If the sliced operand of a valid slice expression is a var a [10]int s1 := a[3:7] // underlying array of s1 is array a; &s1[2] == &a[5] s2 := s1[1:4] // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5] s2[1] = 42 // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element Full slice expressionsThe primary expression a[low : high : max] constructs a slice of the same type, and with
the same length and elements as the simple slice expression a := [5]int{1, 2, 3, 4, 5} t := a[1:3:5] the slice t[0] == 2 t[1] == 3
As for simple slice expressions, if The indices are in range if Type assertions For an expression x.(T) asserts that More precisely, if If the type assertion holds, the value of the expression is the value stored in var x interface{} = 7 // x has dynamic type int and value 7 i := x.(int) // i has type int and value 7 type I interface { m() } func f(y I) { s := y.(string) // illegal: string does not implement I (missing method m) r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader … } A type assertion used in an assignment statement or initialization of the special form v, ok = x.(T) v, ok := x.(T) var v, ok = x.(T) var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool yields an additional untyped boolean value. The value of Calls Given an expression f(a1, a2, … an) calls math.Atan2(x, y) // function call var pt *Point pt.Scale(3.5) // method call with receiver pt If In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the caller when the function returns. Calling a As a special case, if the return values of a function or method func Split(s string, pos int) (string, string) { return s[0:pos], s[pos:] } func Join(s, t string) string { return s + t } if Join(Split(value, len(value)/2)) != value { log.Panic("test fails") } A method call var p Point p.Scale(3.5) There is no distinct method type and there are no method literals. Passing arguments to ... parameters If Given the function and calls func Greeting(prefix string, who ...string) Greeting("nobody") Greeting("hello:", "Joe", "Anna", "Eileen") within If the final argument is assignable to a slice type Given the slice s := []string{"James", "Jasmine"} Greeting("goodbye:", s...) within InstantiationsA generic function or type is instantiated by substituting type arguments for the type parameters. Instantiation proceeds in two steps:
Instantiating a type results in a new non-generic named type; instantiating a function produces a new non-generic function. type parameter list type arguments after substitution [P any] int int implements any [S ~[]E, E any] []int, int []int implements ~[]int, int implements any [P io.Writer] string illegal: string doesn't implement io.Writer For a generic function, type arguments may be provided explicitly, or they may be partially or completely inferred. A generic function that is not called requires a type argument list for instantiation; if the list is partial, all remaining type arguments must be inferrable. A generic function that is called may provide a (possibly partial) type argument list, or may omit it entirely if the omitted type arguments are inferrable from the ordinary (non-type) function arguments. func min[T ~int|~float64](x, y T) T { … } f := min // illegal: min must be instantiated with type arguments when used without being called minInt := min[int] // minInt has type func(x, y int) int a := minInt(2, 3) // a has value 2 of type int b := min[float64](2.0, 3) // b has value 2.0 of type float64 c := min(b, -1) // c has value -1.0 of type float64 A partial type argument list cannot be empty; at least the first argument must be present. The list is a prefix of the full list of type arguments, leaving the remaining arguments to be inferred. Loosely speaking, type arguments may be omitted from "right to left". func apply[S ~[]E, E any](s S, f(E) E) S { … } f0 := apply[] // illegal: type argument list cannot be empty f1 := apply[[]int] // type argument for S explicitly provided, type argument for E inferred f2 := apply[[]string, string] // both type arguments explicitly provided var bytes []byte r := apply(bytes, func(byte) byte { … }) // both type arguments inferred from the function arguments For a generic type, all type arguments must always be provided explicitly. Type inferenceMissing function type arguments may be inferred by a series of steps, described below. Each step attempts to use known information to infer additional type arguments. Type inference stops as soon as all type arguments are known. After type inference is complete, it is still necessary to substitute all type arguments for type parameters and verify that each type argument implements the relevant constraint; it is possible for an inferred type argument to fail to implement a constraint, in which case instantiation fails. Type inference is based on
and then proceeds with the following steps:
If there are no ordinary or untyped function arguments, the respective steps are skipped. Constraint type inference is skipped if the previous step didn't infer any new type arguments, but it is run at least once if there are missing type arguments. The substitution map M is carried through all steps, and each step may add entries to M. The process stops as soon as M has a type argument for each type parameter or if an inference step fails. If an inference step fails, or if M is still missing type arguments after the last step, type inference fails. Type unification Type inference is based on type unification. A single unification step applies to a substitution map and
two types, either or both of which may be or contain type parameters. The substitution map tracks the known (explicitly provided or already inferred) type arguments: the map contains an entry For unification, two types that don't contain any type parameters from the current type parameter list are equivalent if they are identical, or if they are channel types that are identical ignoring channel direction, or if their underlying types are equivalent. Unification works by comparing the structure of pairs of types: their structure disregarding type parameters must be identical, and types other than type parameters must be equivalent. A type parameter in one type may match any complete subtype in the other type; each successful match causes an entry to be added to the substitution map. If the structure differs, or types other than type parameters are not equivalent, unification fails. For example, if []map[int]bool // types are identical T1 // adds T1 → []map[int]bool to substitution map []T1 // adds T1 → map[int]bool to substitution map []map[T1]T2 // adds T1 → int and T2 → bool to substitution map On the other hand, int // int is not a slice struct{} // a struct is not a slice []struct{} // a struct is not a map []map[T1]string // map element types don't match As an exception to this general rule, because a
defined type type Vector []float64 and the type literal Function argument type inference
Function argument type inference infers type arguments from function arguments: if a function parameter is declared with a type For instance, given the generic function func scale[Number ~int64|~float64|~complex128](v []Number, s Number) []Number and the call var vector []float64 scaledVector := scale(vector, 42) the type argument for Inference happens in two separate phases; each phase operates on a specific list of (parameter, argument) pairs:
Any other (parameter, argument) pair is ignored. By construction, the arguments of the pairs in Lu are untyped constants (or the untyped boolean result of a comparison). And because default types of untyped values are always predeclared non-composite types, they can never match against a composite type, so it is sufficient to only consider parameter types that are single type parameters. Each list is processed in a separate phase:
While unification is successful, processing of each list continues until all list elements are considered, even if all type arguments are inferred before the last list element has been processed. Example: func min[T ~int|~float64](x, y T) T var x int min(x, 2.0) // T is int, inferred from typed argument x; 2.0 is assignable to int min(1.0, 2.0) // T is float64, inferred from default type for 1.0 and matches default type for 2.0 min(1.0, 2) // illegal: default type float64 (for 1.0) doesn't match default type int (for 2) In the example Constraint type inference Constraint type inference infers type arguments by considering type constraints. If a type parameter For instance, consider the type parameter list with type parameters [List ~[]Elem, Elem any] Constraint type inference
can deduce the type of type Bytes []byte unifying the underlying type of Using the core type of a constraint may lose some information: In the (unlikely) case that the constraint's type set contains a single defined type Generally, constraint type inference proceeds in two phases: Starting with a given substitution map M
The result of constraint type inference is the final substitution map M
from type parameters For instance, given the type parameter list [A any, B []C, C *A] and the single provided type argument In the first phase, the type parameters At this point there are two entries in M where the right-hand side is or contains type parameters for which there exists other entries in M: Replace Replace At this point no further substitution is possible and the map is full. Therefore, OperatorsOperators combine operands into expressions. Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" . mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" . Comparisons are discussed elsewhere. For other binary operators, the operand types must be identical unless the operation involves shifts or untyped constants. For operations involving constants only, see the section on constant expressions. Except for shift operations, if one operand is an untyped constant and the other operand is not, the constant is implicitly converted to the type of the other operand. The right operand in a shift expression must have integer type or be an untyped constant representable by a value of type var a [1024]byte var s uint = 33 // The results of the following examples are given for 64-bit ints. var i = 1<<s // 1 has type int var j int32 = 1<<s // 1 has type int32; j == 0 var k = uint64(1<<s) // 1 has type uint64; k == 1<<33 var m int = 1.0<<s // 1.0 has type int; m == 1<<33 var n = 1.0<<s == j // 1.0 has type int32; n == true var o = 1<<s == 2<<s // 1 and 2 have type int; o == false var p = 1<<s == 1<<33 // 1 has type int; p == true var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift var v1 float32 = 1<<s // illegal: 1 has type float32, cannot shift var v2 = string(1<<s) // illegal: 1 is converted to a string, cannot shift var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression; w == 1<<33 var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33 // The results of the following examples are given for 32-bit ints, // which means the shifts will overflow. var mm int = 1.0<<s // 1.0 has type int; mm == 0 var oo = 1<<s == 2<<s // 1 and 2 have type int; oo == true var pp = 1<<s == 1<<33 // illegal: 1 has type int, but 1<<33 overflows int var xx = a[1.0<<s] // 1.0 has type int; xx == a[0] var bb = make([]byte, 1.0<<s) // 1.0 has type int; len(bb) == 0 Operator precedence Unary operators have the
highest precedence. As the There are five precedence levels for binary operators. Multiplication operators bind strongest, followed by addition operators, comparison operators, Precedence Operator 5 * / % << >> & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 || Binary operators of the same precedence associate from left to right.
For instance, +x 23 + 3*x[i] x <= f() ^a >> b f() || g() x == y+1 && <-chanInt > 0 Arithmetic operators Arithmetic operators apply to numeric values and yield a result of the same type as the first operand. The four standard arithmetic operators ( + sum integers, floats, complex values, strings - difference integers, floats, complex values * product integers, floats, complex values / quotient integers, floats, complex values % remainder integers & bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << integer >= 0 >> right shift integer >> integer >= 0 If the operand type is a type parameter, the operator must apply to each type in that type set. The operands are represented as values of the type argument that the type parameter is instantiated with, and the operation is computed with the precision of that type argument. For example, given the function: func dotProduct[F ~float32|~float64](v1, v2 []F) F { var s F for i, x := range v1 { y := v2[i] s += x * y } return s } the product Integer operators For two integer values x = q*y + r and |r| < |y| with x y x / y x % y 5 3 1 2 -5 3 -1 -2 5 -3 -1 2 -5 -3 1 -2 The one exception to this rule is that if the dividend x, q int8 -128 int16 -32768 int32 -2147483648 int64 -9223372036854775808 If the divisor is a constant, it must not be zero. If the divisor is zero at run time, a run-time panic occurs. If the dividend is non-negative and the divisor is a constant power of 2, the division may be replaced by a right shift, and computing the remainder may be replaced by a bitwise AND operation: x x / 4 x % 4 x >> 2 x & 3 11 2 3 2 3 -11 -2 -3 -3 1 The shift operators shift the left operand by the shift count specified by the right operand, which must be non-negative. If the shift count is negative at run time, a run-time panic occurs. The shift operators implement arithmetic shifts if the left operand is a signed integer and logical shifts if it is an unsigned integer. There is no upper limit on the shift count.
Shifts behave as if the left operand is shifted For integer operands, the unary operators +x is 0 + x -x negation is 0 - x ^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x and m = -1 for signed x Integer overflow For unsigned integer values, the
operations For signed integers, the operations Floating-point operators For floating-point and complex numbers, An implementation may combine multiple floating-point operations into a single fused operation, possibly across statements, and produce a result that differs from the value obtained by executing and rounding the instructions individually. An explicit floating-point type conversion rounds to the precision of the target type, preventing fusion that would discard that rounding. For instance, some architectures provide a "fused multiply and add" (FMA) instruction that computes // FMA allowed for computing r, because x*y is not explicitly rounded: r = x*y + z r = z; r += x*y t = x*y; r = t + z *p = x*y; r = *p + z r = x*y + float64(z) // FMA disallowed for computing r, because it would omit rounding of x*y: r = float64(x*y) + z r = z; r += float64(x*y) t = float64(x*y); r = t + z String concatenation Strings can be concatenated using the s := "hi" + string(c) s += " and good bye" String addition creates a new string by concatenating the operands. Comparison operatorsComparison operators compare two operands and yield an untyped boolean value. == equal != not equal < less <= less or equal > greater >= greater or equal In any comparison, the first operand must be assignable to the type of the second operand, or vice versa. The equality operators
A comparison of two interface values with identical dynamic types causes a run-time panic if values of that type are not comparable. This behavior applies not only to direct interface value comparisons but also when comparing arrays of interface values or structs with interface-valued fields. Slice, map, and function values are not comparable. However, as a special case, a slice, map, or function value may be compared to the predeclared identifier
const c = 3 < 4 // c is the untyped boolean constant true type MyBool bool var x, y int var ( // The result of a comparison is an untyped boolean. // The usual assignment rules apply. b3 = x == y // b3 has type bool b4 bool = x == y // b4 has type bool b5 MyBool = x == y // b5 has type MyBool ) Logical operatorsLogical operators apply to boolean values and yield a result of the same type as the operands. The right operand is evaluated conditionally. && conditional AND p && q is "if p then q else false" || conditional OR p || q is "if p then true else q" ! NOT !p is "not p" Address operators For an operand For an operand &x &a[f(2)] &Point{2, 3} *p *pf(x) var x *int = nil *x // causes a run-time panic &*x // causes a run-time panic Receive operator For an operand v1 := <-ch v2 = <-ch f(<-ch) <-strobe // wait until clock pulse and discard received value A receive expression used in an assignment statement or initialization of the special form x, ok = <-ch x, ok := <-ch var x, ok = <-ch var x, ok T = <-ch yields an additional untyped boolean result reporting whether the communication succeeded. The value of ConversionsA conversion changes the type of an expression to the type specified by the conversion. A conversion may appear literally in the source, or it may be implied by the context in which an expression appears. An explicit conversion is an expression of the form Conversion = Type "(" Expression [ "," ] ")" . If the type starts with the operator *Point(p) // same as *(Point(p)) (*Point)(p) // p is converted to *Point <-chan int(c) // same as <-(chan int(c)) (<-chan int)(c) // c is converted to <-chan int func()(x) // function signature func() x (func())(x) // x is converted to func() (func() int)(x) // x is converted to func() int func() int(x) // x is converted to func() int (unambiguous) A constant value Converting a constant to a type that is not a type parameter yields a typed constant. uint(iota) // iota value of type uint float32(2.718281828) // 2.718281828 of type float32 complex128(1) // 1.0 + 0.0i of type complex128 float32(0.49999999) // 0.5 of type float32 float64(-1e-1000) // 0.0 of type float64 string('x') // "x" of type string string(0x266c) // "♬" of type string myString("foo" + "bar") // "foobar" of type myString string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant (*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type int(1.2) // illegal: 1.2 cannot be represented as an int string(65.0) // illegal: 65.0 is not an integer constant Converting a constant to a type parameter yields a non-constant value of that type, with the value represented as a value of the type argument that the type parameter is instantiated with. For example, given the function: func f[P ~float32|~float64]() { … P(1.1) … } the conversion A non-constant value
Additionally, if
Struct tags are ignored when comparing struct types for identity for the purpose of conversion: type Person struct { Name string Address *struct { Street string City string } } var data *struct { Name string `json:"name"` Address *struct { Street string `json:"street"` City string `json:"city"` } `json:"address"` } var person = (*Person)(data) // ignoring tags, the underlying types are identical Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the
representation of There is no linguistic mechanism to convert between pointers and integers. The package Conversions between numeric typesFor the conversion of non-constant numeric values, the following rules apply:
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent. Conversions to and from a string type
Conversions from slice to array pointerConverting a slice to an array pointer yields a pointer to the underlying array of the slice. If the length of the slice is less than the length of the array, a run-time panic occurs. s := make([]byte, 2, 4) s0 := (*[0]byte)(s) // s0 != nil s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1] s2 := (*[2]byte)(s) // &s2[0] == &s[0] s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := (*[0]string)(t) // t0 == nil t1 := (*[1]string)(t) // panics: len([1]string) > len(t) u := make([]byte, 0) u0 := (*[0]byte)(u) // u0 != nil Constant expressionsConstant expressions may contain only constant operands and are evaluated at compile time. Untyped boolean, numeric, and string constants may be used as operands wherever it is legal to use an operand of boolean, numeric, or string type, respectively. A constant comparison always yields an untyped boolean constant. If the left operand of a constant shift expression is an untyped constant, the result is an integer constant; otherwise it is a constant of the same type as the left operand, which must be of integer type. Any other operation on untyped constants results in an untyped constant of the same kind; that is, a boolean, integer, floating-point, complex, or string constant. If the untyped operands of a binary operation (other than a shift) are of different kinds, the result is of the operand's kind that appears later in this list: integer, rune, floating-point, complex. For example, an untyped integer constant divided by an untyped complex constant yields an untyped complex constant. const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant) const b = 15 / 4 // b == 3 (untyped integer constant) const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant) const Θ float64 = 3/2 // Θ == 1.0 (type float64, 3/2 is integer division) const Π float64 = 3/2. // Π == 1.5 (type float64, 3/2. is float division) const d = 1 << 3.0 // d == 8 (untyped integer constant) const e = 1.0 << 3 // e == 8 (untyped integer constant) const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32) const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant) const h = "foo" > "bar" // h == true (untyped boolean constant) const j = true // j == true (untyped boolean constant) const k = 'w' + 1 // k == 'x' (untyped rune constant) const l = "hi" // l == "hi" (untyped string constant) const m = string(k) // m == "x" (type string) const Σ = 1 - 0.707i // (untyped complex constant) const Δ = Σ + 2.0e-4 // (untyped complex constant) const Φ = iota*1i - 1/1i // (untyped complex constant) Applying the built-in function const ic = complex(0, c) // ic == 3.75i (untyped complex constant) const iΘ = complex(0, Θ) // iΘ == 1i (type complex128) Constant expressions are always evaluated exactly; intermediate values and the constants themselves may require precision significantly larger than supported by any predeclared type in the language. The following are legal declarations: const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant) const Four int8 = Huge >> 98 // Four == 4 (type int8) The divisor of a constant division or remainder operation must not be zero: 3.14 / 0.0 // illegal: division by zero The values of typed constants must always be accurately representable by values of the constant type. The following constant expressions are illegal: uint(-1) // -1 cannot be represented as a uint int(3.14) // 3.14 cannot be represented as an int int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64 Four * 300 // operand 300 cannot be represented as an int8 (type of Four) Four * 100 // product 400 cannot be represented as an int8 (type of Four) The mask used by the unary bitwise complement operator ^1 // untyped integer constant, equal to -2 uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8 ^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE) int8(^1) // same as int8(-2) ^int8(1) // same as -1 ^ int8(1) = -2 Implementation restriction: A compiler may use rounding while computing untyped floating-point or complex constant expressions; see the implementation restriction in the section on constants. This rounding may cause a floating-point constant expression to be invalid in an integer context, even if it would be integral when calculated using infinite precision, and vice versa. Order of evaluationAt package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order. For example, in the (function-local) assignment y[f()], ok = g(h(), i()+x[j()], <-c), k() the function calls and communication happen in the order a := 1 f := func() int { a++; return a } x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified At package level, initialization dependencies override the left-to-right rule for individual initialization expressions, but not for operands within each expression: var a, b, c = f() + v(), g(), sqr(u()) + v() func f() int { return c } func g() int { return a } func sqr(x int) int { return x*x } // functions u and v are independent of all other variables and functions The function calls happen in the order Floating-point operations within a single expression are evaluated according to the associativity of the operators. Explicit parentheses affect the evaluation by overriding the default associativity. In the expression StatementsStatements control execution. Statement = Declaration | LabeledStmt | SimpleStmt | GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | DeferStmt . SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl . Terminating statementsA terminating statement interrupts the regular flow of control in a block. The following statements are terminating:
All other statements are not terminating. A statement list ends in a terminating statement if the list is not empty and its final non-empty statement is terminating. Empty statementsThe empty statement does nothing. EmptyStmt = . Labeled statements A labeled statement may be the target of a LabeledStmt = Label ":" Statement . Label = identifier . Error: log.Panic("error encountered") Expression statementsWith the exception of specific built-in functions, function and method calls and receive operations can appear in statement context. Such statements may be parenthesized. ExpressionStmt = Expression . The following built-in functions are not permitted in statement context: append cap complex imag len make new real unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice h(x+y) f.Close() <-ch (<-ch) len("foo") // illegal if len is the built-in function Send statementsA send statement sends a value on a channel. The channel expression's core type must be a channel, the channel direction must permit send operations, and the type of the value to be sent must be assignable to the channel's element type. SendStmt = Channel "<-" Expression . Channel = Expression . Both the channel and the value expression are evaluated before communication begins. Communication blocks until the send can proceed. A send on an unbuffered channel can proceed if a receiver is ready. A send on a buffered channel can proceed if there is room in the buffer. A send on a closed channel proceeds by causing a
run-time panic. A send on a ch <- 3 // send value 3 to channel ch IncDec statements The "++" and "--" statements increment or decrement their operands by the untyped constant IncDecStmt = Expression ( "++" | "--" ) . The following assignment statements are semantically equivalent: IncDec statement Assignment x++ x += 1 x-- x -= 1 Assignment statementsAn assignment replaces the current value stored in a variable with a new value specified by an expression. An assignment statement may assign a single value to a single variable, or multiple values to a matching number of variables. Assignment = ExpressionList assign_op ExpressionList . assign_op = [ add_op | mul_op ] "=" . Each left-hand side operand must be addressable, a map index expression, or (for x = 1 *p = f() a[i] = 23 (k) = <-ch // same as: k = <-ch An assignment operation a[i] <<= 2 i &^= 1<<n
A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on
the left hand side must match the number of values. For instance, if x, y = f() assigns the first value to one, two, three = '一', '二', '三' The blank identifier provides a way to ignore right-hand side values in an assignment: _ = x // evaluate x but ignore it x, _ = f() // evaluate f() but ignore second result value The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order. a, b = b, a // exchange a and b x := []int{1, 2, 3} i := 0 i, x[i] = 1, 2 // set i = 1, x[0] = 2 i = 0 x[i], i = 2, 1 // set x[0] = 2, i = 1 x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end) x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5. type Point struct { x, y int } var p *Point x[2], p.x = 6, 7 // set x[2] = 6, then panic setting p.x = 7 i = 2 x = []int{3, 5, 7} for i, x[i] = range x { // set i, x[2] = 0, x[0] break } // after this loop, i == 0 and x == []int{3, 5, 3} In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
If statements"If" statements specify the conditional execution of two branches according to the value of a boolean expression. If the expression evaluates to true, the "if" branch is executed, otherwise, if present, the "else" branch is executed. IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] . if x > max { x = max } The expression may be preceded by a simple statement, which executes before the expression is evaluated. if x := f(); x < y { return x } else if x > z { return z } else { return y } Switch statements"Switch" statements provide multi-way execution. An expression or type is compared to the "cases" inside the "switch" to determine which branch to execute. SwitchStmt = ExprSwitchStmt | TypeSwitchStmt . There are two forms: expression switches and type switches. In an expression switch, the cases contain expressions that are compared against the value of the switch expression. In a type switch, the cases contain types that are compared against the type of a specially annotated switch expression. The switch expression is evaluated exactly once in a switch statement. Expression switches In an expression switch, the switch expression is evaluated and the case expressions, which need not be constants, are evaluated left-to-right and top-to-bottom; the first one that equals the switch expression triggers execution of the statements of the associated case; the other cases are skipped. If no case matches and there is a "default" case, its statements are executed.
There can be at most one default case and it may appear anywhere in the "switch" statement. A missing switch expression is equivalent to the boolean value ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" . ExprCaseClause = ExprSwitchCase ":" StatementList . ExprSwitchCase = "case" ExpressionList | "default" . If the switch expression evaluates to an untyped constant, it is first implicitly converted to its default type. The predeclared untyped value If a case expression is untyped, it is first implicitly converted to the type of the switch expression. For each (possibly converted) case expression In other words, the switch expression is treated as if it were used to declare and initialize a temporary variable In a case or default clause, the last non-empty statement may be a (possibly labeled) "fallthrough" statement to indicate that control should flow from the end of this clause to the first statement of the next clause. Otherwise control flows to the end of the "switch" statement. A "fallthrough" statement may appear as the last statement of all but the last clause of an expression switch. The switch expression may be preceded by a simple statement, which executes before the expression is evaluated. switch tag { default: s3() case 0, 1, 2, 3: s1() case 4, 5, 6, 7: s2() } switch x := f(); { // missing switch expression means "true" case x < 0: return -x default: return x } switch { case x < y: f1() case x < z: f2() case x == 4: f3() } Implementation restriction: A compiler may disallow multiple case expressions evaluating to the same constant. For instance, the current compilers disallow duplicate integer, floating point, or string constants in case expressions. Type switches A type switch compares types rather than values. It is otherwise similar to an expression switch. It is marked by a
special switch expression that has the form of a type assertion using the keyword switch x.(type) { // cases } Cases then match actual types TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . TypeCaseClause = TypeSwitchCase ":" StatementList . TypeSwitchCase = "case" TypeList | "default" . The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the end of the TypeSwitchCase in the implicit block of each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard. Instead of a type, a case may use the predeclared identifier Given an expression switch i := x.(type) { case nil: printString("x is nil") // type of i is type of x (interface{}) case int: printInt(i) // type of i is int case float64: printFloat64(i) // type of i is float64 case func(int) float64: printFunction(i) // type of i is func(int) float64 case bool, string: printString("type is bool or string") // type of i is type of x (interface{}) default: printString("don't know the type") // type of i is type of x (interface{}) } could be rewritten: v := x // x is evaluated exactly once if v == nil { i := v // type of i is type of x (interface{}) printString("x is nil") } else if i, isInt := v.(int); isInt { printInt(i) // type of i is int } else if i, isFloat64 := v.(float64); isFloat64 { printFloat64(i) // type of i is float64 } else if i, isFunc := v.(func(int) float64); isFunc { printFunction(i) // type of i is func(int) float64 } else { _, isBool := v.(bool) _, isString := v.(string) if isBool || isString { i := v // type of i is type of x (interface{}) printString("type is bool or string") } else { i := v // type of i is type of x (interface{}) printString("don't know the type") } } A type parameter or a generic type may be used as a type in a case. If upon instantiation that type turns out to duplicate another entry in the switch, the first matching case is chosen. func f[P any](x any) int { switch x.(type) { case P: return 0 case string: return 1 case []P: return 2 case []byte: return 3 default: return 4 } } var v1 = f[string]("foo") // v1 == 0 var v2 = f[byte]([]byte{}) // v2 == 2 The type switch guard may be preceded by a simple statement, which executes before the guard is evaluated. The "fallthrough" statement is not permitted in a type switch. For statementsA "for" statement specifies repeated execution of a block. There are three forms: The iteration may be controlled by a single condition, a "for" clause, or a "range" clause. ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . Condition = Expression . For statements with single condition In its simplest form, a "for" statement specifies the repeated execution of a block as long as a boolean condition evaluates to true. The condition is evaluated before each iteration. If the condition is absent, it is equivalent to the boolean value for a < b { a *= 2 } For statements with |