From a9ed30ff377976b9e2fd7fb4a897ffda71649474 Mon Sep 17 00:00:00 2001
From: Rob Pike
-A declaration binds an identifier to a language entity such as -a variable or function and specifies properties such as its type. -Every identifier in a program must be declared. -
+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.-Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl . +Type = TypeName | TypeLit | "(" Type ")" . +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.
-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, but inner blocks can declare a new entity with the same -identifier, in which case the scope created by the outer declaration excludes -that created by the inner. -
+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.-There are levels of scoping in effect before each source file is compiled. -In order from outermost to innermost: -
--The scope of an identifier depends on the entity declared: -
- -+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). + -
if
, for
,
- or switch
statement, the
- innermost surrounding block is the block associated
- with that statement.-The following identifiers are implicitly declared in the outermost scope: -
-Basic types: - bool byte float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 - -Platform-specific convenience types: - float int uint uintptr +byte same as uint8 (for convenience) -Constants: - true false iota nil +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) -Functions: - cap convert len make new panic panicln print println typeof (TODO: typeof??) +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) -Packages: - sys unsafe (TODO: does sys endure?) +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+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. -
-By default, identifiers are visible only within the package in which they are declared. -Some identifiers are exported and can be referenced using -qualified identifiers in other packages (§Qualified identifiers). -If an identifier satisfies these two conditions: -
--it will be exported automatically. -
+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.
-A constant declaration binds a list of identifiers (the names of -the constants) to the values of a list of constant expressions -(§Constant expressions). The number of identifiers must be equal -to the number of expressions, and the nth identifier on -the left is bound to value of the nth expression on the -right. -
+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. --ConstDecl = "const" ( ConstSpec | "(" [ ConstSpecList ] ")" ) . -ConstSpecList = ConstSpec { ";" ConstSpec } [ ";" ] . -ConstSpec = IdentifierList [ CompleteType ] [ "=" ExpressionList ] . -IdentifierList = identifier { "," identifier } . -ExpressionList = Expression { "," Expression } . ++The type "bool" comprises the truth values true and false, which are +available through the two predeclared constants, "true" and "false". -Booleans
-CompleteType = Type . -
-If the type (CompleteType) is omitted, the constants take the -individual types of the corresponding expressions, which may be -``ideal integer'' or ``ideal float'' (§Ideal number). If the type -is present, all constants take the type specified, and the types -of all the expressions must be assignment-compatible -with that 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 -+
-Within a parenthesized const
declaration list the
-expression list may be omitted from any but the first declaration.
-Such an empty list is equivalent to the textual substitution of the
-first preceding non-empty expression list. Omitting the list of
-expressions is therefore 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
-(§Iota) this mechanism permits light-weight declaration of sequential values:
+The "string" type represents the set of string values (strings).
+Strings behave like arrays of bytes, with the following properties:
-const ( - Sunday = iota; - Monday; - Tuesday; - Wednesday; - Thursday; - Friday; - Partyday; - numberOfDays; // this constant is not exported -) +a [3]byte; a[0] = 'a'; a[1] = 'b'; a[2] = 'c'; string(a) == "abc";+
-Within a constant declaration, the predeclared pseudo-constant
-iota
represents successive integers. It is reset to 0
-whenever the reserved word const
appears in the source
-and increments with each semicolon. It can be used to construct a
-set of related constants:
-
-const ( // iota is reset to 0 - c0 = iota; // c0 == 0 - c1 = iota; // c1 == 1 - c2 = iota // c2 == 2 -) - -const ( - a = 1 << iota; // a == 1 (iota has been reset) - b = 1 << iota; // b == 2 - c = 1 << iota; // c == 4 -) ++ArrayType = "[" ArrayLength "]" ElementType . +ArrayLength = Expression . +ElementType = CompleteType . +-const ( - u = iota * 42; // u == 0 (ideal integer) - v float = iota * 42; // v == 42.0 (float) - w = iota * 42; // w == 84 (ideal integer) -) +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 -const x = iota; // x == 0 (iota has been reset) -const y = iota; // y == 0 (iota has been reset) +
+len(a)--Within an ExpressionList, the value of each
+The length of arrays is known at compile-time, and the result of a call to +"len(a)" is a compile-time constant.iota
is the same because -it is only incremented at a semicolon: --const ( - bit0, mask0 = 1 << iota, 1 << iota - 1; // bit0 == 1, mask0 == 0 - bit1, mask1; // bit1 == 2, mask1 == 1 - bit2, mask2; // bit2 == 4, mask2 == 3 -) +[32]byte +[2*N] struct { x, y int32 } +[1000]*float64--This last example exploits the implicit repetition of the -last non-empty expression list. -
+Assignment compatibility: Arrays can be assigned to variables of equal type +and to slice variables with equal element type. When assigning to a slice +variable, the array is not copied but a slice comprising the entire array +is created. -Type declarations
+Struct types
--A type declaration binds an identifier, the type name, -to a new type. TODO: what exactly is a "new type"? -
+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).-TypeDecl = "type" ( TypeSpec | "(" [ TypeSpecList ] ")" ) . -TypeSpecList = TypeSpec { ";" TypeSpec } [ ";" ] . -TypeSpec = identifier Type . +StructType = "struct" [ "{" [ FieldDeclList ] "}" ] . +FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] . +FieldDecl = (IdentifierList CompleteType | [ "*" ] TypeName) [ Tag ] . +Tag = StringLit .-type IntArray [16] int - -type ( - Point struct { x, y float }; - Polar Point -) - -type TreeNode struct { - left, right *TreeNode; - value Point; -} +// An empty struct. +struct {} -type Comparable interface { - cmp(Comparable) int +// A struct with 5 fields. +struct { + x, y int; + u float; + A *[]int; + F func(); }-Variable declarations
+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 variable declaration creates a variable, binds an identifier to it and -gives it a type and optionally an initial value. -The variable type must be a complete type (§Types). -
--VarDecl = "var" ( VarSpec | "(" [ VarSpecList ] ")" ) . -VarSpecList = VarSpec { ";" VarSpec } [ ";" ] . -VarSpec = IdentifierList ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) . ++// 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: +-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" -) +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).-If there are expressions, their number must be equal -to the number of identifiers, and the nth variable -is initialized to the value of the nth expression. -Otherwise, each variable is initialized to the zero -of the type (§Program initialization and execution). -The expressions can be general expressions; they need not be constants. -
--Either the type or the expression list must be present. If the -type is present, it sets the type of each variable and the expressions -(if any) must be assignment-compatible to that type. If the type -is absent, the variables take the types of the corresponding -expressions. -
--If the type is absent and the corresponding expression is a constant -expression of ideal integer or ideal float type, the type of the -declared variable is
+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.int
orfloat
-respectively: --var i = 0 // i has type int -var f = 3.1415 // f has type float +// 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"; +}-Short variable declarations
+Assignment compatibility: Structs are assignment compatible to variables of +equal type only. -A short variable declaration uses the syntax --SimpleVarDecl = IdentifierList ":=" ExpressionList . -+Pointer types
-and is shorthand for the declaration syntax +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".-"var" IdentifierList = ExpressionList . +PointerType = "*" BaseType . +BaseType = Type .-i, j := 0, 10; -f := func() int { return 7; } -ch := new(chan int); +*int +map[string] chan--Unlike regular variable declarations, short variable declarations -can be used, by analogy with tuple assignment (§Assignments), to -receive the individual elements of a multi-valued expression such -as a call to a multi-valued function. In this form, the ExpressionLIst -must be a single such multi-valued expression, the number of -identifiers must equal the number of values, and the declared -variables will be assigned the corresponding values. -
+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:-count, error := os.Close(fd); // os.Close() returns two values +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.-Short variable declarations may appear only inside functions. -In some contexts such as the initializers for
- -if
, -for
, orswitch
statements, -they can be used to declare local temporary variables (§Statements). -Function declarations
- +Comparisons: A variable of pointer type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution).-A function declaration binds an identifier to a function (§Function types). -
+Two variables of equal pointer type can be tested for equality with the +operators "==" and "!=" (§Comparison operators). The pointers are equal +if they point to the same location. --FunctionDecl = "func" identifier Signature [ Block ] . -+Pointer arithmetic of any kind is not permitted. --func min(x int, y int) int { - if x < y { - return x; - } - return y; -} ---A function must be declared or forward-declared before it can be invoked (§Forward declarations). -Implementation restriction: Functions can only be declared at the package level. -
+Function types
-Method declarations
+A function type denotes the set of all functions with the same parameter +and result types, and the value "nil". --A method declaration binds an identifier to a method, -which is a function with a receiver. -
-MethodDecl = "func" Receiver identifier Signature [ Block ] . -Receiver = "(" [ identifier ] [ "*" ] TypeName ")" . +FunctionType = "func" Signature . +Signature = "(" [ 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.-The receiver type must be a type name or a pointer to a type name, -and that name is called the receiver base type or just base type. -The base type must not be a pointer type and must be -declared in the same source file as the method. -The method is said to be bound to the base type -and is visible only within selectors for that type -(§Type declarations, §Selectors). -
- --All methods bound to a base type must have the same receiver type, -either all pointers to the base type or all the base type itself. -Given 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).Point
, the declarations --func (p *Point) Length() float { - return Math.sqrt(p.x * p.x + p.y * p.y); -} +func () +func (x int) +func () int +func (string, float, ...) +func (a, b int, z float) bool +func (a, b int, z float) (bool) +func (a, b int, z float, opt ...) (success bool) +func (int, int, float) (float, *[]int) +-func (p *Point) Scale(factor float) { - p.x = p.x * factor; - p.y = p.y * factor; -} +If the result type of a function is itself a function type, the result type +must be parenthesized to resolve a parsing ambiguity: + ++func (n int) (func (p* T))+Assignment compatibility: A function can be assigned to a function +variable only if both function types are equal.-bind the methods
- +Comparisons: A variable of function type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution).Length
andScale
-to the base typePoint
. --If the -receiver's value is not referenced inside the the body of the method, -its identifier may be omitted in the declaration. The same applies in -general to parameters of functions and methods. -
+Two variables of equal function type can be tested for equality with the +operators "==" and "!=" (§Comparison operators). The variables are equal +if they refer to the same function. --Methods can be declared -only after their base type is declared or forward-declared, and invoked -only after their own declaration or forward-declaration (§Forward declarations). -Implementation restriction: They can only be declared at package level. -
-Forward declarations
+Interface types
--Mutually-recursive types struct or interface types require that one be -forward declared so that it may be named in the other. -A forward declaration of a type omits the block containing the fields -or methods of the type. -
+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 Signature | TypeName . +-type List struct // forward declaration of List -type Item struct { - value int; - next *List; -} -type List struct { - head, tail *Item +// An interface specifying a basic File type. +interface { + Read, Write (b Buffer) bool; + Close (); }--A forward-declared type is incomplete (§Types) -until it is fully declared. The full declaration must follow -before the end of the block containing the forward declaration. -
--Functions and methods may similarly be forward-declared by omitting their body. -
+ +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 F(a int) int // forward declaration of F -func G(a, b int) int { - return F(a) + F(b) -} -func F(a int) int { - if a <= 0 { return 0 } - return G(a-1, b+1) -} +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. -Types
+All types implement the empty interface: -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. +
+interface {} +--Type = TypeName | TypeLit | "(" Type ")" . -TypeName = QualifiedIdent. -TypeLit = - ArrayType | StructType | PointerType | FunctionType | InterfaceType | - SliceType | MapType | ChannelType . +In general, a type implements an arbitrary number of interfaces. +For instance, consider the interface + ++type Lock interface { + Lock, Unlock (); +}-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. +If S1 and S2 also implement -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. +
+func (p T) Lock() { ... } +func (p T) Unlock() { ... } ++ +they implement the Lock interface as well as the File interface.-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). - +An interface may contain a type name T in place of a method specification. +T must denote another, complete (and not forward-declared) interface type. +Using this notation is equivalent to enumerating the methods of T explicitly +in the interface containing T. -
Basic types
++type ReadWrite interface { + Read, Write (b Buffer) bool; +} -Go defines a number of basic types, referred to by their predeclared -type names. These include traditional arithmetic types, booleans, -and strings. +type File interface { + ReadWrite; // same as enumerating the methods in ReadWrite + Lock; // same as enumerating the methods in Lock + Close(); +} ++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: -Arithmetic types
++type T2 interface +type T1 interface { + foo(T2) int; +} +type T2 interface { + bar(T1) int; +} +-The following list enumerates all platform-independent numeric types: +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". ++Comparisons: A variable of interface type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution). +
+Two variables of interface type can be tested for equality with the +operators "==" and "!=" (§Comparison operators) if both variables have the +same static type. They are equal if both their dynamic types and values are +equal. If the dynamic types are equal but the values do not support comparison, +a run-time error occurs. -
-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) +Slice types
-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) +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. -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 ++SliceType = "[" "]" ElementType .-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. +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) +-Additionally, Go declares a set of platform-specific numeric types for -convenience: +and the following relationship between "len()" and "cap()" holds: --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 ++0 <= len(a) <= cap(a)-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. +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) +-Booleans
+is effectively the same as allocating an array and slicing it -The type "bool" comprises the truth values true and false, which are -available through the two predeclared constants, "true" and "false". ++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: -
Strings
++a[i] ++This denotes the slice element at index "i". "i" must be within bounds, +that is "0 <= i < len(a)".-The "string" type represents the set of string values (strings). -Strings behave like arrays of bytes, with the following properties: -
-
-a [3]byte; a[0] = 'a'; a[1] = 'b'; a[2] = 'c'; string(a) == "abc"; +a[i : j]-
+Comparisons: A variable of slice type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution). -
-ArrayType = "[" ArrayLength "]" ElementType . -ArrayLength = Expression . -ElementType = CompleteType . +MapType = "map" "[" KeyType "]" ValueType . +KeyType = CompleteType . +ValueType = 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 comparison operators "==" and "!=" (§Comparison operators) must be defined +for operands of the key type; thus the key type must be a basic, pointer, +interface, or channel type. If the key type is an interface type, +the dynamic key types must support these comparison operators. In this case, +inserting a map value with a key that does not support testing for equality +is a run-time error.
-The number of elements of an array "a" can be discovered using the built-in -function +Upon creation, a map is empty and values may be added and removed +during execution.
-len(a) +map [string] int +map [*T] struct { x, y float } +map [string] interface {}-The length of arrays is known at compile-time, and the result of a call to -"len(a)" is a compile-time constant. +The length of a map "m" can be discovered using the built-in function
-[32]byte -[2*N] struct { x, y int32 } -[1000]*float64 +len(m)-Assignment compatibility: Arrays can be assigned to variables of equal type -and to slice variables with equal element type. When assigning to a slice -variable, the array is not copied but a slice comprising the entire array -is created. +The value of an uninitialized map is "nil". A new, empty map value for given +map type M is made using the built-in function "make" which takes the map type +and an optional capacity as arguments: +
+my_map := make(M, 100); +-
+Assignment compatibility: A map type is assignment compatible to a variable of +map type only if both types are equal. +
+Comparisons: A variable of map type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution). -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 = StringLit . -+
-// An empty struct. -struct {} +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?) -// A struct with 5 fields. -struct { - x, y int; - u float; - A *[]int; - F func(); -} ++ChannelType = Channel | SendChannel | RecvChannel . +Channel = "chan" ValueType . +SendChannel = "chan" "<-" ValueType . +RecvChannel = "<-" "chan" ValueType .-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. +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.-// 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; -} +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 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: +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:-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 -} +my_chan = make(chan int, 100);-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). +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.-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. +Assignment compatibility: A value of type channel can be assigned to a variable +of type channel only if a) both types are equal (§Type equality), or b) both +have equal channel value types and the value is a bidirectional channel. +
+Comparisons: A variable of channel type can be compared against "nil" with the +operators "==" and "!=" (§Comparison operators). The variable is +"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or +if the variable has not been modified since creation (§Program initialization +and execution). +
+Two variables of channel type can be tested for equality with the +operators "==" and "!=" (§Comparison operators) if both variables have +the same ValueType. They are equal if both values were created by the same +"make" call (§Making slices, maps, and channels). -
-// 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"; -} --Assignment compatibility: Structs are assignment compatible to variables of -equal type only. +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 structurally +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: +
+
-PointerType = "*" BaseType . -BaseType = Type . -+
-*int -map[string] chan -+
-type S struct { s *S } +
+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: +
+-Comparisons: A variable of pointer type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution). -
-Two variables of equal pointer type can be tested for equality with the -operators "==" and "!=" (§Comparison operators). The pointers are equal -if they point to the same location. +
+Finally, two types are different if they are not structurally equal. +(By definition, they cannot be identical, either). -
-FunctionType = "func" Signature . -Signature = "(" [ ParameterList ] ")" [ Result ] . -ParameterList = ParameterDecl { "," ParameterDecl } . -ParameterDecl = [ IdentifierList ] ( Type | "..." ) . -Result = Type | "(" ParameterList ")" . +For instance, given the declarations + ++type ( + T0 []string; + T1 []string + T2 struct { a, b int }; + T3 struct { a, c int }; + T4 func (int, float) *T0 + T5 func (x int, y float) *[]string +)-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). +these are some types that are equal
-func () -func (x int) -func () int -func (string, float, ...) -func (a, b int, z float) bool -func (a, b int, z float) (bool) -func (a, b int, z float, opt ...) (success bool) -func (int, int, float) (float, *[]int) +T0 and T0 +T0 and []string +T2 and T3 +T4 and T5 +T3 and struct { a int; int }-If the result type of a function is itself a function type, the result type -must be parenthesized to resolve a parsing ambiguity: +and these are some types that are identical-func (n int) (func (p* T)) +T0 and T0 +[]int and []int +struct { a, b *T5 } and struct { a, b *T5 }-Assignment compatibility: A function can be assigned to a function -variable only if both function types are equal. --Comparisons: A variable of function type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution). -
-Two variables of equal function type can be tested for equality with the -operators "==" and "!=" (§Comparison operators). The variables are equal -if they refer to the same function. +As an example, "T0" and "T1" are equal but not identical because they have +different declarations. +
-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". +Declarations and Scope
+ ++A declaration binds an identifier to a language entity such as +a variable or function and specifies properties such as its type. +Every identifier in a program must be declared. +
-InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] . -MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] . -MethodSpec = IdentifierList Signature | TypeName . +Declaration = ConstDecl | TypeDecl | VarDecl | FunctionDecl | MethodDecl .+ ++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, but inner blocks can declare a new entity with the same +identifier, in which case the scope created by the outer declaration excludes +that created by the inner. +
++There are levels of scoping in effect before each source file is compiled. +In order from outermost to innermost: +
++
-- The universe scope contains all predeclared identifiers.
+- An implicit scope contains only the package name.
+- The package-level scope surrounds all declarations at the + top level of the file, that is, outside the body of any + function or method. That scope is shared across all + source files within the package (§Packages), allowing + package-level identifiers to be shared between source + files.
+-// An interface specifying a basic File type. -interface { - Read, Write (b Buffer) bool; - Close (); -} -++The scope of an identifier depends on the entity declared: +
-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 ++
-- The scope of predeclared identifiers is the universe scope.
--func (p T) Read(b Buffer) bool { return ... } -func (p T) Write(b Buffer) bool { return ... } -func (p T) Close() { ... } -+- The scope of an (identifier denoting a) type, function or package + extends from the point of the identifier in the declaration + to the end of the innermost surrounding block.
-(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. +- The scope of a constant or variable extends textually from + the end of the declaration to the end of the innermost + surrounding block. If the variable is declared in the + init statement of an
-All types implement the empty interface: +if
,for
, + orswitch
statement, the + innermost surrounding block is the block associated + with that statement.- The scope of a parameter or result is the body of the + corresponding function.
--interface {} -+- The scope of a field or method is selectors for the + corresponding type containing the field or method (§Selectors).
-In general, a type implements an arbitrary number of interfaces. -For instance, consider the interface +- The scope of a label is a unique scope emcompassing + the body of the innermost surrounding function, excluding + nested functions. Labels do not conflict with variables.
+-type Lock interface { - Lock, Unlock (); -} -+Predeclared identifiers
-If S1 and S2 also implement ++The following identifiers are implicitly declared in the outermost scope: +
++Basic types: + bool byte float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 --func (p T) Lock() { ... } -func (p T) Unlock() { ... } -+Platform-specific convenience types: + float int uint uintptr -they implement the Lock interface as well as the File interface. --An interface may contain a type name T in place of a method specification. -T must denote another, complete (and not forward-declared) interface type. -Using this notation is equivalent to enumerating the methods of T explicitly -in the interface containing T. +Constants: + true false iota nil -
-type ReadWrite interface { - Read, Write (b Buffer) bool; -} +Functions: + cap convert len make new panic panicln print println typeof (TODO: typeof??) -type File interface { - ReadWrite; // same as enumerating the methods in ReadWrite - Lock; // same as enumerating the methods in Lock - Close(); -} +Packages: + sys unsafe (TODO: does sys endure?)-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; -} -+Exported identifiers
-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".-Comparisons: A variable of interface type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution). +By default, identifiers are visible only within the package in which they are declared. +Some identifiers are exported and can be referenced using +qualified identifiers in other packages (§Qualified identifiers). +If an identifier satisfies these two conditions: +
++
- the first character of the identifier's name is a Unicode upper case letter; +
- the identifier is declared at the package level or is a field or method of a type +declared at the top level; +
-Two variables of interface type can be tested for equality with the -operators "==" and "!=" (§Comparison operators) if both variables have the -same static type. They are equal if both their dynamic types and values are -equal. If the dynamic types are equal but the values do not support comparison, -a run-time error occurs. - +it will be exported automatically. +
-Slice types
+Const declarations
-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. ++A constant declaration binds a list of identifiers (the names of +the constants) to the values of a list of constant expressions +(§Constant expressions). The number of identifiers must be equal +to the number of expressions, and the nth identifier on +the left is bound to value of the nth expression on the +right. +
-SliceType = "[" "]" ElementType . -+ConstDecl = "const" ( ConstSpec | "(" [ ConstSpecList ] ")" ) . +ConstSpecList = ConstSpec { ";" ConstSpec } [ ";" ] . +ConstSpec = IdentifierList [ CompleteType ] [ "=" ExpressionList ] . -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 +IdentifierList = identifier { "," identifier } . +ExpressionList = Expression { "," Expression } . -
-cap(a) +CompleteType = Type .-and the following relationship between "len()" and "cap()" holds: ++If the type (CompleteType) is omitted, the constants take the +individual types of the corresponding expressions, which may be +``ideal integer'' or ``ideal float'' (§Ideal number). If the type +is present, all constants take the type specified, and the types +of all the expressions must be assignment-compatible +with that type. +
-0 <= len(a) <= cap(a) +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-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" ++Within a parenthesized
const
declaration list the +expression list may be omitted from any but the first declaration. +Such an empty list is equivalent to the textual substitution of the +first preceding non-empty expression list. Omitting the list of +expressions is therefore equivalent to repeating the previous list. +The number of identifiers must be equal to the number of expressions +in the previous list. Together with theiota
constant generator +(§Iota) this mechanism permits light-weight declaration of sequential values: +-make([]T, length, capacity) +const ( + Sunday = iota; + Monday; + Tuesday; + Wednesday; + Thursday; + Friday; + Partyday; + numberOfDays; // this constant is not exported +)-is effectively the same as allocating an array and slicing it --new([capacity]T)[0 : length] -+Iota
-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: +Within a constant declaration, the predeclared pseudo-constant +
iota
represents successive integers. It is reset to 0 +whenever the reserved wordconst
appears in the source +and increments with each semicolon. It can be used to construct a +set of related constants: +-a[i] +const ( // iota is reset to 0 + c0 = iota; // c0 == 0 + c1 = iota; // c1 == 1 + c2 = iota // c2 == 2 +) + +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)-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: +Within an ExpressionList, the value of each
iota
is the same because +it is only incremented at a semicolon: +-a[i : j] +const ( + bit0, mask0 = 1 << iota, 1 << iota - 1; // bit0 == 1, mask0 == 0 + bit1, mask1; // bit1 == 2, mask1 == 1 + bit2, mask2; // bit2 == 4, mask2 == 3 +)-This creates the sub-slice consisting of the elements "a[i]" through "a[j - 1]" -(that is, excluding "a[j]"). The values "i" and "j" must satisfy the condition -"0 <= 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.-Comparisons: A variable of slice type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution). +This last example exploits the implicit repetition of the +last non-empty expression list. +
-Map types
+Type declarations
-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. ++A type declaration binds an identifier, the type name, +to a new type. TODO: what exactly is a "new type"? +
-MapType = "map" "[" KeyType "]" ValueType . -KeyType = CompleteType . -ValueType = CompleteType . +TypeDecl = "type" ( TypeSpec | "(" [ TypeSpecList ] ")" ) . +TypeSpecList = TypeSpec { ";" TypeSpec } [ ";" ] . +TypeSpec = identifier Type .-The comparison operators "==" and "!=" (§Comparison operators) must be defined -for operands of the key type; thus the key type must be a basic, pointer, -interface, or channel type. If the key type is an interface type, -the dynamic key types must support these comparison operators. In this case, -inserting a map value with a key that does not support testing for equality -is a run-time error. --Upon creation, a map is empty and values may be added and removed -during execution. -
-map [string] int -map [*T] struct { x, y float } -map [string] interface {} -+type IntArray [16] int -The length of a map "m" can be discovered using the built-in function +type ( + Point struct { x, y float }; + Polar Point +) --len(m) +type TreeNode struct { + left, right *TreeNode; + value Point; +} + +type Comparable interface { + cmp(Comparable) int +}-The value of an uninitialized map is "nil". A new, empty map value for given -map type M is made using the built-in function "make" which takes the map type -and an optional capacity as arguments: +Variable declarations
+ ++A variable declaration creates a variable, binds an identifier to it and +gives it a type and optionally an initial value. +The variable type must be a complete type (§Types). +
++VarDecl = "var" ( VarSpec | "(" [ VarSpecList ] ")" ) . +VarSpecList = VarSpec { ";" VarSpec } [ ";" ] . +VarSpec = IdentifierList ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) . +-my_map := make(M, 100); +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" +)-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. +If there are expressions, their number must be equal +to the number of identifiers, and the nth variable +is initialized to the value of the nth expression. +Otherwise, each variable is initialized to the zero +of the type (§Program initialization and execution). +The expressions can be general expressions; they need not be constants. +
-Comparisons: A variable of map type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution). +Either the type or the expression list must be present. If the +type is present, it sets the type of each variable and the expressions +(if any) must be assignment-compatible to that type. If the type +is absent, the variables take the types of the corresponding +expressions. +
++If the type is absent and the corresponding expression is a constant +expression of ideal integer or ideal float type, the type of the +declared variable is
+int
orfloat
+respectively: ++var i = 0 // i has type int +var f = 3.1415 // f has type float +-Channel types
+Short variable declarations
-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?) +A short variable declaration uses the syntax-ChannelType = Channel | SendChannel | RecvChannel . -Channel = "chan" ValueType . -SendChannel = "chan" "<-" ValueType . -RecvChannel = "<-" "chan" ValueType . +SimpleVarDecl = IdentifierList ":=" ExpressionList .-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. +and is shorthand for the declaration syntax --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 ++"var" IdentifierList = ExpressionList .-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); +i, j := 0, 10; +f := func() int { return 7; } +ch := new(chan int);-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: A value of type channel can be assigned to a variable -of type channel only if a) both types are equal (§Type equality), or b) both -have equal channel value types and the value is a bidirectional channel. -
-Comparisons: A variable of channel type can be compared against "nil" with the -operators "==" and "!=" (§Comparison operators). The variable is -"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or -if the variable has not been modified since creation (§Program initialization -and execution).
-Two variables of channel type can be tested for equality with the -operators "==" and "!=" (§Comparison operators) if both variables have -the same ValueType. They are equal if both values were created by the same -"make" call (§Making slices, maps, and channels). - +Unlike regular variable declarations, short variable declarations +can be used, by analogy with tuple assignment (§Assignments), to +receive the individual elements of a multi-valued expression such +as a call to a multi-valued function. In this form, the ExpressionLIst +must be a single such multi-valued expression, the number of +identifiers must equal the number of values, and the declared +variables will be assigned the corresponding values. +
-Type equality
++count, error := os.Close(fd); // os.Close() returns two values +-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 structurally -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: +Short variable declarations may appear only inside functions. +In some contexts such as the initializers for
-if
, +for
, orswitch
statements, +they can be used to declare local temporary variables (§Statements).
+A function declaration binds an identifier to a function (§Function types). +
-+FunctionDecl = "func" identifier Signature [ Block ] . +-
+func min(x int, y int) int { + if x < y { + return x; + } + return y; +} +-
+A function must be declared or forward-declared before it can be invoked (§Forward declarations). +Implementation restriction: Functions can only be declared at the package level. +
--Type identity is defined by these rules: +A method declaration binds an identifier to a method, +which is a function with a receiver.
++MethodDecl = "func" Receiver identifier Signature [ Block ] . +Receiver = "(" [ identifier ] [ "*" ] TypeName ")" . ++
-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: +The receiver type must be a type name or a pointer to a type name, +and that name is called the receiver base type or just base type. +The base type must not be a pointer type and must be +declared in the same source file as the method. +The method is said to be bound to the base type +and is visible only within selectors for that type +(§Type declarations, §Selectors).
-
+All methods bound to a base type must have the same receiver type,
+either all pointers to the base type or all the base type itself.
+Given type Point
, the declarations
+
+func (p *Point) Length() float { + return Math.sqrt(p.x * p.x + p.y * p.y); +} -
+bind the methods Length
and Scale
+to the base type Point
.
+
-Finally, two types are different if they are not structurally equal. -(By definition, they cannot be identical, either). +If the +receiver's value is not referenced inside the the body of the method, +its identifier may be omitted in the declaration. The same applies in +general to parameters of functions and methods. +
-For instance, given the declarations ++Methods can be declared +only after their base type is declared or forward-declared, and invoked +only after their own declaration or forward-declaration (§Forward declarations). +Implementation restriction: They can only be declared at package level. +
--type ( - T0 []string; - T1 []string - T2 struct { a, b int }; - T3 struct { a, c int }; - T4 func (int, float) *T0 - T5 func (x int, y float) *[]string -) -+
+Mutually-recursive types struct or interface types require that one be +forward declared so that it may be named in the other. +A forward declaration of a type omits the block containing the fields +or methods of the type. +
-T0 and T0 -T0 and []string -T2 and T3 -T4 and T5 -T3 and struct { a int; int } +type List struct // forward declaration of List +type Item struct { + value int; + next *List; +} +type List struct { + head, tail *Item +}- -and these are some types that are identical - +
+A forward-declared type is incomplete (§Types) +until it is fully declared. The full declaration must follow +before the end of the block containing the forward declaration. +
++Functions and methods may similarly be forward-declared by omitting their body. +
-T0 and T0 -[]int and []int -struct { a, b *T5 } and struct { a, b *T5 } +func F(a int) int // forward declaration of F +func G(a, b int) int { + return F(a) + F(b) +} +func F(a int) int { + if a <= 0 { return 0 } + return G(a-1, b+1) +}-As an example, "T0" and "T1" are equal but not identical because they have -different declarations. -