mirror of
https://github.com/golang/go
synced 2024-11-25 07:07:57 -07:00
83c17606d7
- removed explicit "export" declarations and keyword - fixed a few glitches and adjusted examples (The details of what "export" mean should be clarified in the spec, this is just so we have a working doc for now.) R=r DELTA=131 (7 added, 63 deleted, 61 changed) OCL=22753 CL=22970
3349 lines
105 KiB
Plaintext
3349 lines
105 KiB
Plaintext
The Go Programming Language Specification (DRAFT)
|
|
----
|
|
|
|
Robert Griesemer, Rob Pike, Ken Thompson
|
|
|
|
(January 16, 2009)
|
|
|
|
----
|
|
|
|
This document is a semi-formal specification of the Go systems
|
|
programming language.
|
|
|
|
<font color=red>
|
|
This document is not ready for external review, it is under active development.
|
|
Any part may change substantially as design progresses.
|
|
</font>
|
|
|
|
----
|
|
|
|
<!--
|
|
Timeline (9/5/08):
|
|
- threads: 1 month
|
|
- reflection code: 2 months
|
|
- proto buf support: 3 months
|
|
- GC: 6 months
|
|
- debugger
|
|
- Jan 1, 2009: enough support to write interesting programs
|
|
|
|
|
|
Missing:
|
|
[ ] Helper syntax for composite types: allow names/indices for maps/arrays,
|
|
remove need for type in elements of composites
|
|
|
|
|
|
Todo's:
|
|
[ ] clarification on interface types, rules
|
|
[ ] clarify slice rules
|
|
[ ] clarify tuples
|
|
[ ] need to talk about precise int/floats clearly
|
|
[ ] iant suggests to use abstract/precise int for len(), cap() - good idea
|
|
(issue: what happens in len() + const - what is the type?)
|
|
[ ] what are the permissible ranges for the indices in slices? The spec
|
|
doesn't correspond to the implementation. The spec is wrong when it
|
|
comes to the first index i: it should allow (at least) the range 0 <= i <= len(a).
|
|
also: document different semantics for strings and arrays (strings cannot be grown).
|
|
|
|
|
|
Open issues:
|
|
[ ] semantics of type decl and where methods are attached
|
|
what about: type MyInt int (does it produce a new (incompatible) int)?
|
|
[ ] convert should not be used for composite literals anymore,
|
|
in fact, convert() should go away
|
|
[ ] if statement: else syntax must be fixed
|
|
[ ] old-style export decls (still needed, but ideally should go away)
|
|
[ ] like to have assert() in the language, w/ option to disable code gen for it
|
|
[ ] composite types should uniformly create an instance instead of a pointer
|
|
[ ] need for type switch? (or use type guard with ok in tuple assignment?)
|
|
[ ] do we need anything on package vs file names?
|
|
[ ] type switch or some form of type test needed
|
|
[ ] what is the meaning of typeof()
|
|
[ ] at the moment: type T S; strips any methods of S. It probably shouldn't.
|
|
[ ] 6g allows: interface { f F } where F is a function type. fine, but then we should
|
|
also allow: func f F {}, where F is a function type.
|
|
[ ] provide composite literal notation to address array indices: []int{ 0: x1, 1: x2, ... }
|
|
and struct field names (both seem easy to do).
|
|
[ ] reopening & and func issue: Seems inconsistent as both &func(){} and func(){} are
|
|
permitted. Suggestion: func literals are pointers. We need to use & for all other
|
|
functions. This would be in consistency with the declaration of function pointer
|
|
variables and the use of '&' to convert methods into function pointers.
|
|
[ ] Conversions: can we say: "type T int; T(3.0)" ?
|
|
We could allow converting structurally equivalent types into each other this way.
|
|
May play together with "type T1 T2" where we give another type name to T2.
|
|
[ ] Is . import implemented / do we still need it?
|
|
[ ] Do we allow empty statements? If so, do we allow empty statements after a label?
|
|
and if so, does a label followed by an empty statement (a semicolon) still denote
|
|
a for loop that is following, and can break L be used inside it?
|
|
[ ] comparison of non-basic types: what do we allow? what do we allow in interfaces
|
|
what about maps (require ==, copy and hash)
|
|
maybe: no maps with non-basic type keys, and no interface comparison unless
|
|
with nil
|
|
[ ] consider syntactic notation for composite literals to make them parseable w/o type information
|
|
(require ()'s in control clauses)
|
|
|
|
|
|
Decisions in need of integration into the doc:
|
|
[ ] pair assignment is required to get map, and receive ok.
|
|
[ ] len() returns an int, new(array_type, n) n must be an int
|
|
[ ] passing a "..." arg to another "..." parameter doesn't wrap the argument again
|
|
(so "..." args can be passed down easily)
|
|
|
|
|
|
Closed:
|
|
[x] packages of multiple files - we have a working approach
|
|
[x] partial export of structs, methods
|
|
[x] new as it is now is weird - need to go back to previous semantics and introduce
|
|
literals for slices, maps, channels - done
|
|
[x] determine if really necessary to disallow array assignment - allow array assignment
|
|
[x] semantics of statements - we just need to fill in the language, the semantics is mostly clear
|
|
[x] range statement: to be defined more reasonably
|
|
[x] need to be specific on (unsigned) integer operations: one must be able
|
|
to rely on wrap-around on overflow
|
|
[x] global var decls: "var a, b, c int = 0, 0, 0" is ok, but "var a, b, c = 0, 0, 0" is not
|
|
(seems inconsistent with "var a = 0", and ":=" notation)
|
|
[x] const decls: "const a, b = 1, 2" is not allowed - why not? Should be symmetric to vars.
|
|
[x] new(arraytype, n1, n2): spec only talks about length, not capacity
|
|
(should only use new(arraytype, n) - this will allow later
|
|
extension to multi-dim arrays w/o breaking the language) - documented
|
|
[x] should we have a shorter list of alias types? (byte, int, uint, float) - done
|
|
[x] reflection support
|
|
[x] syntax for var args
|
|
[x] Do composite literals create a new literal each time (gri thinks yes) (Russ is putting in a change
|
|
to this effect, essentially)
|
|
[x] comparison operators: can we compare interfaces?
|
|
[x] can we add methods to types defined in another package? (probably not)
|
|
[x] optional semicolons: too complicated and unclear
|
|
[x] anonymous types are written using a type name, which can be a qualified identifier.
|
|
this might be a problem when referring to such a field using the type name.
|
|
[x] nil and interfaces - can we test for nil, what does it mean, etc.
|
|
[x] talk about underflow/overflow of 2's complement numbers (defined vs not defined).
|
|
[x] change wording on array composite literals: the types are always fixed arrays
|
|
for array composites
|
|
[x] meaning of nil
|
|
[x] remove "any"
|
|
[x] methods for all types
|
|
[x] should binary <- be at lowest precedence level? when is a send/receive non-blocking? (NO - 9/19/08)
|
|
[x] func literal like a composite type - should probably require the '&' to get address (NO)
|
|
[x] & needed to get a function pointer from a function? (NO - there is the "func" keyword - 9/19/08)
|
|
-->
|
|
|
|
|
|
Contents
|
|
----
|
|
|
|
Introduction
|
|
Guiding principles
|
|
Program structure
|
|
Modularity, identifiers and scopes
|
|
Typing, polymorphism, and object-orientation
|
|
Pointers and garbage collection
|
|
Values and references
|
|
Multithreading and channels
|
|
|
|
Notation
|
|
|
|
Source code representation
|
|
Characters
|
|
Letters and digits
|
|
|
|
Vocabulary
|
|
Identifiers
|
|
Numeric literals
|
|
Character and string literals
|
|
Operators and delimitors
|
|
Reserved words
|
|
|
|
Declarations and scope rules
|
|
Predeclared identifiers
|
|
Exported identifiers
|
|
Const declarations
|
|
Iota
|
|
Type declarations
|
|
Variable declarations
|
|
|
|
Types
|
|
Basic types
|
|
Arithmetic types
|
|
Booleans
|
|
Strings
|
|
Array types
|
|
Struct types
|
|
Pointer types
|
|
Function types
|
|
Interface types
|
|
Slice types
|
|
Map types
|
|
Channel types
|
|
Type equality
|
|
|
|
Expressions
|
|
Operands
|
|
Constants
|
|
Qualified identifiers
|
|
Composite Literals
|
|
Function Literals
|
|
|
|
Primary expressions
|
|
Selectors
|
|
Indexes
|
|
Slices
|
|
Type guards
|
|
Calls
|
|
Parameter passing
|
|
|
|
Operators
|
|
Arithmetic operators
|
|
Integer overflow
|
|
Comparison operators
|
|
Logical operators
|
|
Address operators
|
|
Communication operators
|
|
|
|
Constant expressions
|
|
|
|
Statements
|
|
Label declarations
|
|
Expression statements
|
|
IncDec statements
|
|
Assignments
|
|
If statements
|
|
Switch statements
|
|
For statements
|
|
Go statements
|
|
Select statements
|
|
Return statements
|
|
Break statements
|
|
Continue statements
|
|
Label declaration
|
|
Goto statements
|
|
|
|
Function declarations
|
|
Method declarations
|
|
Predeclared functions
|
|
Length and capacity
|
|
Conversions
|
|
Allocation
|
|
Making slices, maps, and channels
|
|
|
|
Packages
|
|
|
|
Program initialization and execution
|
|
|
|
|
|
----
|
|
|
|
Introduction
|
|
----
|
|
|
|
Go is a new systems programming language intended as an alternative to C++ at
|
|
Google. Its main purpose is to provide a productive and efficient programming
|
|
environment for compiled programs such as servers and distributed systems.
|
|
|
|
|
|
Guiding principles
|
|
----
|
|
|
|
The design of Go is motivated by the following goals (in no particular order):
|
|
|
|
- very fast compilation, instantaneous incremental compilation
|
|
- strongly typed
|
|
- procedural
|
|
- concise syntax avoiding repetition
|
|
- few, orthogonal, and general concepts
|
|
- support for threading and interprocess communication
|
|
- garbage collection
|
|
- container library written in Go
|
|
- efficient code, comparable to other compiled languages
|
|
|
|
|
|
Program structure
|
|
----
|
|
|
|
A Go program consists of a number of ``packages''.
|
|
|
|
A package is built from one or more source files, each of which consists
|
|
of a package specifier followed by declarations. There are no statements at
|
|
the top level of a file.
|
|
|
|
By convention, the package called "main" is the starting point for execution.
|
|
It contains a function, also called "main", that is the first function invoked
|
|
by the run time system after initialization (if a source file within the program
|
|
contains a function "init()", that function will be executed before "main.main()"
|
|
is called).
|
|
|
|
Source files can be compiled separately (without the source code of packages
|
|
they depend on), but not independently (the compiler does check dependencies
|
|
by consulting the symbol information in compiled packages).
|
|
|
|
|
|
Modularity, identifiers and scopes
|
|
----
|
|
|
|
A package is a collection of import, constant, type, variable, and function
|
|
declarations. Each declaration binds an ``identifier'' with a program entity
|
|
(such as a variable).
|
|
|
|
In particular, all identifiers occurring in a package are either declared
|
|
explicitly within the package, arise from an import declaration, or belong
|
|
to a small set of predeclared identifiers (such as "string").
|
|
|
|
Scoping follows the usual rules: The scope of an identifier declared within
|
|
a ``block'' generally extends from the declaration of the identifier to the
|
|
end of the block. An identifier shadows identifiers with the same name declared
|
|
in outer scopes. Within a scope, an identifier can be declared at most once.
|
|
|
|
Identifiers may be ``internal'' or ``exported''. Internal identifiers are only
|
|
accessible to files belonging to the package in which they are declared.
|
|
External identifiers are accessible to other packages.
|
|
|
|
|
|
Typing, polymorphism, and object-orientation
|
|
----
|
|
|
|
Go programs are strongly typed. Certain variables may be polymorphic.
|
|
The language provides mechanisms to make use of such polymorphic variables
|
|
type-safe.
|
|
|
|
Object-oriented programming is supported by interface types.
|
|
Different interface types are independent of each
|
|
other and no explicit hierarchy is required (such as single or
|
|
multiple inheritance explicitly specified through respective type
|
|
declarations). Interface types only define a set of methods that a
|
|
corresponding implementation must provide. Thus interface and
|
|
implementation are strictly separated.
|
|
|
|
An interface is implemented by associating methods with types. If a type
|
|
defines all methods of an interface, it implements that interface and thus
|
|
can be used where that interface is required. Unless used through a variable
|
|
of interface type, methods can always be statically bound (they are not
|
|
``virtual''), and invoking them incurs no extra run-time overhead compared
|
|
to ordinary functions.
|
|
|
|
Go has no explicit notion of classes, sub-classes, or inheritance.
|
|
These concepts are trivially modeled in Go through the use of
|
|
functions, structures, embedding of types, associated methods, and interfaces.
|
|
|
|
Go has no explicit notion of type parameters or templates. Instead,
|
|
containers (such as stacks, lists, etc.) are implemented through the
|
|
use of abstract operations on interface types.
|
|
|
|
|
|
Pointers and garbage collection
|
|
----
|
|
|
|
Variables may be allocated automatically (when entering the scope of
|
|
the variable) or explicitly on the heap. Pointers are used to refer
|
|
to heap-allocated variables. Pointers may also be used to point to
|
|
any other variable; such a pointer is obtained by "taking the
|
|
address" of that variable. Variables are automatically reclaimed when
|
|
they are no longer accessible. There is no pointer arithmetic in Go.
|
|
|
|
|
|
Values and references
|
|
----
|
|
|
|
Most data types have value semantics, but their contents may be accessed
|
|
through different pointers referring to the same object. However, some
|
|
data types have reference semantics to facilitate common usage patterns
|
|
and implementation.
|
|
|
|
For example, when calling a function with a struct, the struct is passed
|
|
by value, possibly by making a copy. To pass a reference, one must explicitly
|
|
pass a pointer to the struct. On the other hand, when calling a function with
|
|
a map, a reference to the map is passed implicitly without the need to pass a
|
|
pointer to the map; thus the map contents are not copied when a map is assigned
|
|
to a variable.
|
|
|
|
|
|
Multithreading and channels
|
|
----
|
|
|
|
Go supports multithreaded programming directly. A function may
|
|
be invoked as a parallel thread of execution. Communication and
|
|
synchronization are provided through channels and their associated
|
|
language support.
|
|
|
|
|
|
----
|
|
|
|
Notation
|
|
----
|
|
|
|
The syntax is specified using Extended Backus-Naur Form (EBNF):
|
|
|
|
Production = production_name "=" Expression .
|
|
Expression = Alternative { "|" Alternative } .
|
|
Alternative = Term { Term } .
|
|
Term = production_name | token [ "..." token ] | Group | Option | Repetition .
|
|
Group = "(" Expression ")" .
|
|
Option = "[" Expression ")" .
|
|
Repetition = "{" Expression "}" .
|
|
|
|
Productions are expressions constructed from terms and the following operators:
|
|
|
|
| separates alternatives (least binding strength)
|
|
() groups
|
|
[] specifies an option (0 or 1 times)
|
|
{} specifies repetition (0 to n times)
|
|
|
|
Lower-case production names are used to identify productions that cannot
|
|
be broken by white space or comments; they are tokens. Other production
|
|
names are in CamelCase.
|
|
|
|
Tokens (lexical symbols) are enclosed in double quotes '''' (the
|
|
double quote symbol is written as ''"'').
|
|
|
|
The form "a ... b" represents the set of characters from "a" through "b" as
|
|
alternatives.
|
|
|
|
Where possible, recursive productions are used to express evaluation order
|
|
and operator precedence syntactically (for instance for expressions).
|
|
|
|
A production may be referenced from various places in this document
|
|
but is usually defined close to its first use. Productions and code
|
|
examples are indented.
|
|
|
|
----
|
|
|
|
Source code representation
|
|
----
|
|
|
|
Source code is Unicode text encoded in UTF-8.
|
|
|
|
Tokenization follows the usual rules. Source text is case-sensitive.
|
|
|
|
White space is blanks, newlines, carriage returns, or tabs.
|
|
|
|
Comments are // to end of line or /* */ without nesting and are treated as white space.
|
|
|
|
Some Unicode characters (e.g., the character U+00E4) may be representable in
|
|
two forms, as a single code point or as two code points. For simplicity of
|
|
implementation, Go treats these as distinct characters: each Unicode code
|
|
point is a single character in Go.
|
|
|
|
|
|
Characters
|
|
----
|
|
|
|
The following terms are used to denote specific Unicode character classes:
|
|
|
|
unicode_char an arbitrary Unicode code point
|
|
unicode_letter a Unicode code point classified as "Letter"
|
|
capital_letter a Unicode code point classified as "Letter, uppercase"
|
|
|
|
(The Unicode Standard, Section 4.5 General Category - Normative.)
|
|
|
|
|
|
Letters and digits
|
|
----
|
|
|
|
letter = unicode_letter | "_" .
|
|
decimal_digit = "0" ... "9" .
|
|
octal_digit = "0" ... "7" .
|
|
hex_digit = "0" ... "9" | "A" ... "F" | "a" ... "f" .
|
|
|
|
|
|
----
|
|
|
|
Vocabulary
|
|
----
|
|
|
|
Tokens make up the vocabulary of the Go language. They consist of
|
|
identifiers, numbers, strings, operators, and delimitors.
|
|
|
|
|
|
Identifiers
|
|
----
|
|
|
|
An identifier is a name for a program entity such as a variable, a
|
|
type, a function, etc.
|
|
|
|
identifier = letter { letter | decimal_digit } .
|
|
|
|
Exported identifiers (§Exported identifiers) start with a capital_letter.
|
|
|
|
a
|
|
_x9
|
|
ThisVariableIsExported
|
|
αβ
|
|
|
|
Some identifiers are predeclared (§Predeclared identifiers).
|
|
|
|
|
|
Numeric literals
|
|
----
|
|
|
|
An integer literal represents a mathematically ideal integer constant
|
|
of arbitrary precision, or 'ideal int'.
|
|
|
|
int_lit = decimal_int | octal_int | hex_int .
|
|
decimal_int = ( "1" ... "9" ) { decimal_digit } .
|
|
octal_int = "0" { octal_digit } .
|
|
hex_int = "0" ( "x" | "X" ) hex_digit { hex_digit } .
|
|
|
|
42
|
|
0600
|
|
0xBadFace
|
|
170141183460469231731687303715884105727
|
|
|
|
A floating point literal represents a mathematically ideal floating point
|
|
constant of arbitrary precision, or 'ideal float'.
|
|
|
|
float_lit =
|
|
decimals "." [ decimals ] [ exponent ] |
|
|
decimals exponent |
|
|
"." decimals [ exponent ] .
|
|
decimals = decimal_digit { decimal_digit } .
|
|
exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
|
|
|
|
0.
|
|
2.71828
|
|
1.e+0
|
|
6.67428e-11
|
|
1E6
|
|
.25
|
|
.12345E+5
|
|
|
|
Numeric literals are unsigned. A negative constant is formed by
|
|
applying the unary prefix operator "-" (§Arithmetic operators).
|
|
|
|
An 'ideal number' is either an 'ideal int' or an 'ideal float'.
|
|
|
|
Only when an ideal number (or an arithmetic expression formed
|
|
solely from ideal numbers) is bound to a variable or used in an expression
|
|
or constant of fixed-size integers or floats it is required to fit
|
|
a particular size. In other words, ideal numbers and arithmetic
|
|
upon them are not subject to overflow; only use of them in assignments
|
|
or expressions involving fixed-size numbers may cause overflow, and thus
|
|
an error (§Expressions).
|
|
|
|
Implementation restriction: A compiler may implement ideal numbers
|
|
by choosing a "sufficiently large" internal representation of such
|
|
numbers.
|
|
|
|
|
|
Character and string literals
|
|
----
|
|
|
|
Character and string literals are almost the same as in C, with the
|
|
following differences:
|
|
|
|
- The encoding is UTF-8
|
|
- `` strings exist; they do not interpret backslashes
|
|
- Octal character escapes are always 3 digits ("\077" not "\77")
|
|
- Hexadecimal character escapes are always 2 digits ("\x07" not "\x7")
|
|
|
|
The rules are:
|
|
|
|
char_lit = "'" ( unicode_value | byte_value ) "'" .
|
|
unicode_value = unicode_char | little_u_value | big_u_value | escaped_char .
|
|
byte_value = octal_byte_value | hex_byte_value .
|
|
octal_byte_value = "\" octal_digit octal_digit octal_digit .
|
|
hex_byte_value = "\" "x" hex_digit hex_digit .
|
|
little_u_value = "\" "u" hex_digit hex_digit hex_digit hex_digit .
|
|
big_u_value =
|
|
"\" "U" hex_digit hex_digit hex_digit hex_digit
|
|
hex_digit hex_digit hex_digit hex_digit .
|
|
escaped_char = "\" ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | "\" | "'" | """ ) .
|
|
|
|
A unicode_value takes one of four forms:
|
|
|
|
* The UTF-8 encoding of a Unicode code point. Since Go source
|
|
text is in UTF-8, this is the obvious translation from input
|
|
text into Unicode characters.
|
|
* The usual list of C backslash escapes: "\n", "\t", etc.
|
|
Within a character or string literal, only the corresponding quote character
|
|
is a legal escape (this is not explicitly reflected in the above syntax).
|
|
* A `little u' value, such as "\u12AB". This represents the Unicode
|
|
code point with the corresponding hexadecimal value. It always
|
|
has exactly 4 hexadecimal digits.
|
|
* A `big U' value, such as "\U00101234". This represents the
|
|
Unicode code point with the corresponding hexadecimal value.
|
|
It always has exactly 8 hexadecimal digits.
|
|
|
|
Some values that can be represented this way are illegal because they
|
|
are not valid Unicode code points. These include values above
|
|
0x10FFFF and surrogate halves.
|
|
|
|
An octal_byte_value contains three octal digits. A hex_byte_value
|
|
contains two hexadecimal digits. (Note: This differs from C but is
|
|
simpler.)
|
|
|
|
It is erroneous for an octal_byte_value to represent a value larger than 255.
|
|
(By construction, a hex_byte_value cannot.)
|
|
|
|
A character literal is a form of unsigned integer constant. Its value
|
|
is that of the Unicode code point represented by the text between the
|
|
quotes.
|
|
|
|
'a'
|
|
'ä'
|
|
'本'
|
|
'\t'
|
|
'\000'
|
|
'\007'
|
|
'\377'
|
|
'\x07'
|
|
'\xff'
|
|
'\u12e4'
|
|
'\U00101234'
|
|
|
|
String literals come in two forms: double-quoted and back-quoted.
|
|
Double-quoted strings have the usual properties; back-quoted strings
|
|
do not interpret backslashes at all.
|
|
|
|
string_lit = raw_string_lit | interpreted_string_lit .
|
|
raw_string_lit = "`" { unicode_char } "`" .
|
|
interpreted_string_lit = """ { unicode_value | byte_value } """ .
|
|
|
|
A string literal has type "string" (§Strings). Its value is constructed
|
|
by taking the byte values formed by the successive elements of the
|
|
literal. For byte_values, these are the literal bytes; for
|
|
unicode_values, these are the bytes of the UTF-8 encoding of the
|
|
corresponding Unicode code points. Note that
|
|
"\u00FF"
|
|
and
|
|
"\xFF"
|
|
are
|
|
different strings: the first contains the two-byte UTF-8 expansion of
|
|
the value 255, while the second contains a single byte of value 255.
|
|
The same rules apply to raw string literals, except the contents are
|
|
uninterpreted UTF-8.
|
|
|
|
`abc`
|
|
`\n`
|
|
"hello, world\n"
|
|
"\n"
|
|
""
|
|
"Hello, world!\n"
|
|
"日本語"
|
|
"\u65e5本\U00008a9e"
|
|
"\xff\u00FF"
|
|
|
|
These examples all represent the same string:
|
|
|
|
"日本語" // UTF-8 input text
|
|
`日本語` // UTF-8 input text as a raw literal
|
|
"\u65e5\u672c\u8a9e" // The explicit Unicode code points
|
|
"\U000065e5\U0000672c\U00008a9e" // The explicit Unicode code points
|
|
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // The explicit UTF-8 bytes
|
|
|
|
Adjacent strings separated only by whitespace (including comments)
|
|
are concatenated into a single string. The following two lines
|
|
represent the same string:
|
|
|
|
"Alea iacta est."
|
|
"Alea " /* The die */ `iacta est` /* is cast */ "."
|
|
|
|
The language does not canonicalize Unicode text or evaluate combining
|
|
forms. The text of source code is passed uninterpreted.
|
|
|
|
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 character literal (it is not a single code
|
|
point), and will appear as two code points if placed in a string
|
|
literal.
|
|
|
|
|
|
Operators and delimitors
|
|
----
|
|
|
|
The following special character sequences serve as operators or delimitors:
|
|
|
|
+ & += &= && == != ( )
|
|
- | -= |= || < <= [ ]
|
|
* ^ *= ^= <- > >= { }
|
|
/ << /= <<= ++ = := , ;
|
|
% >> %= >>= -- ! ... . :
|
|
|
|
|
|
Reserved words
|
|
----
|
|
|
|
The following words are reserved and must not be used as identifiers:
|
|
|
|
break default func interface select
|
|
case else go map struct
|
|
chan goto package switch
|
|
const fallthrough if range type
|
|
continue for import return var
|
|
|
|
|
|
----
|
|
|
|
Declarations and scope rules
|
|
----
|
|
|
|
A declaration ``binds'' an identifier to a language entity (such as
|
|
a package, constant, type, struct field, variable, parameter, result,
|
|
function, method) and specifies properties of that entity such as its type.
|
|
|
|
Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .
|
|
|
|
Every identifier in a program must be declared; some identifiers, such as "int"
|
|
and "true", are predeclared (§Predeclared identifiers).
|
|
|
|
The ``scope'' of an identifier is the extent of source text within which the
|
|
identifier denotes the bound entity. No identifier may be declared twice in a
|
|
single scope. Go is lexically scoped: An identifier denotes the entity it is
|
|
bound to only within the scope of the identifier.
|
|
|
|
For instance, for a variable named "x", the scope of identifier "x" is the
|
|
extent of source text within which "x" denotes that particular variable.
|
|
It is illegal to declare another identifier "x" within the same scope.
|
|
|
|
The scope of an identifier depends on the entity declared. The scope for
|
|
an identifier always excludes scopes redeclaring the identifier in nested
|
|
blocks. An identifier declared in a nested block is said to ``shadow'' the
|
|
same identifier declared in an outer block.
|
|
|
|
1. The scope of predeclared identifiers is the entire source file.
|
|
|
|
2. The scope of an identifier denoting a type, function or package
|
|
extends textually from the point of the identifier in the declaration
|
|
to the end of the innermost surrounding block.
|
|
|
|
3. The scope of a constant or variable extends textually from
|
|
after the declaration to the end of the innermost surrounding
|
|
block. If the variable is declared in the init statement of an
|
|
if, for, or switch statement, the innermost surrounding block
|
|
is the block associated with the respective statement.
|
|
|
|
4. The scope of a parameter or result identifier is the body of the
|
|
corresponding function.
|
|
|
|
5. The scope of a field or method identifier is selectors for the
|
|
corresponding type containing the field or method (§Selectors).
|
|
|
|
6. The scope of a label is the body of the innermost surrounding
|
|
function and does not intersect with any non-label scope. Thus,
|
|
each function has its own private label scope.
|
|
|
|
|
|
Predeclared identifiers
|
|
----
|
|
|
|
The following identifiers are predeclared:
|
|
|
|
All basic types:
|
|
|
|
bool, byte, uint8, uint16, uint32, uint64, int8, int16, int32, int64,
|
|
float32, float64, float80, string
|
|
|
|
A set of platform-specific convenience types:
|
|
|
|
uint, int, float, uintptr
|
|
|
|
The predeclared constants:
|
|
|
|
true, false, iota, nil
|
|
|
|
The predeclared functions (note: this list is likely to change):
|
|
|
|
cap(), convert(), len(), make(), new(), panic(), panicln(), print(), println(), typeof(), ...
|
|
|
|
|
|
Exported identifiers
|
|
----
|
|
|
|
Identifiers that start with a capital_letter (§Identifiers) are ``exported'',
|
|
thus making the identifiers accessible outside the current package. A file
|
|
belonging to another package may then import the package (§Packages) and access
|
|
exported identifiers via qualified identifiers (§Qualified identifiers).
|
|
|
|
All other identifiers are ``internal''; they are only visible in files
|
|
belonging to the same package which declares them.
|
|
|
|
TODO: This should be made clearer. For instance, function-local identifiers
|
|
are never exported, but non-global fields/methods may be exported.
|
|
|
|
|
|
Const declarations
|
|
----
|
|
|
|
A constant declaration binds an identifier to the value of a constant
|
|
expression (§Constant expressions).
|
|
|
|
ConstDecl = "const" ( ConstSpec | "(" [ ConstSpecList ] ")" ) .
|
|
ConstSpecList = ConstSpec { ";" ConstSpec } [ ";" ] .
|
|
ConstSpec = IdentifierList [ CompleteType ] [ "=" ExpressionList ] .
|
|
|
|
IdentifierList = identifier { "," identifier } .
|
|
ExpressionList = Expression { "," Expression } .
|
|
|
|
A 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, with the i'th identifier on the left
|
|
corresponding to the i'th expression on the right. If CompleteType is omitted,
|
|
the types of the constants are the types of the corresponding expressions;
|
|
different expressions may have different types. If CompleteType is present,
|
|
the type of all constants is the type specified, and the types of all
|
|
expressions in ExpressionList must be assignment-compatible with the
|
|
constant type.
|
|
|
|
const Pi float64 = 3.14159265358979323846
|
|
const E = 2.718281828
|
|
const (
|
|
size int64 = 1024;
|
|
eof = -1;
|
|
)
|
|
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo"
|
|
const u, v float = 0, 3 // u = 0.0, v = 3.0
|
|
|
|
As a special case, within a parenthesized "const" declaration list the
|
|
ExpressionList may be omitted from any but the first declaration. Such an empty
|
|
ExpressionList is equivalent to the textual substitution of the first preceding
|
|
non-empty ExpressionList in the same "const" declaration list.
|
|
That is, omitting the list of expressions is equivalent to repeating the
|
|
previous list. The number of identifiers must be equal to the number of
|
|
expressions in the previous list.
|
|
|
|
Together with the "iota" constant generator implicit repetition of
|
|
ExpressionLists permit light-weight declaration of enumerated values (§Iota):
|
|
|
|
const (
|
|
Sunday = iota;
|
|
Monday;
|
|
Tuesday;
|
|
Wednesday;
|
|
Thursday;
|
|
Friday;
|
|
Partyday;
|
|
numberOfDays; // this constant in not exported
|
|
)
|
|
|
|
The initializing expression for a numeric constant is evaluated
|
|
using the principles described in the section on numeric literals:
|
|
constants are mathematical values given a size only upon assignment
|
|
to a variable. Intermediate values, and the constants themselves,
|
|
may require precision significantly larger than any concrete type
|
|
in the language. Thus the following is legal:
|
|
|
|
const Huge = 1 << 100;
|
|
const Four int8 = Huge >> 98;
|
|
|
|
A given numeric constant expression is, however, defined to be
|
|
either an integer or a floating point value, depending on the syntax
|
|
of the literals it comprises (123 vs. 1.0e4). This is because the
|
|
nature of the arithmetic operations depends on the type of the
|
|
values; for example, 3/2 is an integer division yielding 1, while
|
|
3./2. is a floating point division yielding 1.5. Thus
|
|
|
|
const x = 3./2. + 3/2;
|
|
|
|
yields a floating point constant of value 2.5 (1.5 + 1); its
|
|
constituent expressions are evaluated using different rules for
|
|
division.
|
|
|
|
If the type is missing from a numeric constant declaration, the constant
|
|
represents a value of abitrary precision, either integer or floating
|
|
point, determined by the type of the initializing expression. Such
|
|
a constant may be assigned to any variable that can represent its
|
|
value accurately, regardless of type. For instance, 3 can be
|
|
assigned to any integer variable but also to any floating point variable,
|
|
while 1e12 can be assigned to a "float32", "float64", or even "int64".
|
|
It is erroneous to assign a value with a non-zero fractional part
|
|
to an integer, or if the assignment would overflow or underflow.
|
|
|
|
|
|
Iota
|
|
----
|
|
|
|
Within a constant declaration, the predeclared operand "iota" represents
|
|
successive elements of an integer sequence. It is reset to 0 whenever the
|
|
reserved word "const" appears in the source and increments with each
|
|
semicolon. For instance, "iota" can be used to construct a set of related
|
|
constants:
|
|
|
|
const ( // iota is set to 0
|
|
enum0 = iota; // sets enum0 to 0, etc.
|
|
enum1 = iota;
|
|
enum2 = iota
|
|
)
|
|
|
|
const (
|
|
a = 1 << iota; // a == 1 (iota has been reset)
|
|
b = 1 << iota; // b == 2
|
|
c = 1 << iota; // c == 4
|
|
)
|
|
|
|
const (
|
|
u = iota * 42; // u == 0 (ideal integer)
|
|
v float = iota * 42; // v == 42.0 (float)
|
|
w = iota * 42; // w == 84 (ideal integer)
|
|
)
|
|
|
|
const x = iota; // x == 0 (iota has been reset)
|
|
const y = iota; // y == 0 (iota has been reset)
|
|
|
|
Within an ExpressionList, the value of all "iota"'s is the same because "iota"
|
|
is only incremented at each semicolon:
|
|
|
|
const (
|
|
base0, mask0 int64 = 1 << iota, i << iota - 1; // base0 == 1, mask0 = 0
|
|
base1, mask1 int64 = 1 << iota, i << iota - 1; // base1 == 2, mask1 = 1
|
|
base2, mask2 int64 = 1 << iota, i << iota - 1; // base2 == 4, mask2 = 3
|
|
)
|
|
|
|
Since the ExpressionList in constant declarations repeats implicitly
|
|
if omitted, some of the examples above can be abbreviated:
|
|
|
|
const (
|
|
enum0 = iota;
|
|
enum1;
|
|
enum2
|
|
)
|
|
|
|
const (
|
|
a = 1 << iota;
|
|
b;
|
|
c;
|
|
)
|
|
|
|
const (
|
|
u = iota * 42;
|
|
v float;
|
|
w;
|
|
)
|
|
|
|
const (
|
|
base0, mask0 int64 = 1 << iota, i << iota - 1;
|
|
base1, mask1 int64;
|
|
base2, mask2 int64;
|
|
)
|
|
|
|
|
|
Type declarations
|
|
----
|
|
|
|
A type declaration specifies a new type and binds an identifier to it.
|
|
The identifier is called the ``type name''; it denotes the type.
|
|
|
|
TypeDecl = "type" ( TypeSpec | "(" [ TypeSpecList ] ")" ) .
|
|
TypeSpecList = TypeSpec { ";" TypeSpec } [ ";" ] .
|
|
TypeSpec = identifier Type .
|
|
|
|
A struct or interface type may be forward-declared (§Struct types,
|
|
§Interface types). A forward-declared type is incomplete (§Types)
|
|
until it is fully declared. The full declaration must must follow
|
|
within the same block containing the forward declaration.
|
|
|
|
type IntArray [16] int
|
|
|
|
type (
|
|
Point struct { x, y float };
|
|
Polar Point
|
|
)
|
|
|
|
type TreeNode struct {
|
|
left, right *TreeNode;
|
|
value Point;
|
|
}
|
|
|
|
type Comparable interface {
|
|
cmp(Comparable) int
|
|
}
|
|
|
|
|
|
Variable declarations
|
|
----
|
|
|
|
A variable declaration creates a variable, binds an identifier to it and
|
|
gives it a type. It may optionally give the variable an initial value.
|
|
The variable type must be a complete type (§Types).
|
|
In some forms of declaration the type of the initial value defines the type
|
|
of the variable.
|
|
|
|
VarDecl = "var" ( VarSpec | "(" [ VarSpecList ] ")" ) .
|
|
VarSpecList = VarSpec { ";" VarSpec } [ ";" ] .
|
|
VarSpec = IdentifierList ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) .
|
|
|
|
var i int
|
|
var U, V, W float
|
|
var k = 0
|
|
var x, y float = -1.0, -2.0
|
|
var (
|
|
i int;
|
|
u, v, s = 2.0, 3.0, "bar"
|
|
)
|
|
|
|
If the expression list is present, it must have the same number of elements
|
|
as there are variables in the variable specification.
|
|
|
|
If the variable type is omitted, an initialization expression (or expression
|
|
list) must be present, and the variable type is the type of the expression
|
|
value (in case of a list of variables, the variables assume the types of the
|
|
corresponding expression values).
|
|
|
|
If the variable type is omitted, and the corresponding initialization expression
|
|
is a constant expression of abstract int or floating point type, the type
|
|
of the variable is "int" or "float" respectively:
|
|
|
|
var i = 0 // i has int type
|
|
var f = 3.1415 // f has float type
|
|
|
|
The syntax
|
|
|
|
SimpleVarDecl = IdentifierList ":=" ExpressionList .
|
|
|
|
is shorthand for
|
|
|
|
"var" IdentifierList = ExpressionList .
|
|
|
|
i, j := 0, 10;
|
|
f := func() int { return 7; }
|
|
ch := new(chan int);
|
|
|
|
Also, in some contexts such as "if", "for", or "switch" statements,
|
|
this construct can be used to declare local temporary variables.
|
|
|
|
|
|
----
|
|
|
|
Types
|
|
----
|
|
|
|
A type specifies the set of values that variables of that type may assume
|
|
and the operators that are applicable.
|
|
|
|
A type may be specified by a type name (§Type declarations) or a type literal.
|
|
A type literal is a syntactic construct that explicitly specifies the
|
|
composition of a new type in terms of other (already declared) types.
|
|
|
|
Type = TypeName | TypeLit .
|
|
TypeName = QualifiedIdent.
|
|
TypeLit =
|
|
ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
|
SliceType | MapType | ChannelType .
|
|
|
|
Some types are predeclared and denoted by their type names; these are called
|
|
``basic types''. Generally (except for strings) they are not composed of more
|
|
elementary types; instead they model elementary machine data types.
|
|
|
|
All other types are called ``composite types'; they are composed from other
|
|
(basic or composite) types and denoted by their type names or by type literals.
|
|
There are arrays, structs, pointers, functions, interfaces, slices, maps, and
|
|
channels.
|
|
|
|
At a given point in the source code, a type may be ``complete'' or
|
|
''incomplete''. Array and struct types are complete when they are fully declared.
|
|
All other types are always complete (although their components, such as the base
|
|
type of a pointer type, may be incomplete). Incomplete types are subject to usage
|
|
restrictions; for instance the type of a variable must be complete where the
|
|
variable is declared.
|
|
|
|
CompleteType = Type .
|
|
|
|
The ``interface'' of a type is the set of methods bound to it
|
|
(§Method declarations). The interface of a pointer type is the interface
|
|
of the pointer base type (§Pointer types). All types have an interface;
|
|
if they have no methods associated with them, their interface is
|
|
called the ``empty'' interface.
|
|
|
|
The ``static type'' (or simply ``type'') of a variable is the type defined by
|
|
the variable's declaration. The ``dynamic type'' of a variable is the actual
|
|
type of the value stored in a variable at run-time. Except for variables of
|
|
interface type, the dynamic type of a variable is always its static type.
|
|
|
|
Variables of interface type may hold values with different dynamic types
|
|
during execution. However, its dynamic type is always compatible with
|
|
the static type of the interface variable (§Interface types).
|
|
|
|
|
|
Basic types
|
|
----
|
|
|
|
Go defines a number of basic types, referred to by their predeclared
|
|
type names. These include traditional arithmetic types, booleans,
|
|
and strings.
|
|
|
|
|
|
Arithmetic types
|
|
----
|
|
|
|
The following list enumerates all platform-independent numeric types:
|
|
|
|
byte same as uint8 (for convenience)
|
|
|
|
uint8 the set of all unsigned 8-bit integers (0 to 255)
|
|
uint16 the set of all unsigned 16-bit integers (0 to 65535)
|
|
uint32 the set of all unsigned 32-bit integers (0 to 4294967295)
|
|
uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615)
|
|
|
|
int8 the set of all signed 8-bit integers (-128 to 127)
|
|
int16 the set of all signed 16-bit integers (-32768 to 32767)
|
|
int32 the set of all signed 32-bit integers (-2147483648 to 2147483647)
|
|
int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
|
|
|
|
float32 the set of all valid IEEE-754 32-bit floating point numbers
|
|
float64 the set of all valid IEEE-754 64-bit floating point numbers
|
|
float80 the set of all valid IEEE-754 80-bit floating point numbers
|
|
|
|
Integer types are represented in the usual binary format; the value of
|
|
an n-bit integer is n bits wide. A negative signed integer is represented
|
|
as the two's complement of its absolute value.
|
|
|
|
<!--
|
|
The representation of signed integers and their exact range is
|
|
implementation-specific, but the set of all positive values (including zero)
|
|
of a signed integer type is always a subset of the corresponding unsigned
|
|
integer type (thus, a positive signed integer can always be converted into
|
|
its corresponding unsigned type without loss).
|
|
-->
|
|
|
|
Additionally, Go declares a set of platform-specific numeric types for
|
|
convenience:
|
|
|
|
uint at least 32 bits, at most the size of the largest uint type
|
|
int at least 32 bits, at most the size of the largest int type
|
|
float at least 32 bits, at most the size of the largest float type
|
|
uintptr smallest uint type large enough to store the uninterpreted
|
|
bits of a pointer value
|
|
|
|
For instance, int might have the same size as int32 on a 32-bit
|
|
architecture, or int64 on a 64-bit architecture.
|
|
|
|
Except for "byte", which is an alias for "uint8", all numeric types
|
|
are different from each other to avoid portability issues. Conversions
|
|
are required when different numeric types are mixed in an expression or assignment.
|
|
For instance, "int32" and "int" are not the same type even though they may have
|
|
the same size on a particular platform.
|
|
|
|
|
|
Booleans
|
|
----
|
|
|
|
The type "bool" comprises the truth values true and false, which are
|
|
available through the two predeclared constants, "true" and "false".
|
|
|
|
|
|
Strings
|
|
----
|
|
|
|
The "string" type represents the set of string values (strings).
|
|
Strings behave like arrays of bytes, with the following properties:
|
|
|
|
- They are immutable: after creation, it is not possible to change the
|
|
contents of a string.
|
|
- No internal pointers: it is illegal to create a pointer to an inner
|
|
element of a string.
|
|
- They can be indexed: given string "s1", "s1[i]" is a byte value.
|
|
- They can be concatenated: given strings "s1" and "s2", "s1 + s2" is a value
|
|
combining the elements of "s1" and "s2" in sequence.
|
|
- Known length: the length of a string "s1" can be obtained by calling
|
|
"len(s1)". The length of a string is the number
|
|
of bytes within. Unlike in C, there is no terminal NUL byte.
|
|
- Creation 1: a string can be created from an integer value by a conversion;
|
|
the result is a string containing the UTF-8 encoding of that code point
|
|
(§Conversions).
|
|
"string('x')" yields "x"; "string(0x1234)" yields the equivalent of "\u1234"
|
|
|
|
- Creation 2: a string can by created from an array of integer values (maybe
|
|
just array of bytes) by a conversion (§Conversions):
|
|
|
|
a [3]byte; a[0] = 'a'; a[1] = 'b'; a[2] = 'c'; string(a) == "abc";
|
|
|
|
|
|
Array types
|
|
----
|
|
|
|
An array is a composite type consisting of a number of elements all of the
|
|
same type, called the element type. The element type must be a complete type
|
|
(§Types). The number of elements of an array is called its length; it is never
|
|
negative. The elements of an array are designated by indices
|
|
which are integers from 0 through the length - 1.
|
|
|
|
ArrayType = "[" ArrayLength "]" ElementType .
|
|
ArrayLength = Expression .
|
|
ElementType = CompleteType .
|
|
|
|
The array length and its value are part of the array type. The array length
|
|
must be a constant expression (§Constant expressions) that evaluates to an
|
|
integer value >= 0.
|
|
|
|
The number of elements of an array "a" can be discovered using the built-in
|
|
function
|
|
|
|
len(a)
|
|
|
|
The length of arrays is known at compile-time, and the result of a call to
|
|
"len(a)" is a compile-time constant.
|
|
|
|
[32]byte
|
|
[2*N] struct { x, y int32 }
|
|
[1000]*float64
|
|
|
|
Assignment compatibility: Arrays can be assigned to slice variables of
|
|
equal element type; arrays cannot be assigned to other array variables
|
|
or passed to functions (by value).
|
|
TODO rethink this restriction. Causes irregularities.
|
|
|
|
|
|
Struct types
|
|
----
|
|
|
|
A struct is a composite type consisting of a fixed number of elements,
|
|
called fields, with possibly different types. A struct type declares
|
|
an identifier and type for each field. Within a struct type no field
|
|
identifier may be declared twice and all field types must be complete
|
|
types (§Types).
|
|
|
|
StructType = "struct" [ "{" [ FieldDeclList ] "}" ] .
|
|
FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] .
|
|
FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
|
|
Tag = string_lit .
|
|
|
|
// An empty struct.
|
|
struct {}
|
|
|
|
// A struct with 5 fields.
|
|
struct {
|
|
x, y int;
|
|
u float;
|
|
A *[]int;
|
|
F *();
|
|
}
|
|
|
|
A struct may contain ``anonymous fields'', which are declared with a type
|
|
but no explicit field identifier. An anonymous field type must be specified as
|
|
a type name "T", or as a pointer to a type name ``*T'', and T itself may not be
|
|
a pointer or interface type. The unqualified type name acts as the field identifier.
|
|
|
|
// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
|
|
struct {
|
|
T1; // the field name is T1
|
|
*T2; // the field name is T2
|
|
P.T3; // the field name is the unqualified type name T3
|
|
*P.T4; // the field name is the unqualified type name T4
|
|
x, y int;
|
|
}
|
|
|
|
The unqualified type name of an anonymous field must not conflict with the
|
|
field identifier (or unqualified type name for an anonymous field) of any
|
|
other field within the struct. The following declaration is illegal:
|
|
|
|
struct {
|
|
T; // conflicts with anonymous field *T and *P.T
|
|
*T; // conflicts with anonymous field T and *P.T
|
|
*P.T; // conflicts with anonymous field T and *T
|
|
}
|
|
|
|
Fields and methods (§Method declarations) of an anonymous field become directly
|
|
accessible as fields and methods of the struct without the need to provide the
|
|
type name of the respective anonymous field (§Selectors).
|
|
|
|
A field declaration may be followed by an optional string literal tag which
|
|
becomes an ``attribute'' for all the identifiers in the corresponding
|
|
field declaration. The tags are available via the reflection library but
|
|
are ignored otherwise. A tag may contain arbitrary application-specific
|
|
information.
|
|
|
|
// A struct corresponding to the EventIdMessage protocol buffer.
|
|
// The tag strings contain the protocol buffer field tags.
|
|
struct {
|
|
time_usec uint64 "1";
|
|
server_ip uint32 "2";
|
|
process_id uint32 "3";
|
|
}
|
|
|
|
Forward declaration:
|
|
A struct type consisting of only the reserved word "struct" may be used in
|
|
a type declaration; it declares an incomplete struct type (§Type declarations).
|
|
This allows the construction of mutually recursive types such as:
|
|
|
|
type S2 struct // forward declaration of S2
|
|
type S1 struct { s2 *S2 }
|
|
type S2 struct { s1 *S1 }
|
|
|
|
Assignment compatibility: Structs are assignment compatible to variables of
|
|
equal type only.
|
|
|
|
|
|
Pointer types
|
|
----
|
|
|
|
A pointer type denotes the set of all pointers to variables of a given
|
|
type, called the ``base type'' of the pointer, and the value "nil".
|
|
|
|
PointerType = "*" BaseType .
|
|
BaseType = Type .
|
|
|
|
*int
|
|
map[string] chan
|
|
|
|
The pointer base type may be denoted by an identifier referring to an
|
|
incomplete type (§Types), possibly declared via a forward declaration.
|
|
This allows the construction of recursive and mutually recursive types
|
|
such as:
|
|
|
|
type S struct { s *S }
|
|
|
|
type S2 struct // forward declaration of S2
|
|
type S1 struct { s2 *S2 }
|
|
type S2 struct { s1 *S1 }
|
|
|
|
Assignment compatibility: A pointer is assignment compatible to a variable
|
|
of pointer type, only if both types are equal.
|
|
|
|
Pointer arithmetic of any kind is not permitted.
|
|
|
|
|
|
Function types
|
|
----
|
|
|
|
A function type denotes the set of all functions with the same parameter
|
|
and result types.
|
|
|
|
FunctionType = "(" [ ParameterList ] ")" [ Result ] .
|
|
ParameterList = ParameterDecl { "," ParameterDecl } .
|
|
ParameterDecl = [ IdentifierList ] ( Type | "..." ) .
|
|
Result = Type | "(" ParameterList ")" .
|
|
|
|
In ParameterList, the parameter names (IdentifierList) either must all be
|
|
present, or all be absent. If the parameters are named, each name stands
|
|
for one parameter of the specified type. If the parameters are unnamed, each
|
|
type stands for one parameter of that type.
|
|
|
|
For the last incoming parameter only, instead of a parameter type one
|
|
may write "...". The ellipsis indicates that the last parameter stands
|
|
for an arbitrary number of additional arguments of any type (including
|
|
no additional arguments). If the parameters are named, the identifier
|
|
list immediately preceding "..." must contain only one identifier (the
|
|
name of the last parameter).
|
|
|
|
()
|
|
(x int)
|
|
() int
|
|
(string, float, ...)
|
|
(a, b int, z float) bool
|
|
(a, b int, z float) (bool)
|
|
(a, b int, z float, opt ...) (success bool)
|
|
(int, int, float) (float, *[]int)
|
|
|
|
A variable can hold only a pointer to a function, not a function value.
|
|
In particular, v := func() {} creates a variable of type *(). To call the
|
|
function referenced by v, one writes v(). It is illegal to dereference a
|
|
function pointer.
|
|
|
|
Assignment compatibility: A function pointer can be assigned to a function
|
|
(pointer) variable only if both function types are equal.
|
|
|
|
|
|
Interface types
|
|
----
|
|
|
|
Type interfaces may be specified explicitly by interface types.
|
|
An interface type denotes the set of all types that implement at least
|
|
the set of methods specified by the interface type, and the value "nil".
|
|
|
|
InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] .
|
|
MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] .
|
|
MethodSpec = IdentifierList FunctionType .
|
|
|
|
// An interface specifying a basic File type.
|
|
interface {
|
|
Read, Write (b Buffer) bool;
|
|
Close ();
|
|
}
|
|
|
|
Any type (including interface types) whose interface has, possibly as a
|
|
subset, the complete set of methods of an interface I is said to implement
|
|
interface I. For instance, if two types S1 and S2 have the methods
|
|
|
|
func (p T) Read(b Buffer) bool { return ... }
|
|
func (p T) Write(b Buffer) bool { return ... }
|
|
func (p T) Close() { ... }
|
|
|
|
(where T stands for either S1 or S2) then the File interface is
|
|
implemented by both S1 and S2, regardless of what other methods
|
|
S1 and S2 may have or share.
|
|
|
|
All types implement the empty interface:
|
|
|
|
interface {}
|
|
|
|
In general, a type implements an arbitrary number of interfaces.
|
|
For instance, consider the interface
|
|
|
|
type Lock interface {
|
|
Lock, Unlock ();
|
|
}
|
|
|
|
If S1 and S2 also implement
|
|
|
|
func (p T) Lock() { ... }
|
|
func (p T) Unlock() { ... }
|
|
|
|
they implement the Lock interface as well as the File interface.
|
|
|
|
Forward declaration:
|
|
A interface type consisting of only the reserved word "interface" may be used in
|
|
a type declaration; it declares an incomplete interface type (§Type declarations).
|
|
This allows the construction of mutually recursive types such as:
|
|
|
|
type T2 interface
|
|
type T1 interface {
|
|
foo(T2) int;
|
|
}
|
|
type T2 interface {
|
|
bar(T1) int;
|
|
}
|
|
|
|
Assignment compatibility: A value can be assigned to an interface variable
|
|
if the static type of the value implements the interface or if the value is "nil".
|
|
|
|
|
|
Slice types
|
|
----
|
|
|
|
A slice type denotes the set of all slices (segments) of arrays
|
|
(§Array types) of a given element type, and the value "nil".
|
|
The number of elements of a slice is called its length; it is never negative.
|
|
The elements of a slice are designated by indices which are
|
|
integers from 0 through the length - 1.
|
|
|
|
SliceType = "[" "]" ElementType .
|
|
|
|
Syntactically and semantically, arrays and slices look and behave very
|
|
similarly, but with one important difference: A slice is a descriptor
|
|
of an array segment; in particular, different variables of a slice type may
|
|
refer to different (and possibly overlapping) segments of the same underlying
|
|
array. Thus, with respect to the underlying array, slices behave like
|
|
references. In contrast, two different variables of array type always
|
|
denote two different arrays.
|
|
|
|
For slices, the actual array underlying the slice may extend past the current
|
|
slice length; the maximum length a slice may assume is called its capacity.
|
|
The capacity of any slice "a" can be discovered using the built-in function
|
|
|
|
cap(a)
|
|
|
|
and the following relationship between "len()" and "cap()" holds:
|
|
|
|
0 <= len(a) <= cap(a)
|
|
|
|
The value of an uninitialized slice is "nil", and its length and capacity
|
|
are 0. A new, initialized slice value for a given element type T is
|
|
made using the built-in function "make", which takes a slice type
|
|
and parameters specifying the length and optionally the capacity:
|
|
|
|
make([]T, length)
|
|
make([]T, length, capacity)
|
|
|
|
The "make()" call allocates a new underlying array to which the returned
|
|
slice value refers. More precisely, calling "make"
|
|
|
|
make([]T, length, capacity)
|
|
|
|
is effectively the same as allocating an array and slicing it
|
|
|
|
new([capacity]T)[0 : length]
|
|
|
|
Assignment compatibility: Slices are assignment compatible to variables
|
|
of the same type.
|
|
|
|
Indexing: Given a (pointer to) a slice variable "a", a slice element is
|
|
specified with an index operation:
|
|
|
|
a[i]
|
|
|
|
This denotes the slice element at index "i". "i" must be within bounds,
|
|
that is "0 <= i < len(a)".
|
|
|
|
Slicing: Given a a slice variable "a", a sub-slice is created with a slice
|
|
operation:
|
|
|
|
a[i : j]
|
|
|
|
This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]"
|
|
(that is, excluding "a[j]"). "i" must be within array bounds, and "j" must satisfy
|
|
"i <= j <= cap(a)". The length of the new slice is "j - i". The capacity of
|
|
the slice is "cap(a) - i"; thus if "i" is 0, the slice capacity does not change
|
|
as a result of a slice operation. The type of a sub-slice is the same as the
|
|
type of the slice. Unlike the capacity, the length of a sub-slice
|
|
may be larger than the length of the original slice.
|
|
|
|
TODO what are the proper restrictions on slices?
|
|
TODO describe equality checking against nil
|
|
|
|
|
|
Map types
|
|
----
|
|
|
|
A map is a composite type consisting of a variable number of entries
|
|
called (key, value) pairs. For a given map, the keys and values must
|
|
each be of a specific complete type (§Types) called the key and value type,
|
|
respectively. The number of entries in a map is called its length; it is never
|
|
negative.
|
|
|
|
MapType = "map" "[" KeyType "]" ValueType .
|
|
KeyType = CompleteType .
|
|
ValueType = CompleteType .
|
|
|
|
Upon creation, a map is empty and values may be added and removed
|
|
during execution.
|
|
|
|
map [string] int
|
|
map [struct { pid int; name string }] chan Buffer
|
|
map [string] interface {}
|
|
|
|
The length of a map "m" can be discovered using the built-in function
|
|
|
|
len(m)
|
|
|
|
The value of an uninitialized map is "nil". A new, empty map
|
|
value for given key and value types K and V is made using the built-in
|
|
function "make" which takes the map type and an (optional) capacity as arguments:
|
|
|
|
my_map := make(map[K] V, 100);
|
|
|
|
The map capacity is an allocation hint for more efficient incremental growth
|
|
of the map.
|
|
|
|
Assignment compatibility: A map type is assignment compatible to a variable of
|
|
map type only if both types are equal.
|
|
|
|
TODO: Comparison against nil
|
|
|
|
|
|
Channel types
|
|
----
|
|
|
|
A channel provides a mechanism for two concurrently executing functions
|
|
to synchronize execution and exchange values of a specified type. This
|
|
type must be a complete type (§Types). (TODO could it be incomplete?)
|
|
|
|
ChannelType = Channel | SendChannel | RecvChannel .
|
|
Channel = "chan" ValueType .
|
|
SendChannel = "chan" "<-" ValueType .
|
|
RecvChannel = "<-" "chan" ValueType .
|
|
|
|
Upon creation, a channel can be used both to send and to receive.
|
|
By conversion or assignment, a channel may be constrained only to send or
|
|
to receive. This constraint is called a channel's ``direction''; either
|
|
bi-directional (unconstrained), send, or receive.
|
|
|
|
chan T // can send and receive values of type T
|
|
chan <- float // can only be used to send floats
|
|
<-chan int // can only receive ints
|
|
|
|
The value of an uninitialized channel is "nil". A new, initialized channel
|
|
value for a given element type T is made using the built-in function "make",
|
|
which takes the channel type and an optional capacity as arguments:
|
|
|
|
my_chan = make(chan int, 100);
|
|
|
|
The capacity sets the size of the buffer in the communication channel. If the
|
|
capacity is greater than zero, the channel is asynchronous and, provided the
|
|
buffer is not full, sends can succeed without blocking. If the capacity is zero,
|
|
the communication succeeds only when both a sender and receiver are ready.
|
|
|
|
Assignment compatibility:
|
|
TODO write this paragraph
|
|
|
|
TODO(gri): Do we need the channel conversion? It's enough to just keep
|
|
the assignment rule.
|
|
|
|
|
|
Type equality
|
|
----
|
|
|
|
Types may be ``different'', ``structurally equal'', or ``identical''.
|
|
Go is a type-safe language; generally different types cannot be mixed
|
|
in binary operations, and values cannot be assigned to variables of different
|
|
types. However, values may be assigned to variables of structually
|
|
equal types. Finally, type guards succeed only if the dynamic type
|
|
is identical to or implements the type tested against (§Type guards).
|
|
|
|
Structural type equality (equality for short) is defined by these rules:
|
|
|
|
Two type names denote equal types if the types in the corresponding declarations
|
|
are equal. Two type literals specify equal types if they have the same
|
|
literal structure and corresponding components have equal types. Loosely
|
|
speaking, two types are equal if their values have the same layout in memory.
|
|
More precisely:
|
|
|
|
- Two array types are equal if they have equal element types and if they
|
|
have the same array length.
|
|
|
|
- Two struct types are equal if they have the same number of fields in the
|
|
same order, corresponding fields are either both named or both anonymous,
|
|
and corresponding field types are equal. Note that field names
|
|
do not have to match.
|
|
|
|
- Two pointer types are equal if they have equal base types.
|
|
|
|
- Two function types are equal if they have the same number of parameters
|
|
and result values and if corresponding parameter and result types are
|
|
equal (a "..." parameter is equal to another "..." parameter).
|
|
Note that parameter and result names do not have to match.
|
|
|
|
- Two slice types are equal if they have equal element types.
|
|
|
|
- Two channel types are equal if they have equal value types and
|
|
the same direction.
|
|
|
|
- Two map types are equal if they have equal key and value types.
|
|
|
|
- Two interface types are equal if they have the same set of methods
|
|
with the same names and equal function types. Note that the order
|
|
of the methods in the respective type declarations is irrelevant.
|
|
|
|
|
|
Type identity is defined by these rules:
|
|
|
|
Two type names denote identical types if they originate in the same
|
|
type declaration. Two type literals specify identical types if they have the
|
|
same literal structure and corresponding components have identical types.
|
|
More precisely:
|
|
|
|
- Two array types are identical if they have identical element types and if
|
|
they have the same array length.
|
|
|
|
- Two struct types are identical if they have the same number of fields in
|
|
the same order, corresponding fields either have both the same name or
|
|
are both anonymous, and corresponding field types are identical.
|
|
|
|
- Two pointer types are identical if they have identical base types.
|
|
|
|
- Two function types are identical if they have the same number of
|
|
parameters and result values both with the same (or absent) names, and
|
|
if corresponding parameter and result types are identical (a "..."
|
|
parameter is identical to another "..." parameter with the same name).
|
|
|
|
- Two slice types are identical if they have identical element types.
|
|
|
|
- Two channel types are identical if they have identical value types and
|
|
the same direction.
|
|
|
|
- Two map types are identical if they have identical key and value types.
|
|
|
|
- Two interface types are identical if they have the same set of methods
|
|
with the same names and identical function types. Note that the order
|
|
of the methods in the respective type declarations is irrelevant.
|
|
|
|
Note that the type denoted by a type name is identical only to the type literal
|
|
in the type name's declaration.
|
|
|
|
Finally, two types are different if they are not structurally equal.
|
|
(By definition, they cannot be identical, either).
|
|
|
|
For instance, given the declarations
|
|
|
|
type (
|
|
T0 []string;
|
|
T1 []string
|
|
T2 struct { a, b int };
|
|
T3 struct { a, c int };
|
|
T4 *(int, float) *T0
|
|
T5 *(x int, y float) *[]string
|
|
)
|
|
|
|
these are some types that are equal
|
|
|
|
T0 and T0
|
|
T0 and []string
|
|
T2 and T3
|
|
T4 and T5
|
|
T3 and struct { a int; int }
|
|
|
|
and these are some types that are identical
|
|
|
|
T0 and T0
|
|
[]int and []int
|
|
struct { a, b *T5 } and struct { a, b *T5 }
|
|
|
|
As an example, "T0" and "T1" are equal but not identical because they have
|
|
different declarations.
|
|
|
|
|
|
----
|
|
|
|
Expressions
|
|
----
|
|
|
|
An expression specifies the computation of a value via the application of
|
|
operators and function invocations on operands. An expression has a value and
|
|
a type.
|
|
|
|
The type of a constant expression may be an ideal number. The type of such expressions
|
|
is implicitly converted into the 'expected numeric type' required for the expression.
|
|
The conversion is legal if the (ideal) expression value is a member of the
|
|
set represented by the expected numeric type. In all other cases, and specifically
|
|
if the expected type is not a numeric type, the expression is erroneous.
|
|
|
|
For instance, if the expected numeric type is a uint32, any ideal number
|
|
which fits into a uint32 without loss of precision can be legally converted.
|
|
Thus, the values 991, 42.0, and 1e9 are ok, but -1, 3.14, or 1e100 are not.
|
|
|
|
<!--
|
|
TODO(gri) This may be overly constraining. What about "len(a) + c" where
|
|
c is an ideal number? Is len(a) of type int, or of an ideal number? Probably
|
|
should be ideal number, because for arrays, it is a constant.
|
|
-->
|
|
|
|
|
|
Operands
|
|
----
|
|
|
|
Operands denote the elementary values in an expression.
|
|
|
|
Operand = Literal | QualifiedIdent | "(" Expression ")" .
|
|
Literal = BasicLit | CompositeLit | FunctionLit .
|
|
BasicLit = int_lit | float_lit | char_lit | string_lit .
|
|
|
|
|
|
Constants
|
|
----
|
|
|
|
An operand is called ``constant'' if it is a literal of a basic type
|
|
(including the predeclared constants "true" and "false", and the values
|
|
denoted by "iota"), the predeclared constant "nil", or a parenthesized
|
|
constant expression (§Constant expressions). Constants have values that
|
|
are known at compile-time.
|
|
|
|
|
|
Qualified identifiers
|
|
----
|
|
|
|
A qualified identifier is an identifier qualified by a package name.
|
|
|
|
TODO(gri) expand this section.
|
|
|
|
QualifiedIdent = { PackageName "." } identifier .
|
|
PackageName = identifier .
|
|
|
|
|
|
Composite Literals
|
|
----
|
|
|
|
Literals for composite data structures consist of the type of the value
|
|
followed by a braced expression list for array, slice, and structure literals,
|
|
or a list of expression pairs for map literals.
|
|
|
|
CompositeLit = LiteralType "{" [ ( ExpressionList | ExprPairList ) [ "," ] ] "}" .
|
|
LiteralType = Type | "[" "..." "]" ElementType .
|
|
ExprPairList = ExprPair { "," ExprPair } .
|
|
ExprPair = Expression ":" Expression .
|
|
|
|
The LiteralType must be an struct, array, slice, or map type.
|
|
The types of the expressions must match the respective field, element, and
|
|
key types of the LiteralType; there is no automatic type conversion.
|
|
Composite literals are values of the type specified by LiteralType; that is
|
|
a new value is created every time the literal is evaluated. To get
|
|
a pointer to the literal, the address operator "&" must be used.
|
|
|
|
Given
|
|
|
|
type Rat struct { num, den int }
|
|
type Num struct { r Rat; f float; s string }
|
|
|
|
one can write
|
|
|
|
pi := Num{Rat{22, 7}, 3.14159, "pi"};
|
|
|
|
The length of an array literal is the length specified in the LiteralType.
|
|
If fewer elements than the length are provided in the literal, the missing
|
|
elements are set to the appropriate zero value for the array element type.
|
|
It is an error to provide more elements than specified in LiteralType. The
|
|
notation "..." may be used in place of the length expression to denote a
|
|
length equal to the number of elements in the literal.
|
|
|
|
buffer := [10]string{}; // len(buffer) == 10
|
|
primes := [6]int{2, 3, 5, 7, 9, 11}; // len(primes) == 6
|
|
days := [...]string{"sat", "sun"}; // len(days) == 2
|
|
|
|
A slice literal is a slice describing the entire underlying array literal.
|
|
Thus, the length and capacity of a slice literal is the number of elements
|
|
provided in the literal. A slice literal of the form
|
|
|
|
[]T{x1, x2, ... xn}
|
|
|
|
is essentially a shortcut for a slice operation applied to an array literal:
|
|
|
|
[n]T{x1, x2, ... xn}[0 : n]
|
|
|
|
Map literals are similar except the elements of the expression list are
|
|
key-value pairs separated by a colon:
|
|
|
|
m := map[string]int{"good": 0, "bad": 1, "indifferent": 7};
|
|
|
|
TODO: Consider adding helper syntax for nested composites
|
|
(avoids repeating types but complicates the spec needlessly.)
|
|
|
|
|
|
Function Literals
|
|
----
|
|
|
|
A function literal represents an anonymous function. It consists of a
|
|
specification of the function type and the function body. The parameter
|
|
and result types of the function type must all be complete types (§Types).
|
|
|
|
FunctionLit = "func" FunctionType Block .
|
|
Block = "{" [ StatementList ] "}" .
|
|
|
|
The type of a function literal is a pointer to the function type.
|
|
|
|
func (a, b int, z float) bool { return a*b < int(z); }
|
|
|
|
A function literal can be assigned to a variable of the
|
|
corresponding function pointer type, or invoked directly.
|
|
|
|
f := func(x, y int) int { return x + y; }
|
|
func(ch chan int) { ch <- ACK; } (reply_chan)
|
|
|
|
Implementation restriction: A function literal can reference only
|
|
its parameters, global variables, and variables declared within the
|
|
function literal.
|
|
|
|
|
|
Primary expressions
|
|
----
|
|
|
|
PrimaryExpr =
|
|
Operand |
|
|
PrimaryExpr Selector |
|
|
PrimaryExpr Index |
|
|
PrimaryExpr Slice |
|
|
PrimaryExpr TypeGuard |
|
|
PrimaryExpr Call .
|
|
|
|
Selector = "." identifier .
|
|
Index = "[" Expression "]" .
|
|
Slice = "[" Expression ":" Expression "]" .
|
|
TypeGuard = "." "(" Type ")" .
|
|
Call = "(" [ ExpressionList ] ")" .
|
|
|
|
|
|
x
|
|
2
|
|
(s + ".txt")
|
|
f(3.1415, true)
|
|
Point(1, 2)
|
|
m["foo"]
|
|
s[i : j + 1]
|
|
obj.color
|
|
Math.sin
|
|
f.p[i].x()
|
|
|
|
|
|
Selectors
|
|
----
|
|
|
|
A primary expression of the form
|
|
|
|
x.f
|
|
|
|
denotes the field or method f of the value denoted by x (or of *x if
|
|
x is of pointer type). The identifier f is called the (field or method)
|
|
``selector''.
|
|
|
|
A selector f may denote a field f declared in a type T, or it may refer
|
|
to a field f declared in a nested anonymous field of T. Analogously,
|
|
f may denote a method f of T, or it may refer to a method f of the type
|
|
of a nested anonymous field of T. The number of anonymous fields traversed
|
|
to get to the field or method is called its ``depth'' in T.
|
|
|
|
More precisely, the depth of a field or method f declared in T is zero.
|
|
The depth of a field or method f declared anywhere inside
|
|
an anonymous field A declared in T is the depth of f in A plus one.
|
|
|
|
The following rules apply to selectors:
|
|
|
|
1) For a value x of type T or *T where T is not an interface type,
|
|
x.f denotes the field or method at the shallowest depth in T where there
|
|
is such an f. The type of x.f is the type of the field or method f.
|
|
If there is not exactly one f with shallowest depth, the selector
|
|
expression is illegal.
|
|
|
|
2) For a variable x of type I or *I where I is an interface type,
|
|
x.f denotes the actual method with name f of the value assigned
|
|
to x if there is such a method. The type of x.f is the type
|
|
of the method f. If no value or nil was assigned to x, x.f is illegal.
|
|
|
|
3) In all other cases, x.f is illegal.
|
|
|
|
Thus, selectors automatically dereference pointers as necessary. For instance,
|
|
for an x of type *T where T declares an f, x.f is a shortcut for (*x).f.
|
|
Furthermore, for an x of type T containing an anonymous field A declared as *A
|
|
inside T, and where A contains a field f, x.f is a shortcut for (*x.A).f
|
|
(assuming that the selector is legal in the first place).
|
|
|
|
The following examples illustrate selector use in more detail. Given the
|
|
declarations:
|
|
|
|
type T0 struct {
|
|
x int;
|
|
}
|
|
|
|
func (recv *T0) M0()
|
|
|
|
type T1 struct {
|
|
y int;
|
|
}
|
|
|
|
func (recv T1) M1()
|
|
|
|
type T2 struct {
|
|
z int;
|
|
T1;
|
|
*T0;
|
|
}
|
|
|
|
func (recv *T2) M2()
|
|
|
|
var p *T2; // with p != nil and p.T1 != nil
|
|
|
|
one can write:
|
|
|
|
p.z // (*p).z
|
|
p.y // ((*p).T1).y
|
|
p.x // (*(*p).T0).x
|
|
|
|
p.M2 // (*p).M2
|
|
p.M1 // ((*p).T1).M1
|
|
p.M0 // ((*p).T0).M0
|
|
|
|
|
|
TODO: Specify what happens to receivers.
|
|
|
|
|
|
Indexes
|
|
----
|
|
|
|
A primary expression of the form
|
|
|
|
a[x]
|
|
|
|
denotes the array or map element x. The value x is called the
|
|
``array index'' or ``map key'', respectively. The following
|
|
rules apply:
|
|
|
|
For a of type A or *A where A is an array type (§Array types):
|
|
|
|
- x must be an integer value and 0 <= x < len(a)
|
|
- a[x] is the array element at index x and the type of a[x]
|
|
is the element type of A
|
|
|
|
For a of type *M, where M is a map type (§Map types):
|
|
|
|
- x must be of the same type as the key type of M
|
|
and the map must contain an entry with key x
|
|
- a[x] is the map value with key x and the type of a[x]
|
|
is the value type of M
|
|
|
|
Otherwise a[x] is illegal.
|
|
|
|
TODO: Need to expand map rules for assignments of the form v, ok = m[k].
|
|
|
|
|
|
Slices
|
|
----
|
|
|
|
Strings, arrays, and slices can be ``sliced'' to construct substrings or descriptors
|
|
of subarrays. The index expressions in the slice select which elements appear
|
|
in the result. The result has indexes starting at 0 and length equal to the
|
|
difference in the index values in the slice. After slicing the array "a"
|
|
|
|
a := [4]int{1, 2, 3, 4};
|
|
s := a[1:3];
|
|
|
|
the slice "s" has type "[]int", length 2, and elements
|
|
|
|
s[0] == 2
|
|
s[1] == 3
|
|
|
|
The index values in the slice must be in bounds for the original
|
|
array (or string) and the slice length must be non-negative.
|
|
|
|
If the sliced operand is a string, the result of the slice operation is another
|
|
string (§String types). If the sliced operand is an array or slice, the result
|
|
of the slice operation is a slice (§Slice types).
|
|
|
|
|
|
Type guards
|
|
----
|
|
|
|
For an expression "x" and a type "T", the primary expression
|
|
|
|
x.(T)
|
|
|
|
asserts that the value stored in "x" is an element of type "T" (§Types).
|
|
The notation ".(T)" is called a ``type guard'', and "x.(T)" is called
|
|
a ``guarded expression''. The type of "x" must be an interface type.
|
|
|
|
More precisely, if "T" is not an interface type, the expression asserts
|
|
that the dynamic type of "x" is identical to the type "T" (§Types).
|
|
If "T" is an interface type, the expression asserts that the dynamic type
|
|
of T implements the interface "T" (§Interface types). Because it can be
|
|
verified statically, a type guard in which the static type of "x" implements
|
|
the interface "T" is illegal. The type guard is said to succeed if the
|
|
assertion holds.
|
|
|
|
If the type guard succeeds, the value of the guarded expression is the value
|
|
stored in "x" and its type is "T". If the type guard fails, a run-time
|
|
exception occurs. In other words, even though the dynamic type of "x"
|
|
is only known at run-time, the type of the guarded expression "x.(T)" is
|
|
known to be "T" in a correct program.
|
|
|
|
As a special form, if a guarded expression is used in an assignment
|
|
|
|
v, ok = x.(T)
|
|
v, ok := x.(T)
|
|
|
|
the result of the guarded expression is a pair of values with types "(T, bool)".
|
|
If the type guard succeeds, the expression returns the pair "(x.(T), true)";
|
|
that is, the value stored in "x" (of type "T") is assigned to "v", and "ok"
|
|
is set to true. If the type guard fails, the value in "v" is set to the initial
|
|
value for the type of "v" (§Program initialization and execution), and "ok" is
|
|
set to false. No run-time exception occurs in this case.
|
|
|
|
TODO add examples
|
|
|
|
|
|
Calls
|
|
----
|
|
|
|
Given a function pointer, one writes
|
|
|
|
p()
|
|
|
|
to call the function.
|
|
|
|
A method is called using the notation
|
|
|
|
receiver.method()
|
|
|
|
where receiver is a value of the receive type of the method.
|
|
|
|
For instance, given a *Point variable pt, one may call
|
|
|
|
pt.Scale(3.5)
|
|
|
|
The type of a method is the type of a function with the receiver as first
|
|
argument. For instance, the method "Scale" has type
|
|
|
|
(p *Point, factor float)
|
|
|
|
However, a function declared this way is not a method.
|
|
|
|
There is no distinct method type and there are no method literals.
|
|
|
|
|
|
Parameter passing
|
|
----
|
|
|
|
TODO expand this section (right now only "..." parameters are covered).
|
|
|
|
Inside a function, the type of the "..." parameter is the empty interface
|
|
"interface {}". The dynamic type of the parameter - that is, the type of
|
|
the value stored in the parameter - is of the form (in pseudo-
|
|
notation)
|
|
|
|
*struct {
|
|
arg(0) typeof(arg(0));
|
|
arg(1) typeof(arg(1));
|
|
arg(2) typeof(arg(2));
|
|
...
|
|
arg(n-1) typeof(arg(n-1));
|
|
}
|
|
|
|
where the "arg(i)"'s correspond to the actual arguments passed in place
|
|
of the "..." parameter (the parameter and type names are for illustration
|
|
only). Reflection code may be used to access the struct value and its fields.
|
|
Thus, arguments provided in place of a "..." parameter are wrapped into
|
|
a corresponding struct, and a pointer to the struct is passed to the
|
|
function instead of the actual arguments.
|
|
|
|
For instance, consider the function
|
|
|
|
func f(x int, s string, f_extra ...)
|
|
|
|
and the call
|
|
|
|
f(42, "foo", 3.14, true, &[]int{1, 2, 3})
|
|
|
|
Upon invocation, the parameters "3.14", "true", and "*[3]int{1, 2, 3}"
|
|
are wrapped into a struct and the pointer to the struct is passed to f.
|
|
In f the type of parameter "f_extra" is "interface{}".
|
|
The dynamic type of "f_extra" is the type of the value assigned
|
|
to it upon invocation (the field names "arg0", "arg1", "arg2" are made
|
|
up for illustration only, they are not accessible via reflection):
|
|
|
|
*struct {
|
|
arg0 float;
|
|
arg1 bool;
|
|
arg2 *[3]int;
|
|
}
|
|
|
|
The values of the fields "arg0", "arg1", and "arg2" are "3.14", "true",
|
|
and "*[3]int{1, 2, 3}".
|
|
|
|
As a special case, if a function passes a "..." parameter as the argument
|
|
for a "..." parameter of a function, the parameter is not wrapped again into
|
|
a struct. Instead it is passed along unchanged. For instance, the function
|
|
f may call a function g with declaration
|
|
|
|
func g(x int, g_extra ...)
|
|
|
|
as
|
|
|
|
g(x, f_extra);
|
|
|
|
Inside g, the value stored in g_extra is the same as the value stored
|
|
in f_extra.
|
|
|
|
|
|
Operators
|
|
----
|
|
|
|
Operators combine operands into expressions.
|
|
|
|
Expression = UnaryExpr | Expression binaryOp UnaryExpr .
|
|
UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
|
|
|
|
binary_op = log_op | com_op | rel_op | add_op | mul_op .
|
|
log_op = "||" | "&&" .
|
|
com_op = "<-" .
|
|
rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
|
|
add_op = "+" | "-" | "|" | "^" .
|
|
mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" .
|
|
|
|
unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
|
|
|
|
The operand types in binary operations must be equal, with the following exceptions:
|
|
|
|
- If one operand has numeric type and the other operand is
|
|
an ideal number, the ideal number is converted to match the type of
|
|
the other operand (§Expression).
|
|
|
|
- If both operands are ideal numbers, the conversion is to ideal floats
|
|
if one of the operands is an ideal float (relevant for "/" and "%").
|
|
|
|
- The right operand in a shift operation must be always be an unsigned int
|
|
(or an ideal number that can be safely converted into an unsigned int)
|
|
(§Arithmetic operators).
|
|
|
|
Unary operators have the highest precedence. They are evaluated from
|
|
right to left. Note that "++" and "--" are outside the unary operator
|
|
hierachy (they are statements) and they apply to the operand on the left.
|
|
Specifically, "*p++" means "(*p)++" in Go (as opposed to "*(p++)" in C).
|
|
|
|
There are six precedence levels for binary operators:
|
|
multiplication operators bind strongest, followed by addition
|
|
operators, comparison operators, communication operators,
|
|
"&&" (logical and), and finally "||" (logical or) with the
|
|
lowest precedence:
|
|
|
|
Precedence Operator
|
|
6 * / % << >> &
|
|
5 + - | ^
|
|
4 == != < <= > >=
|
|
3 <-
|
|
2 &&
|
|
1 ||
|
|
|
|
Binary operators of the same precedence associate from left to right.
|
|
For instance, "x / y / z" stands for "(x / y) / z".
|
|
|
|
Examples
|
|
|
|
+x
|
|
23 + 3*x[i]
|
|
x <= f()
|
|
^a >> b
|
|
f() || g()
|
|
x == y + 1 && <-chan_ptr > 0
|
|
|
|
|
|
Arithmetic operators
|
|
----
|
|
|
|
Arithmetic operators apply to numeric types and yield a result of the same
|
|
type as the first operand. The four standard arithmetic operators ("+", "-",
|
|
"*", "/") apply to both integer and floating point types, while "+" also applies
|
|
to strings and arrays; all other arithmetic operators apply to integer types only.
|
|
|
|
+ sum integers, floats, strings, arrays
|
|
- difference integers, floats
|
|
* product integers, floats
|
|
/ quotient integers, floats
|
|
% remainder integers
|
|
|
|
& bitwise and integers
|
|
| bitwise or integers
|
|
^ bitwise xor integers
|
|
|
|
<< left shift integer << unsigned integer
|
|
>> right shift integer >> unsigned integer
|
|
|
|
Strings and arrays can be concatenated using the "+" operator
|
|
(or via the "+=" assignment):
|
|
|
|
s := "hi" + string(c)
|
|
a += []int{5, 6, 7}
|
|
|
|
String and array addition creates a new array or string by copying the
|
|
elements.
|
|
|
|
For integer values, "/" and "%" satisfy the following relationship:
|
|
|
|
(a / b) * b + a % b == a
|
|
|
|
and
|
|
|
|
(a / b) is "truncated towards zero".
|
|
|
|
Examples:
|
|
|
|
x y x / y x % y
|
|
5 3 1 2
|
|
-5 3 -1 -2
|
|
5 -3 -1 2
|
|
-5 -3 1 -2
|
|
|
|
Note that if the dividend is positive and the divisor is a constant power of 2,
|
|
the division may be replaced by a left 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. They implement arithmetic shifts if the left operand is a signed
|
|
integer, and logical shifts if it is an unsigned integer. The shift count must
|
|
be an unsigned integer. There is no upper limit on the shift count. It is
|
|
as if the left operand is shifted "n" times by 1 for a shift count of "n".
|
|
Specifically, "x << 1" is the same as "x*2"; and "x >> 1" is the same as
|
|
"x/2 truncated towards negative infinity".
|
|
|
|
For integer operands, the unary operators "+", "-", and "^" are defined as
|
|
follows:
|
|
|
|
+x is 0 + x
|
|
-x negation is 0 - x
|
|
^x bitwise complement is m ^ x with m = "all bits set to 1"
|
|
|
|
|
|
Integer overflow
|
|
----
|
|
|
|
For unsigned integer values, the operations "+", "-", "*", and "<<" are
|
|
computed modulo 2^n, where n is the bit width of the unsigned integer type
|
|
(§Arithmetic types). Loosely speaking, these unsigned integer operations
|
|
discard high bits upon overflow, and programs may rely on ``wrap around''.
|
|
|
|
For signed integers, the operations "+", "-", "*", and "<<" may legally
|
|
overflow and the resulting value exists and is deterministically defined
|
|
by the signed integer representation, the operation, and its operands.
|
|
No exception is raised as a result of overflow. As a consequence, a
|
|
compiler may not optimize code under the assumption that overflow does
|
|
not occur. For instance, it may not assume that "x < x + 1" is always true.
|
|
|
|
|
|
Comparison operators
|
|
----
|
|
|
|
Comparison operators yield a boolean result. All comparison operators apply
|
|
to strings and numeric types. The operators "==" and "!=" also apply to
|
|
boolean values, pointer, interface types, slice, map, and channel types
|
|
(including the value "nil").
|
|
|
|
== equal
|
|
!= not equal
|
|
< less
|
|
<= less or equal
|
|
> greater
|
|
>= greater or equal
|
|
|
|
Strings are compared byte-wise (lexically).
|
|
|
|
Pointers are equal if they point to the same value.
|
|
|
|
Interfaces are equal if both their dynamic types and values are equal.
|
|
For a value "v" of interface type, "v == nil" is true only if the predeclared
|
|
constant "nil" is assigned explicitly to "v" (§Assignments), or "v" has not
|
|
been modified since creation (§Program initialization and execution).
|
|
|
|
TODO: Should we allow general comparison via interfaces? Problematic.
|
|
|
|
Slices, maps, and channels are equal if they denote the same slice, map, or
|
|
channel respectively, or are "nil".
|
|
|
|
TODO: We need to be more precise here.
|
|
|
|
|
|
Logical operators
|
|
----
|
|
|
|
Logical operators apply to boolean operands and yield a boolean result.
|
|
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
|
|
----
|
|
|
|
TODO: Need to talk about unary "*", clean up section below.
|
|
|
|
Given a function f, declared as
|
|
|
|
func f(a int) int;
|
|
|
|
taking the address of f with the expression
|
|
|
|
&f
|
|
|
|
creates a pointer to the function that may be stored in a value of type pointer
|
|
to function:
|
|
|
|
var fp *(a int) int = &f;
|
|
|
|
The function pointer may be invoked with the usual syntax; no explicit
|
|
indirection is required:
|
|
|
|
fp(7)
|
|
|
|
Methods are a form of function, and the address of a method has the type
|
|
pointer to function. Consider the type T with method M:
|
|
|
|
type T struct {
|
|
a int;
|
|
}
|
|
func (tp *T) M(a int) int;
|
|
var t *T;
|
|
|
|
To construct the address of method M, one writes
|
|
|
|
&t.M
|
|
|
|
using the variable t (not the type T). The expression is a pointer to a
|
|
function, with type
|
|
|
|
*(t *T, a int) int
|
|
|
|
and may be invoked only as a function, not a method:
|
|
|
|
var f *(t *T, a int) int;
|
|
f = &t.M;
|
|
x := f(t, 7);
|
|
|
|
Note that one does not write t.f(7); taking the address of a method demotes
|
|
it to a function.
|
|
|
|
In general, given type T with method M and variable t of type *T,
|
|
the method invocation
|
|
|
|
t.M(args)
|
|
|
|
is equivalent to the function call
|
|
|
|
(&t.M)(t, args)
|
|
|
|
If T is an interface type, the expression &t.M does not determine which
|
|
underlying type's M is called until the point of the call itself. Thus given
|
|
T1 and T2, both implementing interface I with interface M, the sequence
|
|
|
|
var t1 *T1;
|
|
var t2 *T2;
|
|
var i I = t1;
|
|
m := &i.M;
|
|
m(t2);
|
|
|
|
will invoke t2.M() even though m was constructed with an expression involving
|
|
t1.
|
|
|
|
|
|
Communication operators
|
|
----
|
|
|
|
The syntax presented above covers communication operations. This
|
|
section describes their form and function.
|
|
|
|
Here the term "channel" means "variable of type chan".
|
|
|
|
The built-in function "make" makes a new channel value:
|
|
|
|
ch := make(chan int)
|
|
|
|
An optional argument to "make()" specifies a buffer size for an
|
|
asynchronous channel; if absent or zero, the channel is synchronous:
|
|
|
|
sync_chan := make(chan int)
|
|
buffered_chan := make(chan int, 10)
|
|
|
|
The send operation uses the binary operator "<-", which operates on
|
|
a channel and a value (expression):
|
|
|
|
ch <- 3
|
|
|
|
In this form, the send operation is an (expression) statement that
|
|
sends the value on the channel. Both the channel and the expression
|
|
are evaluated before communication begins. Communication blocks
|
|
until the send can proceed, at which point the value is transmitted
|
|
on the channel.
|
|
|
|
If the send operation appears in an expression context, the value
|
|
of the expression is a boolean and the operation is non-blocking.
|
|
The value of the boolean reports true if the communication succeeded,
|
|
false if it did not. These two examples are equivalent:
|
|
|
|
ok := ch <- 3;
|
|
if ok { print("sent") } else { print("not sent") }
|
|
|
|
if ch <- 3 { print("sent") } else { print("not sent") }
|
|
|
|
In other words, if the program tests the value of a send operation,
|
|
the send is non-blocking and the value of the expression is the
|
|
success of the operation. If the program does not test the value,
|
|
the operation blocks until it succeeds.
|
|
|
|
TODO: Adjust the above depending on how we rule on the ok semantics.
|
|
For instance, does the sent expression get evaluated if ok is false?
|
|
|
|
The receive operation uses the prefix unary operator "<-".
|
|
The value of the expression is the value received:
|
|
|
|
<-ch
|
|
|
|
The expression blocks until a value is available, which then can
|
|
be assigned to a variable or used like any other expression:
|
|
|
|
v1 := <-ch
|
|
v2 = <-ch
|
|
f(<-ch)
|
|
|
|
If the receive expression does not save the value, the value is
|
|
discarded:
|
|
|
|
<-strobe // wait until clock pulse
|
|
|
|
If a receive expression is used in a tuple assignment of the form
|
|
|
|
x, ok = <-ch; // or: x, ok := <-ch
|
|
|
|
the receive operation becomes non-blocking, and the boolean variable
|
|
"ok" will be set to "true" if the receive operation succeeded, and set
|
|
to "false" otherwise.
|
|
|
|
|
|
Constant expressions
|
|
----
|
|
|
|
A constant expression is an expression whose operands are all constants
|
|
(§Constants). Additionally, the result of the predeclared functions
|
|
below (with appropriate arguments) is also constant:
|
|
|
|
len(a) if a is an array (as opposed to an array slice)
|
|
|
|
TODO: Complete this list as needed.
|
|
|
|
Constant expressions can be evaluated at compile time.
|
|
|
|
|
|
----
|
|
|
|
Statements
|
|
----
|
|
|
|
Statements control execution.
|
|
|
|
Statement =
|
|
Declaration | LabelDecl | EmptyStat |
|
|
SimpleStat | GoStat | ReturnStat | BreakStat | ContinueStat | GotoStat |
|
|
FallthroughStat | Block | IfStat | SwitchStat | SelectStat | ForStat .
|
|
|
|
SimpleStat =
|
|
ExpressionStat | IncDecStat | Assignment | SimpleVarDecl .
|
|
|
|
|
|
Statements in a statement list are separated by semicolons, which can be
|
|
omitted in some cases as expressed by the OptSemicolon production.
|
|
|
|
StatementList = Statement { OptSemicolon Statement } .
|
|
|
|
A semicolon may be omitted immediately following:
|
|
|
|
- a closing parenthesis ")" ending a list of declarations (§Declarations and scope rules)
|
|
- a closing brace "}" ending a type declaration (§Type declarations)
|
|
- a closing brace "}" ending a block (including switch and select statements)
|
|
- a label declaration (§Label declarations)
|
|
|
|
In all other cases a semicolon is required to separate two statements. Since there
|
|
is an empty statement, a statement list can always be ``terminated'' with a semicolon.
|
|
|
|
|
|
Empty statements
|
|
----
|
|
|
|
The empty statement does nothing.
|
|
|
|
EmptyStat = .
|
|
|
|
|
|
Expression statements
|
|
----
|
|
|
|
ExpressionStat = Expression .
|
|
|
|
f(x+y)
|
|
|
|
TODO: specify restrictions. 6g only appears to allow calls here.
|
|
|
|
|
|
IncDec statements
|
|
----
|
|
|
|
The "++" and "--" statements increment or decrement their operands
|
|
by the (ideal) constant value 1.
|
|
|
|
IncDecStat = Expression ( "++" | "--" ) .
|
|
|
|
The following assignment statements (§Assignments) are semantically
|
|
equivalent:
|
|
|
|
IncDec statement Assignment
|
|
x++ x += 1
|
|
x-- x -= 1
|
|
|
|
Both operators apply to integer and floating point types only.
|
|
|
|
Note that increment and decrement are statements, not expressions.
|
|
For instance, "x++" cannot be used as an operand in an expression.
|
|
|
|
|
|
Assignments
|
|
----
|
|
|
|
Assignment = ExpressionList assign_op ExpressionList .
|
|
|
|
assign_op = [ add_op | mul_op ] "=" .
|
|
|
|
The left-hand side must be an l-value such as a variable, pointer indirection,
|
|
or an array index.
|
|
|
|
x = 1
|
|
*p = f()
|
|
a[i] = 23
|
|
k = <-ch
|
|
|
|
As in C, arithmetic binary operators can be combined with assignments:
|
|
|
|
j <<= 2
|
|
|
|
A tuple assignment assigns the individual elements of a multi-valued operation,
|
|
such as function evaluation or some channel and map operations, into individual
|
|
variables. For instance, a tuple assignment such as
|
|
|
|
v1, v2, v3 = e1, e2, e3
|
|
|
|
assigns the expressions e1, e2, e3 to temporaries and then assigns the temporaries
|
|
to the variables v1, v2, v3. Thus
|
|
|
|
a, b = b, a
|
|
|
|
exchanges the values of a and b. The tuple assignment
|
|
|
|
x, y = f()
|
|
|
|
calls the function f, which must return two values, and assigns them to x and y.
|
|
As a special case, retrieving a value from a map, when written as a two-element
|
|
tuple assignment, assign a value and a boolean. If the value is present in the map,
|
|
the value is assigned and the second, boolean variable is set to true. Otherwise,
|
|
the variable is unchanged, and the boolean value is set to false.
|
|
|
|
value, present = map_var[key]
|
|
|
|
To delete a value from a map, use a tuple assignment with the map on the left
|
|
and a false boolean expression as the second expression on the right, such
|
|
as:
|
|
|
|
map_var[key] = value, false
|
|
|
|
In assignments, the type of the expression must match the type of the left-hand side.
|
|
|
|
|
|
If statements
|
|
----
|
|
|
|
If statements specify the conditional execution of two branches; the "if"
|
|
and the "else" branch. If Expression evaluates to true,
|
|
the "if" branch is executed. Otherwise the "else" branch is executed if present.
|
|
If Condition is omitted, it is equivalent to true.
|
|
|
|
IfStat = "if" [ [ Simplestat ] ";" ] [ Expression ] Block [ "else" Statement ] .
|
|
|
|
if x > 0 {
|
|
return true;
|
|
}
|
|
|
|
An "if" statement may include the declaration of a single temporary variable.
|
|
The scope of the declared variable extends to the end of the if statement, and
|
|
the variable is initialized once before the statement is entered.
|
|
|
|
if x := f(); x < y {
|
|
return x;
|
|
} else if x > z {
|
|
return z;
|
|
} else {
|
|
return y;
|
|
}
|
|
|
|
|
|
<!--
|
|
TODO: gri thinks that Statement needs to be changed as follows:
|
|
|
|
IfStat =
|
|
"if" [ [ Simplestat ] ";" ] [ Expression ] Block
|
|
[ "else" ( IfStat | Block ) ] .
|
|
|
|
To facilitate the "if else if" code pattern, if the "else" branch is
|
|
simply another "if" statement, that "if" statement may be written
|
|
without the surrounding Block:
|
|
|
|
if x > 0 {
|
|
return 0;
|
|
} else if x > 10 {
|
|
return 1;
|
|
} else {
|
|
return 2;
|
|
}
|
|
|
|
-->
|
|
|
|
Switch statements
|
|
----
|
|
|
|
Switches provide multi-way execution.
|
|
|
|
SwitchStat = "switch" [ [ Simplestat ] ";" ] [ Expression ] "{" { CaseClause } "}" .
|
|
CaseClause = Case [ StatementList ] .
|
|
Case = ( "case" ExpressionList | "default" ) ":" .
|
|
|
|
There can be at most one default case in a switch statement. In a case clause,
|
|
the last statement only may be a fallthrough statement ($Fallthrough statement).
|
|
It indicates that the control should flow from the end of this case clause to
|
|
the first statement of the next clause.
|
|
|
|
Each case clause effectively acts as a block for scoping purposes
|
|
($Declarations and scope rules).
|
|
|
|
The expressions do not need to be constants. They will
|
|
be evaluated top to bottom until the first successful non-default case is reached.
|
|
If none matches and there is a default case, the statements of the default
|
|
case are executed.
|
|
|
|
switch tag {
|
|
default: s3()
|
|
case 0, 1: s1()
|
|
case 2: s2()
|
|
}
|
|
|
|
A switch statement may include the declaration of a single temporary variable.
|
|
The scope of the declared variable extends to the end of the switch statement, and
|
|
the variable is initialized once before the switch is entered.
|
|
|
|
switch x := f(); true {
|
|
case x < 0: return -x
|
|
default: return x
|
|
}
|
|
|
|
Cases do not fall through unless explicitly marked with a "fallthrough" statement.
|
|
|
|
switch a {
|
|
case 1:
|
|
b();
|
|
fallthrough
|
|
case 2:
|
|
c();
|
|
}
|
|
|
|
If the expression is omitted, it is equivalent to "true".
|
|
|
|
switch {
|
|
case x < y: f1();
|
|
case x < z: f2();
|
|
case x == 4: f3();
|
|
}
|
|
|
|
|
|
For statements
|
|
----
|
|
|
|
A for statement specifies repeated execution of a block. The iteration is
|
|
controlled by a condition, a for clause, or a range clause.
|
|
|
|
ForStat = "for" [ Condition | ForClause | RangeClause ] Block .
|
|
Condition = Expression .
|
|
|
|
In its simplest form, a for statement specifies the repeated execution of
|
|
a block as long as a condition evaluates to true. The condition is evaluated
|
|
before each iteration. The type of the condition expression must be boolean.
|
|
If the condition is absent, it is equivalent to "true".
|
|
|
|
for a < b {
|
|
a *= 2
|
|
}
|
|
|
|
A for statement with a for clause is also controlled by its condition, but
|
|
additionally it may specify an init and post statement, such as an assignment,
|
|
an increment or decrement statement. The init statement may also be a (simple)
|
|
variable declaration; no variables can be declared in the post statement.
|
|
|
|
ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] .
|
|
InitStat = SimpleStat .
|
|
PostStat = SimpleStat .
|
|
|
|
For instance, one may declare an iteration variable in the init statement:
|
|
|
|
for i := 0; i < 10; i++ {
|
|
f(i)
|
|
}
|
|
|
|
If present, the init statement is executed once before commencing the iteration;
|
|
the post statement is executed after each execution of the statement block (and
|
|
only if the block was executed). The scope of any variable declared in the init
|
|
statement ends with the end of the for statement block ($Declarations and scope
|
|
rules, Rule 3).
|
|
|
|
The init and post statement as well as the condition may be omitted; however
|
|
if either the init or post statement are present, the separating semicolons
|
|
must be present. If the condition is absent, it is equivalent to "true".
|
|
The following statements are equivalent:
|
|
|
|
for ; cond ; { S() } is the same as for cond { S() }
|
|
for true { S() } is the same as for { S() }
|
|
|
|
Alternatively, a for statement may be controlled by a range clause. A
|
|
range clause specifies iteration through all entries of an array or map.
|
|
For each entry it first assigns the current index or key to an iteration
|
|
variable - or the current (index, element) or (key, value) pair to a pair
|
|
of iteration variables - and then executes the block. Iteration terminates
|
|
when all entries have been processed, or if the for statement is terminated
|
|
early, for instance by a break or return statement.
|
|
|
|
RangeClause = IdentifierList ( "=" | ":=" ) "range" Expression .
|
|
|
|
The type of the right-hand expression in the range clause must be an array or
|
|
map, or a pointer to an array or map. If it is a pointer, it must not be nil.
|
|
The left-hand identifier list must contain one or two identifiers denoting the
|
|
iteration variables. The first variable is set to the current array index or
|
|
map key, and the second variable, if present, is set to the corresponding
|
|
array element or map value. The types of the array index (int) and element,
|
|
or of the map key and value respectively, must be assignment-compatible to
|
|
the iteration variables.
|
|
|
|
The iteration variables may be declared by the range clause (":="), in which
|
|
case their scope ends at the end of the for statement block ($Declarations and
|
|
scope rules, Rule 3). In this case their types are the array index and element,
|
|
or the map key and value types, respectively.
|
|
|
|
var a [10]string;
|
|
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6};
|
|
|
|
for i, s := range a {
|
|
// type of i is int
|
|
// type of s is string
|
|
// s == a[i]
|
|
g(i, s)
|
|
}
|
|
|
|
var key string;
|
|
var val interface {}; // value type of m is assignment-compatible to val
|
|
for key, value = range m {
|
|
h(key, value)
|
|
}
|
|
// key == last map key encountered in iteration
|
|
// val == map[key]
|
|
|
|
If map entries that have not yet been processed are deleted during iteration,
|
|
they will not be processed. If map entries are inserted during iteration, the
|
|
behavior is implementation-dependent. Likewise, if the range expression is a
|
|
pointer variable, the behavior of assigning to that variable is implementation-
|
|
dependent. Assigning to the iteration variables during iteration simply changes
|
|
the values of those variables for the current iteration; it does not affect any
|
|
subsequent iterations.
|
|
|
|
|
|
Go statements
|
|
----
|
|
|
|
A go statement starts the execution of a function as an independent
|
|
concurrent thread of control within the same address space. The expression
|
|
must evaluate into a function call.
|
|
|
|
GoStat = "go" Expression .
|
|
|
|
Unlike with a regular function call, program execution does not wait
|
|
for the invoked function to complete.
|
|
|
|
go Server()
|
|
go func(ch chan <- bool) { for { sleep(10); ch <- true; }} (c)
|
|
|
|
|
|
Select statements
|
|
----
|
|
|
|
A select statement chooses which of a set of possible communications
|
|
will proceed. It looks similar to a switch statement but with the
|
|
cases all referring to communication operations.
|
|
|
|
SelectStat = "select" "{" { CommClause } "}" .
|
|
CommClause = CommCase [ StatementList ] .
|
|
CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" .
|
|
SendExpr = Expression "<-" Expression .
|
|
RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression .
|
|
|
|
Each communication clause acts as a block for the purpose of scoping
|
|
(§Declarations and scope rules).
|
|
|
|
For all the send and receive expressions in the select
|
|
statement, the channel expression is evaluated. Any values
|
|
that appear on the right hand side of send expressions are also
|
|
evaluated. If any of the resulting channels can proceed, one is
|
|
chosen and the corresponding communication and statements are
|
|
evaluated. Otherwise, if there is a default case, that executes;
|
|
if not, the statement blocks until one of the communications can
|
|
complete. The channels and send expressions are not re-evaluated.
|
|
A channel pointer may be nil, which is equivalent to that case not
|
|
being present in the select statement.
|
|
|
|
Since all the channels and send expressions are evaluated, any side
|
|
effects in that evaluation will occur for all the communications
|
|
in the select.
|
|
|
|
If the channel sends or receives an interface type, its
|
|
communication can proceed only if the type of the communication
|
|
clause matches that of the dynamic value to be exchanged.
|
|
|
|
If multiple cases can proceed, a uniform fair choice is made regarding
|
|
which single communication will execute.
|
|
|
|
The receive case may declare a new variable (via a ":=" assignment). The
|
|
scope of such variables begins immediately after the variable identifier
|
|
and ends at the end of the respective "select" case (that is, before the
|
|
next "case", "default", or closing brace).
|
|
|
|
var c, c1, c2 chan int;
|
|
var i1, i2 int;
|
|
select {
|
|
case i1 = <-c1:
|
|
print("received ", i1, " from c1\n");
|
|
case c2 <- i2:
|
|
print("sent ", i2, " to c2\n");
|
|
default:
|
|
print("no communication\n");
|
|
}
|
|
|
|
for { // send random sequence of bits to c
|
|
select {
|
|
case c <- 0: // note: no statement, no fallthrough, no folding of cases
|
|
case c <- 1:
|
|
}
|
|
}
|
|
|
|
var ca chan interface {};
|
|
var i int;
|
|
var f float;
|
|
select {
|
|
case i = <-ca:
|
|
print("received int ", i, " from ca\n");
|
|
case f = <-ca:
|
|
print("received float ", f, " from ca\n");
|
|
}
|
|
|
|
TODO: Make semantics more precise.
|
|
|
|
|
|
Return statements
|
|
----
|
|
|
|
A return statement terminates execution of the containing function
|
|
and optionally provides a result value or values to the caller.
|
|
|
|
ReturnStat = "return" [ ExpressionList ] .
|
|
|
|
|
|
There are two ways to return values from a function. The first is to
|
|
explicitly list the return value or values in the return statement:
|
|
|
|
func simple_f() int {
|
|
return 2;
|
|
}
|
|
|
|
A function may return multiple values.
|
|
The syntax of the return clause in that case is the same as
|
|
that of a parameter list; in particular, names must be provided for
|
|
the elements of the return value.
|
|
|
|
func complex_f1() (re float, im float) {
|
|
return -7.0, -4.0;
|
|
}
|
|
|
|
A second method to return values
|
|
is to use those names within the function as variables
|
|
to be assigned explicitly; the return statement will then provide no
|
|
values:
|
|
|
|
func complex_f2() (re float, im float) {
|
|
re = 7.0;
|
|
im = 4.0;
|
|
return;
|
|
}
|
|
|
|
|
|
Break statements
|
|
----
|
|
|
|
Within a for, switch, or select statement, a break statement terminates
|
|
execution of the innermost such statement.
|
|
|
|
BreakStat = "break" [ identifier ].
|
|
|
|
If there is an identifier, it must be a label marking an enclosing
|
|
for, switch, or select statement, and that is the one whose execution
|
|
terminates.
|
|
|
|
L: for i < n {
|
|
switch i {
|
|
case 5: break L
|
|
}
|
|
}
|
|
|
|
|
|
Continue statements
|
|
----
|
|
|
|
Within a for loop a continue statement begins the next iteration of the
|
|
loop at the post statement.
|
|
|
|
ContinueStat = "continue" [ identifier ].
|
|
|
|
The optional identifier is analogous to that of a break statement.
|
|
|
|
|
|
Label declarations
|
|
----
|
|
|
|
A label declaration serves as the target of a goto, break or continue statement.
|
|
|
|
LabelDecl = identifier ":" .
|
|
|
|
Example:
|
|
|
|
Error:
|
|
|
|
|
|
Goto statements
|
|
----
|
|
|
|
A goto statement transfers control to the corresponding label statement.
|
|
|
|
GotoStat = "goto" identifier .
|
|
|
|
goto Error
|
|
|
|
Executing the goto statement must not cause any variables to come into
|
|
scope that were not already in scope at the point of the goto. For
|
|
instance, this example:
|
|
|
|
goto L; // BAD
|
|
v := 3;
|
|
L:
|
|
|
|
is erroneous because the jump to label L skips the creation of v.
|
|
|
|
|
|
Fallthrough statements
|
|
----
|
|
|
|
A fallthrough statement transfers control to the first statement of the
|
|
next case clause in a switch statement (§Switch statements). It may only
|
|
be used in a switch statement, and only as the last statement in a case
|
|
clause of the switch statement.
|
|
|
|
FallthroughStat = "fallthrough" .
|
|
|
|
|
|
----
|
|
|
|
Function declarations
|
|
----
|
|
|
|
A function declaration binds an identifier to a function.
|
|
Functions contain declarations and statements. They may be
|
|
recursive. Except for forward declarations (see below), the parameter
|
|
and result types of the function type must all be complete types (§Type declarations).
|
|
|
|
FunctionDecl = "func" identifier FunctionType [ Block ] .
|
|
|
|
func min(x int, y int) int {
|
|
if x < y {
|
|
return x;
|
|
}
|
|
return y;
|
|
}
|
|
|
|
A function declaration without a block serves as a forward declaration:
|
|
|
|
func MakeNode(left, right *Node) *Node
|
|
|
|
|
|
Implementation restrictions: Functions can only be declared at the global level.
|
|
A function must be declared or forward-declared before it can be invoked.
|
|
|
|
|
|
Method declarations
|
|
----
|
|
|
|
A method declaration is a function declaration with a receiver. The receiver
|
|
is the first parameter of the method, and the receiver type must be specified
|
|
as a type name, or as a pointer to a type name. The type specified by the
|
|
type name is called ``receiver base type''. The receiver base type must be a
|
|
type declared in the current file, and it must not be a pointer type.
|
|
The method is said to be ``bound'' to the receiver base type; specifically
|
|
it is declared within the scope of that type (§Type declarations). If the
|
|
receiver value is not needed inside the method, its identifier may be omitted
|
|
in the declaration.
|
|
|
|
MethodDecl = "func" Receiver identifier FunctionType [ Block ] .
|
|
Receiver = "(" [ identifier ] [ "*" ] TypeName ")" .
|
|
|
|
All methods bound to a receiver base type must have the same receiver type:
|
|
Either all receiver types are pointers to the base type or they are the base
|
|
type. (TODO: This restriction can be relaxed at the cost of more complicated
|
|
assignment rules to interface types).
|
|
|
|
For instance, given type Point, the declarations
|
|
|
|
func (p *Point) Length() float {
|
|
return Math.sqrt(p.x * p.x + p.y * p.y);
|
|
}
|
|
|
|
func (p *Point) Scale(factor float) {
|
|
p.x = p.x * factor;
|
|
p.y = p.y * factor;
|
|
}
|
|
|
|
bind the methods "Length" and "Scale" to the receiver base type "Point".
|
|
|
|
Method declarations may appear anywhere after the declaration of the receiver
|
|
base type and may be forward-declared.
|
|
|
|
|
|
Predeclared functions
|
|
----
|
|
|
|
cap
|
|
convert
|
|
len
|
|
make
|
|
new
|
|
panic
|
|
panicln
|
|
print
|
|
println
|
|
typeof
|
|
|
|
|
|
TODO: (gri) suggests that we should consider assert() as a built-in function.
|
|
It is like panic, but takes a boolean guard as first argument. (rsc also thinks
|
|
this is a good idea).
|
|
|
|
|
|
Length and capacity
|
|
----
|
|
|
|
Call Argument type Result
|
|
|
|
len(s) string, *string string length (in bytes)
|
|
[n]T, *[n]T array length (== n)
|
|
[]T, *[]T slice length
|
|
map[K]T, *map[K]T map length
|
|
chan T number of elements in channel buffer
|
|
|
|
cap(s) []T, *[]T capacity of s
|
|
map[K]T, *map[K]T capacity of s
|
|
chan T channel buffer capacity
|
|
|
|
TODO: confirm len() and cap() for channels
|
|
|
|
The type of the result is always "int" and the implementation guarantees that
|
|
the result always fits into an "int".
|
|
|
|
The capacity of a slice or map is the number of elements for which there is
|
|
space allocated in the underlying array (for a slice) or map. For a slice "s",
|
|
at any time the following relationship holds:
|
|
|
|
0 <= len(s) <= cap(s)
|
|
|
|
|
|
Conversions
|
|
----
|
|
|
|
Conversions syntactically look like function calls of the form
|
|
|
|
T(value)
|
|
|
|
where "T" is the type name of an arithmetic type or string (§Basic types),
|
|
and "value" is the value of an expression which can be converted to a value
|
|
of result type "T".
|
|
|
|
The following conversion rules apply:
|
|
|
|
1) Between integer types. If the value is a signed quantity, it is
|
|
sign extended to implicit infinite precision; otherwise it is zero
|
|
extended. It is then truncated to fit in the result type size.
|
|
For example, uint32(int8(0xFF)) is 0xFFFFFFFF. The conversion always
|
|
yields a valid value; there is no signal for overflow.
|
|
|
|
2) Between integer and floating point types, or between floating point
|
|
types. To avoid overdefining the properties of the conversion, for
|
|
now it is defined as a ``best effort'' conversion. The conversion
|
|
always succeeds but the value may be a NaN or other problematic
|
|
result. TODO: clarify?
|
|
|
|
3) Strings permit two special conversions.
|
|
|
|
3a) Converting an integer value yields a string containing the UTF-8
|
|
representation of the integer.
|
|
|
|
string(0x65e5) // "\u65e5"
|
|
|
|
3b) Converting an array of uint8s yields a string whose successive
|
|
bytes are those of the array. (Recall byte is a synonym for uint8.)
|
|
|
|
string([]byte{'h', 'e', 'l', 'l', 'o'}) // "hello"
|
|
|
|
There is no linguistic mechanism to convert between pointers
|
|
and integers. A library may be provided under restricted circumstances
|
|
to acccess this conversion in low-level code.
|
|
|
|
TODO: Do we allow interface/ptr conversions in this form or do they
|
|
have to be written as type guards? (§Type guards)
|
|
|
|
|
|
Allocation
|
|
----
|
|
|
|
The built-in function "new" takes a type "T" and returns a value of type "*T".
|
|
The memory is initialized as described in the section on initial values
|
|
(§Program initialization and execution).
|
|
|
|
new(T)
|
|
|
|
For instance
|
|
|
|
type S struct { a int; b float }
|
|
new(S)
|
|
|
|
dynamically allocates memory for a variable of type S, initializes it
|
|
(a=0, b=0.0), and returns a value of type *S pointing to that variable.
|
|
|
|
|
|
TODO Once this has become clearer, connect new() and make() (new() may be
|
|
explained by make() and vice versa).
|
|
|
|
|
|
Making slices, maps, and channels
|
|
----
|
|
|
|
The built-in function "make" takes a type "T", optionally followed by a
|
|
type-specific list of expressions. It returns a value of type "T". "T"
|
|
must be a slice, map, or channel type.
|
|
The memory is initialized as described in the section on initial values
|
|
(§Program initialization and execution).
|
|
|
|
make(T [, optional list of expressions])
|
|
|
|
For instance
|
|
|
|
make(map[string] int)
|
|
|
|
creates a new map value and initializes it to an empty map.
|
|
|
|
The only defined parameters affect sizes for allocating slices, maps, and
|
|
buffered channels:
|
|
|
|
s := make([]int, 10, 100); # slice with len(s) == 10, cap(s) == 100
|
|
c := make(chan int, 10); # channel with a buffer size of 10
|
|
m := make(map[string] int, 100); # map with initial space for 100 elements
|
|
|
|
TODO Once this has become clearer, connect new() and make() (new() may be
|
|
explained by make() and vice versa).
|
|
|
|
|
|
----
|
|
|
|
Packages
|
|
----
|
|
|
|
A package is a package clause, optionally followed by import declarations,
|
|
followed by a series of declarations.
|
|
|
|
Package = PackageClause { ImportDecl [ ";" ] } { Declaration [ ";" ] } .
|
|
|
|
The source text following the package clause acts like a block for scoping
|
|
purposes ($Declarations and scope rules).
|
|
|
|
Every source file identifies the package to which it belongs.
|
|
The file must begin with a package clause.
|
|
|
|
PackageClause = "package" PackageName .
|
|
|
|
package Math
|
|
|
|
|
|
A package can gain access to exported identifiers from another package
|
|
through an import declaration:
|
|
|
|
ImportDecl = "import" ( ImportSpec | "(" [ ImportSpecList ] ")" ) .
|
|
ImportSpecList = ImportSpec { ";" ImportSpec } [ ";" ] .
|
|
ImportSpec = [ "." | PackageName ] PackageFileName .
|
|
|
|
An import statement makes the exported top-level identifiers of the named
|
|
package file accessible to this package.
|
|
|
|
In the following discussion, assume we have a package in the
|
|
file "/lib/math", called package "math", which exports the identifiers
|
|
"Sin" and "Cos" denoting the respective trigonometric functions.
|
|
|
|
In the general form, with an explicit package name, the import
|
|
statement declares that package name as an identifier whose
|
|
contents are the exported elements of the imported package.
|
|
For instance, after
|
|
|
|
import M "/lib/math"
|
|
|
|
the contents of the package /lib/math can be accessed by
|
|
"M.Sin", "M.Cos", etc.
|
|
|
|
In its simplest form, with no package name, the import statement
|
|
implicitly uses the imported package name itself as the local
|
|
package name. After
|
|
|
|
import "/lib/math"
|
|
|
|
the contents are accessible by "math.Sin", "math.Cos".
|
|
|
|
Finally, if instead of a package name the import statement uses
|
|
an explicit period, the contents of the imported package are added
|
|
to the current package. After
|
|
|
|
import . "/lib/math"
|
|
|
|
the contents are accessible by "Sin" and "Cos". In this instance, it is
|
|
an error if the import introduces name conflicts.
|
|
|
|
Here is a complete example Go package that implements a concurrent prime sieve:
|
|
|
|
package main
|
|
|
|
// Send the sequence 2, 3, 4, ... to channel 'ch'.
|
|
func generate(ch chan <- int) {
|
|
for i := 2; ; i++ {
|
|
ch <- i // Send 'i' to channel 'ch'.
|
|
}
|
|
}
|
|
|
|
// Copy the values from channel 'in' to channel 'out',
|
|
// removing those divisible by 'prime'.
|
|
func filter(in chan <- int, out *<-chan int, prime int) {
|
|
for {
|
|
i := <-in; // Receive value of new variable 'i' from 'in'.
|
|
if i % prime != 0 {
|
|
out <- i // Send 'i' to channel 'out'.
|
|
}
|
|
}
|
|
}
|
|
|
|
// The prime sieve: Daisy-chain filter processes together.
|
|
func sieve() {
|
|
ch := make(chan int); // Create a new channel.
|
|
go generate(ch); // Start generate() as a subprocess.
|
|
for {
|
|
prime := <-ch;
|
|
print(prime, "\n");
|
|
ch1 := make(chan int);
|
|
go filter(ch, ch1, prime);
|
|
ch = ch1
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
sieve()
|
|
}
|
|
|
|
|
|
----
|
|
|
|
Program initialization and execution
|
|
----
|
|
|
|
When memory is allocated to store a value, either through a declaration
|
|
or "new()", and no explicit initialization is provided, the memory is
|
|
given a default initialization. Each element of such a value is
|
|
set to the ``zero'' for that type: "false" for booleans, "0" for integers,
|
|
"0.0" for floats, '''' for strings, and "nil" for pointers and interfaces.
|
|
This intialization is done recursively, so for instance each element of an
|
|
array of integers will be set to 0 if no other value is specified.
|
|
|
|
These two simple declarations are equivalent:
|
|
|
|
var i int;
|
|
var i int = 0;
|
|
|
|
After
|
|
|
|
type T struct { i int; f float; next *T };
|
|
t := new(T);
|
|
|
|
the following holds:
|
|
|
|
t.i == 0
|
|
t.f == 0.0
|
|
t.next == nil
|
|
|
|
|
|
A package with no imports is initialized by assigning initial values to
|
|
all its global variables in declaration order and then calling any init()
|
|
functions defined in its source. Since a package may contain more
|
|
than one source file, there may be more than one init() function, but
|
|
only one per source file.
|
|
|
|
Initialization code may contain "go" statements, but the functions
|
|
they invoke do not begin execution until initialization is complete.
|
|
Therefore, all initialization code is run in a single thread of
|
|
execution.
|
|
|
|
Furthermore, an "init()" function cannot be referred to from anywhere
|
|
in a program. In particular, "init()" cannot be called explicitly, nor
|
|
can a pointer to "init" be assigned to a function variable).
|
|
|
|
If a package has imports, the imported packages are initialized
|
|
before initializing the package itself. If multiple packages import
|
|
a package P, P will be initialized only once.
|
|
|
|
The importing of packages, by construction, guarantees that there can
|
|
be no cyclic dependencies in initialization.
|
|
|
|
A complete program, possibly created by linking multiple packages,
|
|
must have one package called main, with a function
|
|
|
|
func main() { ... }
|
|
|
|
defined. The function main.main() takes no arguments and returns no
|
|
value.
|
|
|
|
Program execution begins by initializing the main package and then
|
|
invoking main.main().
|
|
|
|
When main.main() returns, the program exits.
|
|
|
|
TODO: is there a way to override the default for package main or the
|
|
default for the function name main.main?
|