Introduction
引言
This is a reference manual for the Go programming language. For more information and other documents, see golang.org.
这是一份关于 Go 语言的参考手册。欲获取更多信息与文档, 请访问 go-zh.org。
Go is a general-purpose language designed with systems programming in mind. It is strongly typed and garbage-collected and has explicit support for concurrent programming. Programs are constructed from packages, whose properties allow efficient management of dependencies.
Go 是通用型的编程语言,它为系统编程而设计。它是强类型化的语言,具有垃圾回收机制, 并显式支持并发编程。程序由包构造,以此来提供高效的依赖管理功能。 既有实现使用传统的“编译 - 链接”模型,生成可执行的二进制文件。
The grammar is compact and regular, allowing for easy analysis by automatic tools such as integrated development environments.
其语法紧凑而规则,便于 IDE 等自动化工具分析。
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 "}" .
语法使用扩展巴克斯-诺尔范式(EBNF)定义:
生成式 = 生成式名 "=" [ 表达式 ] "." . 表达式 = 选择项 { "|" 选择项 } . 选择项 = 条目 { 条目 } . 条目 = 生成式名 | 标记 [ "…" 标记 ] | 分组 | 可选项 | 重复项 . 分组 = "(" 表达式 ")" . 可选项 = "[" 表达式 "]" . 重复项 = "{" 表达式 "}" .
Productions are expressions constructed from terms and the following operators, in increasing precedence:
| alternation () grouping [] option (0 or 1 times) {} repetition (0 to n times)
生成式由表达式构造,表达式通过术语及以下操作符构造,自上而下优先级递增(低=>高):
| 选择 () 分组 [] 可选(0 或 1 次) {} 重复(0 到 n 次)
Lower-case production names are used to identify lexical tokens.
Non-terminals are in CamelCase. Lexical tokens are enclosed in
double quotes ""
or back quotes ``
.
小写生成式名用于标识词法标记。非最终(Non-terminals)词法标记使用驼峰记法(CamelCase)。
位于双引号 ""
或反引号 ``
内的即为词法标记。
The form a … b
represents the set of characters from
a
through b
as alternatives. The horizontal
ellipsis …
is also used elsewhere in the spec to informally denote various
enumerations or code snippets that are not further specified. The character …
(as opposed to the three characters ...
) is not a token of the Go
language.
形式 a … b
表示把从 a
到 b
的字符集作为选择项。
横向省略号 …
也在本文档中非正式地表示各种列举或简略的代码片断。
单个字符 …
(不同于三个字符 ...
)并非 Go 语言本身的标记。
Source code representation
源码的表示
Source code is Unicode text encoded in UTF-8. The text is not canonicalized, so a single accented code point is distinct from the same character constructed from combining an accent and a letter; those are treated as two code points. For simplicity, this document will use the unqualified term character to refer to a Unicode code point in the source text.
源码为采用 UTF-8 编码的 Unicode 文本, 其文本并未标准化。因此单个带变音符号的码点不同于结合了字母与变音符号的字符结构, 它们应视作两个码点。为简单起见,本文档将使用非正式的术语字符在源文本中指代 Unicode 码点。
Each code point is distinct; for instance, upper and lower case letters are different characters.
每个码点都是不同的,例如,大写与小写的字母就是不同的字符。
Implementation restriction: For compatibility with other tools, a compiler may disallow the NUL character (U+0000) in the source text.
实现限制:为兼容其它工具,编译器会阻止字符 NUL(U+0000)出现在源码文本中。
Implementation restriction: For compatibility with other tools, a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF) if it is the first Unicode code point in the source text. A byte order mark may be disallowed anywhere else in the source.
实现限制:为兼容其它工具,若 UTF-8 编码的字节序标记(U+FEFF)为源文本中的第一个 Unicode 码点,那么编译器就会忽略它。字节序标记不允许在源文件中的其它任何地方出现。
Characters
字符
The following terms are used to denote specific Unicode character classes:
具体的 Unicode 字符类别由以下术语表示:
newline = /* the Unicode code point U+000A */ . unicode_char = /* an arbitrary Unicode code point except newline */ . unicode_letter = /* a Unicode code point classified as "Letter" */ . unicode_digit = /* a Unicode code point classified as "Number, decimal digit" */ .
换行符 = /* 即 Unicode 码点 U+000A */ . Unicode字符 = /* 除换行符以外的任意 Unicode 码点 */ . Unicode字母 = /* 类型为“字母”的 Unicode 码点 */ . Unicode数字 = /* 类型为“数值,十进制数字”的 Unicode 码点 */ .
In The Unicode Standard 8.0, Section 4.5 "General Category" defines a set of character categories. Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo as Unicode letters, and those in the Number category Nd as Unicode digits.
在Unicode 标准 8.0, 章节 4.5“一般类别”中定义了字符集类别。其中类别 Lu,Ll,Lt,Lm 及 Lo 被视为 Unicode 字母,类别 Nd 被视为 Unicode 数字。
Letters and digits
字母和数字
The underscore character _
(U+005F) is considered a letter.
下划线字符 _
(U+005F)被视为一个字母。
letter = unicode_letter | "_" . decimal_digit = "0" … "9" . octal_digit = "0" … "7" . hex_digit = "0" … "9" | "A" … "F" | "a" … "f" .
字母 = Unicode字母 | "_" . 十进制数字 = "0" … "9" . 八进制数字 = "0" … "7" . 十六进制数字 = "0" … "9" | "A" … "F" | "a" … "f" .
Lexical elements
词法元素
Comments
注释
Comments serve as program documentation. There are two forms:
注释会作为程序文档,它们有两种形式:
-
Line comments start with the character sequence
//
and stop at the end of the line. -
General comments start with the character sequence
/*
and stop with the first subsequent character sequence*/
.
-
行注释以字符序列
//
开始,至行尾结束。 -
块注释以字符序列
/*
开始,至其后的第一处字符序列*/
结束。
A comment cannot start inside a rune or string literal, or inside a comment. A general comment containing no newlines acts like a space. Any other comment acts like a newline.
注释不能从 符文 或 字符串字面 中开始,也不能在其它注释中。 不包含换行符的块注释视作一个空格,其余任何注释均视做一个换行符。
Tokens
标记
Tokens form the vocabulary of the Go language. There are four classes: identifiers, keywords, operators and punctuation, and literals. White space, formed from spaces (U+0020), horizontal tabs (U+0009), carriage returns (U+000D), and newlines (U+000A), is ignored except as it separates tokens that would otherwise combine into a single token. Also, a newline or end of file may trigger the insertion of a semicolon. While breaking the input into tokens, the next token is the longest sequence of characters that form a valid token.
标记构成 Go 语言的词汇。它有四种类型:标识符,关键字, 运算符与标点以及字面。空白符包括空格(U+0020), 横向制表符(U+0009),回车符(U+000D)和换行符(U+000A),除非用它们来分隔会结合成单个的标记, 否则将被忽略。此外,换行符或 EOF(文件结束符)会触发分号的插入。 当把输入分解为标记时,可形成有效标记的最长字符序列将作为下一个标记。
Semicolons
分号
The formal grammar uses semicolons ";"
as terminators in
a number of productions. Go programs may omit most of these semicolons
using the following two rules:
正式语法使用分号 ";"
作为一些生成式的终止符。Go 程序会使用以下两条规则来省略大多数分号:
-
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
- an identifier
- an integer, floating-point, imaginary, rune, or string literal
- one of the keywords
break
,continue
,fallthrough
, orreturn
- one of the operators and punctuation
++
,--
,)
,]
, or}
-
To allow complex statements to occupy a single line, a semicolon
may be omitted before a closing
")"
or"}"
.
-
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
当输入被分解成标记时,若该行的最后一个标记为以下之一,那么分号就会在该标记之后立即自动插入:
-
为允许复合语句占据单行,闭合的
")"
或"}"
之前的分号可以省略。
To reflect idiomatic use, code examples in this document elide semicolons using these rules.
为符合习惯用法,本文档中的代码示例将使用这些规则省略分号。
Identifiers
标识符
Identifiers name program entities such as variables and types. An identifier is a sequence of one or more letters and digits. The first character in an identifier must be a letter.
identifier = letter { letter | unicode_digit } .
标识符被用来命名程序实体,例如变量和类型。一个标识符由一个或多个字母和数字组成。 标识符的第一个字符必须是字母。
标识符 = 字母 { 字母 | Unicode数字 } .
a _x9 ThisVariableIsExported αβ
Some identifiers are predeclared.
有些标识符是预声明的。
Keywords
关键字
The following keywords are reserved and may not be used as identifiers.
以下为保留关键字,不能用作标识符。
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
Operators and punctuation
运算符与标点
The following character sequences represent operators (including assignment operators) and punctuation:
+ & += &= && == != ( ) - | -= |= || < <= [ ] * ^ *= ^= <- > >= { } / << /= <<= ++ = := , ; % >> %= >>= -- ! ... . : &^ &^=
Integer literals
整数字面
An integer literal is a sequence of digits representing an
integer constant.
An optional prefix sets a non-decimal base: 0
for octal, 0x
or
0X
for hexadecimal. In hexadecimal literals, letters
a-f
and A-F
represent values 10 through 15.
int_lit = decimal_lit | octal_lit | hex_lit . decimal_lit = ( "1" … "9" ) { decimal_digit } . octal_lit = "0" { octal_digit } . hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } .
整数字面由数字序列组成,代表整数常量 。非十进制数由这些前缀定义:
0
为八进制数前缀,0x
或 0X
为十六进制数前缀。
在十六进制数字面中,字母 a-f
或 A-F
表示值 10 到 15。
整数字面 = 十进制数字面 | 八进制数字面 | 十六进制数字面 . 十进制数字面 = ( "1" … "9" ) { 十进制数字 } . 八进制数字面 = "0" { 八进制数字 } . 十六进制数字面 = "0" ( "x" | "X" ) 十六进制数字 { 十六进制数字 } .
42 0600 0xBadFace 170141183460469231731687303715884105727
Floating-point literals
浮点数字面
A floating-point literal is a decimal representation of a
floating-point constant.
It has an integer part, a decimal point, a fractional part,
and an exponent part. The integer and fractional part comprise
decimal digits; the exponent part is an e
or E
followed by an optionally signed decimal exponent. One of the
integer part or the fractional part may be elided; one of the decimal
point or the exponent may be elided.
float_lit = decimals "." [ decimals ] [ exponent ] | decimals exponent | "." decimals [ exponent ] . decimals = decimal_digit { decimal_digit } . exponent = ( "e" | "E" ) [ "+" | "-" ] decimals .
浮点数字面由十进制浮点常量表示。
它由整数部分,小数点,小数部分和指数部分构成。整数部分与小数部分由十进制数字组成;
指数部分由一个 e
或 E
紧跟一个带可选正负号的十进制指数构成。
整数部分或小数部分可以省略;小数点或指数亦可省略。
浮点数字面 = 十进制数 "." [ 十进制数 ] [ 指数 ] | 十进制指数 | "." 十进制数 [ 指数 ] . 十进制数 = 十进制数字 { 十进制数字 } . 指数 = ( "e" | "E" ) [ "+" | "-" ] 十进制数 .
0. 72.40 072.40 // == 72.40 2.71828 1.e+0 6.67428e-11 1E6 .25 .12345E+5
Imaginary literals
虚数字面
An imaginary literal is a decimal representation of the imaginary part of a
complex constant.
It consists of a
floating-point literal
or decimal integer followed
by the lower-case letter i
.
imaginary_lit = (decimals | float_lit) "i" .
虚数字面由十进制复数常量的虚部表示。
它由浮点数字面或十进制整数紧跟小写字母 i
构成。
虚数字面 = (十进制数 | 浮点数字面) "i" .
0i 011i // == 11i 0.i 2.71828i 1.e+0i 6.67428e-11i 1E6i .25i .12345E+5i
Rune literals
符文字面
A rune literal represents a rune constant,
an integer value identifying a Unicode code point.
A rune literal is expressed as one or more characters enclosed in single quotes,
as in 'x'
or '\n'
.
Within the quotes, any character may appear except newline and unescaped single
quote. A single quoted character represents the Unicode value
of the character itself,
while multi-character sequences beginning with a backslash encode
values in various formats.
符文字面由一个符文常量表示,一个整数值确定一个 Unicode 码点。
一个符文字面由围绕在单引号中的一个或更多字符表示。通常一个 Unicode 码点作为一个或更多字符围绕在单引号中,
例如 'x'
或 '\n'
。
在引号内,除换行符和未转义的单引号之外,任何字符都可出现。引号内的单个字符通常代表该字符的 Unicode 值自身,
而以反斜杠开头的多字符序列则会编码为不同的形式。
The simplest form represents the single character within the quotes;
since Go source text is Unicode characters encoded in UTF-8, multiple
UTF-8-encoded bytes may represent a single integer value. For
instance, the literal 'a'
holds a single byte representing
a literal a
, Unicode U+0061, value 0x61
, while
'ä'
holds two bytes (0xc3
0xa4
) representing
a literal a
-dieresis, U+00E4, value 0xe4
.
最简单的形式就是引号内只有一个字符;由于 Go 源码文本是 UTF-8 编码的 Unicode 字符,
多个 UTF-8 编码的字节就可以表示为一个单一的整数值。例如,字面 'a'
包含一个字节,
表示一个字面 a
;Unicode 字符 U+0061,值为 0x61
,而 'ä'
则包含两个字节(0xc3
0xa4
),表示一个字面 分音符-a
,
Unicode 字符 U+00E4,值 0xe4
。
Several backslash escapes allow arbitrary values to be encoded as
ASCII text. There are four ways to represent the integer value
as a numeric constant: \x
followed by exactly two hexadecimal
digits; \u
followed by exactly four hexadecimal digits;
\U
followed by exactly eight hexadecimal digits, and a
plain backslash \
followed by exactly three octal digits.
In each case the value of the literal is the value represented by
the digits in the corresponding base.
反斜杠转义允许用 ASCII 文本来编码任意值。将整数值表示为数字常量有四种方法:
\x
紧跟两个十六进制数字;\u
紧跟四个十六进制数字;
\U
紧跟八个十六进制数字;单个 \
紧跟三个八进制数字。
在任何情况下,字面值都是其相应进制的数字表示的值。
Although these representations all result in an integer, they have
different valid ranges. Octal escapes must represent a value between
0 and 255 inclusive. Hexadecimal escapes satisfy this condition
by construction. The escapes \u
and \U
represent Unicode code points so within them some values are illegal,
in particular those above 0x10FFFF
and surrogate halves.
尽管这些表示方式都会产生整数,其有效范围却不相同。八进制转义只能表示 0 到 255 之间的值。
十六进制转义则视其结构而定。转义符 \u
和 \U
表示 Unicode 码点,
因此其中的一些值是非法的,特别是那些大于 0x10FFFF
的值和半替代值。
After a backslash, certain single-character escapes represent special values:
\a U+0007 alert or bell \b U+0008 backspace \f U+000C form feed \n U+000A line feed or newline \r U+000D carriage return \t U+0009 horizontal tab \v U+000b vertical tab \\ U+005c backslash \' U+0027 single quote (valid escape only within rune literals) \" U+0022 double quote (valid escape only within string literals)
在反斜杠后,某些单字符转义表示特殊值:
\a U+0007 警报或铃声 \b U+0008 退格 \f U+000C 换页 \n U+000A 换行 \r U+000D 回车 \t U+0009 横向制表 \v U+000b 纵向制表 \\ U+005c 反斜杠 \' U+0027 单引号(仅在符文字面中有效) \" U+0022 双引号(仅在字符串字面中有效)
All other sequences starting with a backslash are illegal inside rune literals.
rune_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' 'ä' '本' '\t' '\000' '\007' '\377' '\x07' '\xff' '\u12e4' '\U00101234' '\'' // rune literal containing single quote character 'aa' // illegal: too many characters '\xa' // illegal: too few hexadecimal digits '\0' // illegal: too few octal digits '\uDFFF' // illegal: surrogate half '\U00110000' // illegal: invalid Unicode code point
在符文字面中,所有其它以反斜杠开始的序列都是非法的。
符文字面 = "'" ( Unicode值 | 字节值 ) "'" . Unicode值 = Unicode字符 | 小Unicode值 | 大Unicode值 | 转义字符 . 字节值 = 八进制字节值 | 十六进制字节值 . 八进制字节值 = `\` 八进制数字 八进制数字 八进制数字 . 十六进制字节值 = `\` "x" 十六进制数字 十六进制数字 . 小Unicode值 = `\` "u" 十六进制数字 十六进制数字 十六进制数字 十六进制数字 . 大Unicode值 = `\` "U" 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 . 转义字符 = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
'a' 'ä' '本' '\t' '\000' '\007' '\377' '\x07' '\xff' '\u12e4' '\U00101234' '\'' // 包含单引号字符的符文字面 'aa' // 非法:太多字符 '\xa' // 非法:太少 16 进制数字 '\0' // 非法:太少 8 进制数字 '\uDFFF' // 非法:半代理值 '\U00110000' // 非法:无效的 Unicode 码点
String literals
字符串字面
A string literal represents a string constant obtained from concatenating a sequence of characters. There are two forms: raw string literals and interpreted string literals.
字符串字面表示字符串常量,可通过连结字符序列获得。 它有两种形式:原始字符串字面和解译字符串字面。
Raw string literals are character sequences between back quotes
``
. Within the quotes, any character is legal except
back quote. The value of a raw string literal is the
string composed of the uninterpreted (implicitly UTF-8-encoded) characters
between the quotes;
in particular, backslashes have no special meaning and the string may
contain newlines.
Carriage return characters ('\r') inside raw string literals
are discarded from the raw string value.
原始字符串字面为反引号 ``
之间的字符序列。在该引号内,
除反引号外的任何字符都是合法的。原始字符串字面的值为此引号之间的无解译(隐式 UTF-8 编码的)字符组成的字符串;
另外,反斜杠没有特殊意义且字符串可包含换行符。原始字符串字面中的回车符('\r')将会从原始字符串的值中丢弃。
Interpreted string literals are character sequences between double
quotes, as in "bar"
.
Within the quotes, any character may appear except newline and unescaped double quote.
The text between the quotes forms the
value of the literal, with backslash escapes interpreted as they
are in rune literals (except that \'
is illegal and
\"
is legal), with the same restrictions.
The three-digit octal (\
nnn)
and two-digit hexadecimal (\x
nn) escapes represent individual
bytes of the resulting string; all other escapes represent
the (possibly multi-byte) UTF-8 encoding of individual characters.
Thus inside a string literal \377
and \xFF
represent
a single byte of value 0xFF
=255, while ÿ
,
\u00FF
, \U000000FF
and \xc3\xbf
represent
the two bytes 0xc3
0xbf
of the UTF-8 encoding of character
U+00FF.
string_lit = raw_string_lit | interpreted_string_lit . raw_string_lit = "`" { unicode_char | newline } "`" . interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
`abc` // same as "abc" `\n \n` // same as "\\n\n\\n" "\n" "\"" // same as `"` "Hello, world!\n" "日本語" "\u65e5本\U00008a9e" "\xff\u00FF" "\uD800" // illegal: surrogate half "\U00110000" // illegal: invalid Unicode code point
解译字符串字面为双引号 "bar"
之间的字符序列。
在该引号内,除换行符和未转义双引号外的任何字符均可出现。引号内的文本形成字面的值,
反斜杠转义序列如同在符文字面中一样以相同的限制被解译
(其中\'
是非法的,而 \"
是合法的)。
三位八进制(\
nnn)和两位十六进制(\x
nn)
转义表示字符串值的独立字节;其它转义符表示(可多字节)UTF-8 编码的独立字符。
因此在字符串字面中,\377
和 \xFF
表示值为 0xFF
=255 的单个字节,
而ÿ
、\u00FF
、\U000000FF
和 \xc3\xbf
则表示 UTF-8 编码的字符 U+00FF 的两个字节0xc3
0xbf
。
字符串字面 = 原始字符串字面 | 解译字符串字面 . 原始字符串字面 = "`" { Unicode字符 | 换行符 } "`" . 解译字符串字面 = `"` { Unicode值 | 字节值 } `"` .
`abc` // 等价于 "abc" `\n \n` // 等价于 "\\n\n\\n" "\n" "\"" // 等价于 `"` "Hello, world!\n" "日本語" "\u65e5本\U00008a9e" "\xff\u00FF" "\uD800" // 非法:半代理值 "\U00110000" // 非法:无效的 Unicode 码点
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
这些例子都表示相同的字符串:
"日本語" // UTF-8 输入的文本 `日本語` // UTF-8 输入的原始字面文本 "\u65e5\u672c\u8a9e" // 显式的 Unicode 码点 "\U000065e5\U0000672c\U00008a9e" // 显式的 Unicode 码点 "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // 显式的 UTF-8 字节
If the source code represents a character as two code points, such as a combining form involving an accent and a letter, the result will be an error if placed in a rune literal (it is not a single code point), and will appear as two code points if placed in a string literal.
如果源码将两个码点表示为一个字符,例如包含着重号和字母的结合形式, 那么将它放置在符文字面中就会产生一个错误(它不是单一码点),而放置在字符串字面中则会显示为两个码点。
Constants
常量
There are boolean constants, rune constants, integer constants, floating-point constants, complex constants, and string constants. Rune, integer, floating-point, and complex constants are collectively called numeric constants.
常量包含布尔常量,符文常量, 整数常量,浮点数常量, 复数常量和字符串常量。 符文,整数,浮点数和复数常量统称为数值常量。
A constant value is represented by a
rune,
integer,
floating-point,
imaginary,
or
string literal,
an identifier denoting a constant,
a constant expression,
a conversion with a result that is a constant, or
the result value of some built-in functions such as
unsafe.Sizeof
applied to any value,
cap
or len
applied to
some expressions,
real
and imag
applied to a complex constant
and complex
applied to numeric constants.
The boolean truth values are represented by the predeclared constants
true
and false
. The predeclared identifier
iota denotes an integer constant.
常量的值可由
符文,
整数,
浮点数,
虚数 或
字符串字面表示,
一个标识符可代表一个常量,一个常量表达式,
一个结果为常量的类型转换,或一些内建函数的返回值。
例如 unsafe.Sizeof
作用于任何值时产生的值,
cap
或 len
作用于一些表达式时产生的值,
real
和 imag
作用于复数常量时产生的值,以及
complex
作用于数值常量所产生的值。
布尔值由预声明的常量 true
和 false
来表示。
预声明标识符 iota 表示一个整数常量。
In general, complex constants are a form of constant expression and are discussed in that section.
通常,复数常量的形式为 常量表达式,这一点将在该节中讨论。
Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values.
数值常量可表示任意精度的精确值而不会溢出,因此也就没有表示 IEEE-754 负零和无限的常量。
Constants may be typed or untyped.
Literal constants, true
, false
, iota
,
and certain constant expressions
containing only untyped constant operands are untyped.
常量可以是类型化的或无类型化的。字面常量,true
,false
,
iota
和某些只包含无类型化操作数的常量表达式是无类型化的。
A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a variable declaration or an assignment or as an operand in an expression. It is an error if the constant value cannot be represented as a value of the respective type.
常量可由常量声明或类型转换显式地赋予其类型,
也可由变量声明或赋值以及作为
表达式中的操作数隐式地赋予其类型。若常量的值不能由其类型表示就会产生一个错误。
例如,3.0
可赋予任何整数或浮点数类型的常量,而 2147483648.0
(等价于 1<<31
)则只能赋予 float32
, float64
或 uint32
类型的常量,而不能赋予 int32
或 string
类型的常量。
An untyped constant has a default type which is the type to which the
constant is implicitly converted in contexts where a typed value is required,
for instance, in a short variable declaration
such as i := 0
where there is no explicit type.
The default type of an untyped constant is bool
, rune
,
int
, float64
, complex128
or string
respectively, depending on whether it is a boolean, rune, integer, floating-point,
complex, or string constant.
无类型化的常量有一个默认类型,也就是当上下文中需要类型化常量时通过隐式转换出来的类型,
例如在 i := 0
这种无显示类型的 短变量声明中。
无类型化常量的默认类型分别为 bool
、rune
、int
、
float64
、complex128
或 string
之一,取决于它是布尔值、符文、整数、浮点数、复数还是字符串常量。
Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must:
- Represent integer constants with at least 256 bits.
- Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed binary exponent of at least 16 bits.
- Give an error if unable to represent an integer constant precisely.
- Give an error if unable to represent a floating-point or complex constant due to overflow.
- Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
These requirements apply both to literal constants and to the result of evaluating constant expressions.
实现限制:尽管数值常量在该语言中可拥有任意精度, 但编译器可能使用其有限精度的内部表示来实现它们。即,每个实现必须:
- 使用至少 256 位表示整数常量。
- 使用至少 256 位表示浮点常量,包括复数常量及尾数部分; 使用至少 32 位表示指数符号。
- 若无法精确表示一个整数常量,则给出一个错误。
- 若由于溢出而无法表示一个浮点或复数常量,则给出一个错误。
- 若由于精度限制而无法表示一个浮点或复数常量,则舍入为最近似的可表示常量。
这些要求适用于字面常量和常量表达式的求值结果。
A variable is a storage location for holding a value. The set of permissible values is determined by the variable's type.
变量是用于保存值的存储位置。允许值的集合由变量的类型确定。
A variable declaration
or, for function parameters and results, the signature
of a function declaration
or function literal reserves
storage for a named variable.
Calling the built-in function new
or taking the address of a composite literal
allocates storage for a variable at run time.
Such an anonymous variable is referred to via a (possibly implicit)
pointer indirection.
变量声明以及函数声明或
函数字面的签名(用于表示函数的形参和结果)
为已命名变量保留了存储。
调用内建函数 new
或获取复合字面
的地址会在运行时为变量分配存储。匿名变量通过(可能为隐式的)指针重定向来引用。
Structured variables of array, slice, and struct types have elements and fields that may be addressed individually. Each such element acts like a variable.
数组、切片和结构体 类型的结构化变量拥有可独立寻址的元素和字段。 每个这种元素的行为和用法均与变量相同。
The static type (or just type) of a variable is the
type given in its declaration, the type provided in the
new
call or composite literal, or the type of
an element of a structured variable.
Variables of interface type also have a distinct dynamic type,
which is the concrete type of the value assigned to the variable at run time
(unless the value is the predeclared identifier nil
,
which has no type).
The dynamic type may vary during execution but values stored in interface
variables are always assignable
to the static type of the variable.
变量的静态类型(或只说类型)就是它在声明时给定的类型,或者在
new
调用时提供的类型或复合字面,或者结构化变量的元素的类型。
接口类型的变量还有个独特的动态类型,它是在运行时赋予变量的值的具体类型
(除非该值为预声明的标识符 nil
,它没有类型)。动态类型在执行过程中可能会改变,
但存储在接口变量中的值总是可赋予静态类型的变量的。
var x interface{} // x is nil and has static type interface{} var v *T // v has value nil, static type *T x = 42 // x has value 42 and dynamic type int x = v // x has value (*T)(nil) and dynamic type *T
var x interface{} // x 为 nil 且拥有静态类型 interface{} var v *T // v 拥有值 nil 和静态类型 *T x = 42 // x 拥有值 42 和动态类型 int x = v // x 拥有值 (*T)(nil) 和动态类型 *T
A variable's value is retrieved by referring to the variable in an expression; it is the most recent value assigned to the variable. If a variable has not yet been assigned a value, its value is the zero value for its type.
A variable's value is retrieved by referring to the variable in an expression; it is the most recent value assigned to the variable. 变量的值可通过在表达式中引用变量取得。若变量尚未赋值, 其值即为其类型的零值。
Types
类型
A type determines a set of values together with operations and methods specific to those values. A type may be denoted by a type name, if it has one, or specified using a type literal, which composes a type from existing types.
Type = TypeName | TypeLit | "(" Type ")" . TypeName = identifier | QualifiedIdent . TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | SliceType | MapType | ChannelType .
类型决定值的集合与该类型值特定的操作。已命名类型可通过(或许为限定的) 类型名指定;未命名类型可通过类型字面指定,它将根据既有的类型组成新的类型。
类型 = 类型名 | 类型字面 | "(" 类型 ")" . 类型名 = 标识符 | 限定标识符 . 类型字面 = 数组类型 | 结构体类型 | 指针类型 | 函数类型 | 接口类型 | 切片类型 | 映射类型 | 信道类型 .
The language predeclares certain type names. Others are introduced with type declarations. Composite types—array, struct, pointer, function, interface, slice, map, and channel types—may be constructed using type literals.
布尔值,数值与字符串类型的实例的命名是预声明的。 数组,结构体,指针,函数,接口,切片,映射和信道这些复合类型可由类型字面构造。
Each type T
has an underlying type: If T
is one of the predeclared boolean, numeric, or string types, or a type literal,
the corresponding underlying
type is T
itself. Otherwise, T
's underlying type
is the underlying type of the type to which T
refers in its
type declaration.
每个类型 T
都有一个基本类型:若 T
为预声明的布尔、数值或字符串类型或者类型字面,其相应的基本类型为 T
本身。否则,T
的基本类型为其类型声明中所依据类型的基本类型。
type ( A1 = string A2 = A1 ) type ( B1 string B2 B1 B3 []B1 B4 B3 )
The underlying type of string
, A1
, A2
, B1
,
and B2
is string
.
The underlying type of []B1
, B3
, and B4
is []B1
.
以上 string
,T1
和 T2
的基本类型为 string
。
[]T1
,T3
和 T4
的基本类型为 []T1
。
Method sets
方法集
A type may have a method set associated with it.
The method set of an interface type is its interface.
The method set of any other type T
consists of all
methods declared with receiver type T
.
The method set of the corresponding pointer type *T
is the set of all methods declared with receiver *T
or T
(that is, it also contains the method set of T
).
Further rules apply to structs containing embedded fields, as described
in the section on struct types.
Any other type has an empty method set.
In a method set, each method must have a
unique
non-blank method name.
类型可拥有一个与其相关联的方法集。
接口类型的方法集为其接口。其它任意类型 T
的方法集由所有以接收者类型
T
声明的方法组成。与指针类型 *T
相应的方法集为所有以接收者 *T
或 T
声明的方法的集(就是说,它也包含 T
的方法集)。根据结构体类型一节的描述,
更进一步的规则也适用于包含匿名字段的结构体。任何其它类型都有一个空方法集。
在方法集中,每个方法都必须有唯一的非空白方法名。
The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
一个类型的方法集决定了它所实现的接口 以及可使用该类型接收者调用的方法。
Boolean types
布尔类型
A boolean type represents the set of Boolean truth values
denoted by the predeclared constants true
and false
. The predeclared boolean type is bool
;
it is a defined type.
布尔类型表示由预声明常量 true
和 false
所代表的布尔值的集。
预声明的布尔类型为 bool
。
Numeric types
数值类型
A numeric type represents sets of integer or floating-point values. The predeclared architecture-independent numeric types are:
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 IEEE-754 32-bit floating-point numbers float64 the set of all IEEE-754 64-bit floating-point numbers complex64 the set of all complex numbers with float32 real and imaginary parts complex128 the set of all complex numbers with float64 real and imaginary parts byte alias for uint8 rune alias for int32
数值类型表示整数值和浮点数值的集。 架构无关的预声明数值类型为:
uint8 所有无符号 8 位整数集(0 到 255) uint16 所有无符号 16 位整数集(0 到 65535) uint32 所有无符号 32 位整数集(0 到 4294967295) uint64 所有无符号 64 位整数集(0 到 18446744073709551615) int8 所有带符号 8 位整数集(-128 到 127) int16 所有带符号 16 位整数集(-32768 到 32767) int32 所有带符号 32 位整数集(-2147483648 到 2147483647) int64 所有带符号 64 位整数集(-9223372036854775808 到 9223372036854775807) float32 所有 IEEE-754 32 位浮点数集 float64 所有 IEEE-754 64 位浮点数集 complex64 所有带 float32 实部和虚部的复数集 complex128 所有带 float64 实部和虚部的复数集 byte uint8 的别名 rune int32 的别名
The value of an n-bit integer is n bits wide and represented using two's complement arithmetic.
n 位的整数值是 n 位宽的,它使用 二进制补码运算表示。
There is also a set of predeclared numeric types with implementation-specific sizes:
uint either 32 or 64 bits int same size as uint uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value
大小取决于具体实现的预声明数值类型:
uint 32 或 64 位 int 大小与 uint 相同 uintptr 大到足以存储指针值无解释位的无符号整数
To avoid portability issues all numeric types are defined
types and thus distinct except
byte
, which is an alias for uint8
, and
rune
, which is an alias for int32
.
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 architecture.
为避免可移植性问题,除 byte
为 uint8
的别名以及
rune
为 int32
的别名外,所有数值类型都是不同的。
当不同的数值类型混合在一个表达式或赋值操作中时,必须进行类型转换。
例如,int32
与 int
是不同的类型,
尽管它们在特定架构上可能有相同的大小。
String types
字符串类型
A string type represents the set of string values.
A string value is a (possibly empty) sequence of bytes.
Strings are immutable: once created,
it is impossible to change the contents of a string.
The predeclared string type is string
;
it is a defined type.
字符串类型表示字符串值的集。字符串的值为(可能为空的)字节序列。字符串是不可变的:
一旦被创建,字符串的内容就不能更改。预声明的字符串类型为 string
。
The length of a string s
(its size in bytes) can be discovered using
the built-in function len
.
The length is a compile-time constant if the string is a constant.
A string's bytes can be accessed by integer indices
0 through len(s)-1
.
It is illegal to take the address of such an element; if
s[i]
is the i
'th byte of a
string, &s[i]
is invalid.
字符串 s
的长度(即其字节大小)可使用内建函数
len
获取。若该字符串为常量,则其长度即为编译时常量。
字符串的字节可通过整数(§下标)0 至 len(s)-1
访问。
获取这样一个元素的地址是非法的;若 s[i]
为字符串的第 i
个字节,&s[i]
就是无效的。
Array types
数组类型
An array is a numbered sequence of elements of a single type, called the element type. The number of elements is called the length and is never negative.
ArrayType = "[" ArrayLength "]" ElementType . ArrayLength = Expression . ElementType = Type .
数组是单一类型元素的编号序列,该单一类型称为元素类型。元素的数量称为长度且为非负数。
数组类型 = "[" 数组长度 "]" 元素类型 . 数组长度 = 表达式 . 元素类型 = 类型 .
The length is part of the array's type; it must evaluate to a
non-negative constant
representable by a value
of type int
.
The length of array a
can be discovered
using the built-in function len
.
The elements can be addressed by integer indices
0 through len(a)-1
.
Array types are always one-dimensional but may be composed to form
multi-dimensional types.
[32]byte [2*N] struct { x, y int32 } [1000]*float64 [3][5]int [2][2][2]float64 // same as [2]([2]([2]float64))
长度是数组类型的一部分,其求值结果必须可表示为 int
类型的非负常量。
数组 a
的长度可使用内建函数 len
获取,
其元素可通过整数下标 0 到 len(a)-1
寻址。
数组类型总是一维的,但可组合构成多维的类型。
[32]byte [2*N] struct { x, y int32 } [1000]*float64 [3][5]int [2][2][2]float64 // 等价于[2]([2]([2]float64))
Slice types
切片类型
A slice is a descriptor for a contiguous segment of an underlying array and
provides access to a numbered sequence of elements from that array.
A slice type denotes the set of all slices of arrays of its element type.
The value of an uninitialized slice is nil
.
SliceType = "[" "]" ElementType .
切片是其底层数组上连续一段的描述符,它提供了访问此数组的元素的编号序列。
切片类型表示元素类型为数组的所有切片的集。未初始化切片的值为 nil
。
切片类型 = "[" "]" 元素类型 .
Like arrays, slices are indexable and have a length. The length of a
slice s
can be discovered by the built-in function
len
; unlike with arrays it may change during
execution. The elements can be addressed by integer indices
0 through len(s)-1
. The slice index of a
given element may be less than the index of the same element in the
underlying array.
类似于数组,切片是可索引的且拥有一个长度。切片 s
的长度可通过内建函数
len
获取;不同于数组的是,切片可在执行过程中被改变,
其元素可通过整数(§下标) 0 到 len(s)-1
寻址。
给定元素的切片下标可能小于它在其底层数组中的下标。
A slice, once initialized, is always associated with an underlying array that holds its elements. A slice therefore shares storage with its array and with other slices of the same array; by contrast, distinct arrays always represent distinct storage.
切片一旦初始化,就总是伴随着一个包含其元素的底层数组。 因此,切片与其数组及其它本数组的切片共享存储; 与此相反,不同的数组总是表示其不同的存储。
The array underlying a slice may extend past the end of the slice.
The capacity is a measure of that extent: it is the sum of
the length of the slice and the length of the array beyond the slice;
a slice of length up to that capacity can be created by
slicing a new one from the original slice.
The capacity of a slice a
can be discovered using the
built-in function cap(a)
.
切片的底层数组可扩展其切片的结尾。容量是该扩展的量度:
它是切片的长度和切片往后数组的长度之和;长度达到其容量的切片可通过从原切片
切下一个新的来创建。
切片 a
的容量可使用内建函数 cap(a)
获取。
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:
给定元素类型 T
的一个新的,已初始化的切片值使用内建函数
make
创建,
它需要一个切片类型和指定其长度与可选容量的形参。
make([]T, length) make([]T, length, capacity)
A slice created with make
always allocates a new, hidden array
to which the returned slice value refers. That is, executing
通过 make
创建的切片总是分配一个新的、隐藏的数组,该数组被返回的切片值所引用。即,执行
make([]T, length, capacity)
produces the same slice as allocating an array and slicing it, so these two expressions are equivalent:
产生切片与分配数组后再切下它相同,因此这两个表达式是等价的:
make([]int, 50, 100) new([100]int)[0:50]
Like arrays, slices are always one-dimensional but may be composed to construct higher-dimensional objects. With arrays of arrays, the inner arrays are, by construction, always the same length; however with slices of slices (or arrays of slices), the inner lengths may vary dynamically. Moreover, the inner slices must be initialized individually.
类似于数组,切片总是一维的,但可组合构造更高维的对象。 元素为数组的数组,根据其构造,其内部数组的长度始终相同; 然而元素为切片的切片(或元素为数组的切片),其内部长度会动态地改变。 此外,其内部的切片必须单独进行初始化。
Struct types
结构体类型
A struct is a sequence of named elements, called fields, each of which has a name and a type. Field names may be specified explicitly (IdentifierList) or implicitly (EmbeddedField). Within a struct, non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName . Tag = string_lit .
// An empty struct. struct {} // A struct with 6 fields. struct { x, y int u float32 _ float32 // padding A *[]int F func() }
结构体是已命名的元素序列,被称为字段,其中每一个元素都有一个名字和类型。 字段名可显示地指定(标识符列表)或隐式地指定(匿名字段)。 在结构体中,非空白字段名必须是唯一的。
结构体类型 = "struct" "{" { 字段声明 ";" } "}" . 字段声明 = (标识符列表 类型 | 匿名字段) [ 标注 ] . 匿名字段 = [ "*" ] 类型名 . 标注 = 字符串字面 .
// 空结构体 struct {} // 带 6 个字段的结构体 struct { x, y int u float32 _ float32 // 填充 A *[]int F func() }
A field declared with a type but no explicit field name is called an embedded field.
An embedded field must be specified as
a type name T
or as a pointer to a non-interface type name *T
,
and T
itself may not be
a pointer type. The unqualified type name acts as the field name.
// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4 struct { T1 // field name is T1 *T2 // field name is T2 P.T3 // field name is T3 *P.T4 // field name is T4 x, y int // field names are x and y }
通过有类型而无显式字段名声明的字段为匿名字段,亦称为嵌入式字段或该结构体中此种类型的嵌入。
这种字段类型必须作为一个类型名 T
或一个非接口类型名的指针 *T
来实现,
且 T
本身不能为指针类型。未限定类型名的行为类似于字段名。
// 带有类型为 T1、*T2、P.T3 和 *P.T4 的四个匿名字段的结构体 struct { T1 // 字段名为 T1 *T2 // 字段名为 T2 P.T3 // 字段名为 T3 *P.T4 // 字段名为 T4 x, y int // 字段名为 x 和 y }
The following declaration is illegal because field names must be unique in a struct type:
struct { T // conflicts with embedded field *T and *P.T *T // conflicts with embedded field T and *P.T *P.T // conflicts with embedded field T and *T }
以下为非法声明,因为字段名在结构体类型中必须是唯一的:
struct { T // 与匿名字段 *T 及 *P.T 相冲突 *T // 与匿名字段 T 及 *P.T 相冲突 *P.T // 与匿名字段 T 及 *T 相冲突 }
A field or method f
of an
embedded field in a struct x
is called promoted if
x.f
is a legal selector that denotes
that field or method f
.
在结构体 x
中,若 x.f
为表示字段或方法
f
的合法选择器,则匿名字段的字段或方法 f
即为已提升的。
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
已提升字段除了不能用作该结构体复合字面中的字段名外, 其行为如同结构体的一般字段。
Given a struct type S
and a defined type
T
, promoted methods are included in the method set of the struct as follows:
-
If
S
contains an embedded fieldT
, the method sets ofS
and*S
both include promoted methods with receiverT
. The method set of*S
also includes promoted methods with receiver*T
. -
If
S
contains an embedded field*T
, the method sets ofS
and*S
both include promoted methods with receiverT
or*T
.
给定结构体类型 S
与名为 T
的类型,包含在结构体方法集中的已提升方法如下:
-
若
S
包含一个匿名字段T
,则S
与*S
的方法集均包含带接收者T
的已提升方法。*S
的方法集也包含带接收者*T
的已提升方法。 -
若
S
包含匿名字段*T
,则S
与*S
的方法集均包含带接收者T
或*T
的已提升方法。
A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored.
struct { x, y float64 "" // an empty tag string is like an absent tag name string "any string is permitted as a tag" _ [4]byte "ceci n'est pas un champ de structure" } // A struct corresponding to a TimeStamp protocol buffer. // The tag strings define the protocol buffer field numbers; // they follow the convention outlined by the reflect package. struct { microsec uint64 `protobuf:"1"` serverIP6 uint64 `protobuf:"2"` }
字段声明可后跟一个可选的字符串字面标注,成为所有相应字段声明中字段的属性。 空标注字符串等价于没有标注。标注可通过 反射接口 获得, 并成为结构体的类型标识的一部分,其它情况下会被忽略。
struct { x, y float64 "" // 空标注字符串相当于没有标注 name string "任何字符串都允许作为标注" _ [4]byte "这不是一个结构体字段" } // 一个对应于时间戳协议缓冲的结构体. // 标注字符串定义了协议缓冲的字段号,它们遵循 reflect 包所用的约定。 struct { microsec uint64 `protobuf:"1"` serverIP6 uint64 `protobuf:"2"` }Pointer types
指针类型
A pointer type denotes the set of all pointers to variables of a given
type, called the base type of the pointer.
The value of an uninitialized pointer is nil
.
PointerType = "*" BaseType . BaseType = Type .
指针类型表示一个所有给定类型变量的指针的集,称为指针的基础类型。
未初始化的指针的值为 nil
。
指针类型 = "*" 基础类型 . 基础类型 = 类型 .
*Point *[4]int
Function types
函数类型
A function type denotes the set of all functions with the same parameter
and result types. The value of an uninitialized variable of function type
is nil
.
FunctionType = "func" Signature . Signature = Parameters [ Result ] . Result = Parameters | Type . Parameters = "(" [ ParameterList [ "," ] ] ")" . ParameterList = ParameterDecl { "," ParameterDecl } . ParameterDecl = [ IdentifierList ] [ "..." ] Type .
函数类型表示所有带相同形参和返回类型的集。未初始化的函数类型变量的的值为 nil
。
函数类型 = "func" 签名 . 签名 = 形参 [ 结果 ] . 结果 = 形参 | 类型 . 形参 = "(" [ 形参列表 [ "," ] ] ")" . 形参列表 = 形参声明 { "," 形参声明 } . 形参声明 = [ 标识符列表 ] [ "..." ] 类型 .
Within a list of parameters or results, the names (IdentifierList) must either all be present or all be absent. If present, each name stands for one item (parameter or result) of the specified type and all non-blank names in the signature must be unique. If absent, each type stands for one item of that type. Parameter and result lists are always parenthesized except that if there is exactly one unnamed result it may be written as an unparenthesized type.
在形参或结果的列表中,其名称(标识符列表)必须都存在或都不存在。 若存在,则每个名称代表一个指定类型的项(形参或结果),所有在签名中的非 空白名称必须是唯一的。 若不存在,则每个类型代表一个此类型的项。若恰好有一个未命名的值,它可能写作一个不加括号的类型, 除此之外,形参和结果的列表总是在括号中。
The final incoming parameter in a function signature may have
a type prefixed with ...
.
A function with such a parameter is called variadic and
may be invoked with zero or more arguments for that parameter.
函数签名中加入的最后一个形参可能有一个带 ...
前缀的类型。
带这样形参的函数被称为变参函数,它可接受零个或多个实参。
func() func(x int) int func(a, _ int, z float32) bool func(a, b int, z float32) (bool) func(prefix string, values ...int) func(a, b int, z float64, opt ...interface{}) (success bool) func(int, int, float64) (float64, *[]int) func(n int) func(p *T)
Interface types
接口类型
An interface type specifies a method set called its interface.
A variable of interface type can store a value of any type with a method set
that is any superset of the interface. Such a type is said to
implement the interface.
The value of an uninitialized variable of interface type is nil
.
InterfaceType = "interface" "{" { MethodSpec ";" } "}" . MethodSpec = MethodName Signature | InterfaceTypeName . MethodName = identifier . InterfaceTypeName = TypeName .
接口类型指定一个称为接口的 方法集。
接口类型变量可存储任何带方法集类型的值,该方法集为此接口的超集。
这种类型表示实现此接口。未初始化的接口类型变量的值为 nil
。
接口类型 = "interface" "{" { 方法实现 ";" } "}" . 方法实现 = 方法名 签名 | 接口类型名 . 方法名 = 标识符 . 接口类型名 = 类型名 .
As with all method sets, in an interface type, each method must have a unique non-blank name.
// A simple File interface interface { Read(b Buffer) bool Write(b Buffer) bool Close() }
对于所有的方法集,在一个接口类型中,每个方法必须有唯一的非 空白名字。
// 一个简单的 File 接口 interface { Read(b Buffer) bool Write(b Buffer) bool Close() }
More than one type may implement an interface.
For instance, if two types S1
and S2
have the method set
不止一个类型可实现同一接口。例如,若两个类型 S1
和 S2
拥有方法集
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.
(其中 T
代表 S1
或 S2
)
那么 File
接口都将被 S1
和 S2
所实现,
不论如何,方法 S1
和 S2
都会拥有或共享它。
A type implements any interface comprising any subset of its methods and may therefore implement several distinct interfaces. For instance, all types implement the empty interface:
类型可实现任何接口,包括任何其方法的子集,因此可能实现几个不同的接口。 例如,所有类型都实现了空接口:
interface{}
Similarly, consider this interface specification,
which appears within a type declaration
to define an interface called Locker
:
同样,考虑此接口的实现,它出现在类型声明
中以定义一个名为 Locker
的接口:
type Locker interface { Lock() Unlock() }
If S1
and S2
also implement
若 S1
和 S2
也实现
func (p T) Lock() { … } func (p T) Unlock() { … }
they implement the Locker
interface as well
as the File
interface.
它们不仅会实现 Locker
还会实现 File
接口
An interface T
may use a (possibly qualified) interface type
name E
in place of a method specification. This is called
embedding interface E
in T
; it adds
all (exported and non-exported) methods of E
to the interface
T
.
type ReadWriter interface { Read(b Buffer) bool Write(b Buffer) bool } type File interface { ReadWriter // same as adding the methods of ReadWriter Locker // same as adding the methods of Locker Close() } type LockedFile interface { Locker File // illegal: Lock, Unlock not unique Lock() // illegal: Lock not unique }
一个接口 T
可通过包含一个(可能被限制的)名为 E
的接口类型来代替方法的指定。这称为在 T
中嵌入接口
E
,它会将 E
中所有(已导出和未导出的)方法添加到接口
T
中。
type ReadWriter interface { Read(b Buffer) bool Write(b Buffer) bool } type File interface { ReadWriter // 等价于添加了 ReadWriter 的方法 Locker // 等价于添加了 Locker 的方法 Close() } type LockedFile interface { Locker File // 非法:Lock、Unlock 不唯一 Lock() // 非法:Lock 不唯一 }
An interface type T
may not embed itself
or any interface type that embeds T
, recursively.
// illegal: Bad cannot embed itself type Bad interface { Bad } // illegal: Bad1 cannot embed itself using Bad2 type Bad1 interface { Bad2 } type Bad2 interface { Bad1 }
接口类型 T
不能嵌入其自身或任何递归地嵌入 T
的接口类型。
// 非法:Bad 不能嵌入其自身 type Bad interface { Bad } // 非法:Bad1 不能通过 Bad2 嵌入其自身 type Bad1 interface { Bad2 } type Bad2 interface { Bad1 }
Map types
映射类型
A map is an unordered group of elements of one type, called the
element type, indexed by a set of unique keys of another type,
called the key type.
The value of an uninitialized map is nil
.
MapType = "map" "[" KeyType "]" ElementType . KeyType = Type .
映射是一个同种类型元素的无序组,该类型称为元素类型;
映射通过另一类型唯一的键集索引,该类型称为键类型。
未初始化的映射值为 nil
。
映射类型 = "map" "[" 键类型 "]" 元素类型 . 键类型 = 类型 .
The comparison operators
==
and !=
must be fully defined
for operands of the key type; thus the key type must not be a function, map, or
slice.
If the key type is an interface type, these
comparison operators must be defined for the dynamic key values;
failure will cause a run-time panic.
比较操作符 ==
和 !=
必须由键类型的操作数完全定义;因此键类型不能是函数,映射或切片。
若该键类型为接口类型,这些比较运算符必须由动态键值定义;
失败将导致一个 运行时恐慌.
map[string]int map[*T]struct{ x, y float64 } map[string]interface{}
The number of map elements is called its length.
For a map m
, it can be discovered using the
built-in function len
and may change during execution. Elements may be added during execution
using assignments and retrieved with
index expressions; they may be removed with the
delete
built-in function.
元素的数量称为长度。
对于映射 m
,其长度可使用内建函数 len
获取并可在执行时更改。元素可在执行时使用赋值来添加并通过
下标表达式 来检索;它们也可通过内建函数
delete
删除。
A new, empty map value is made using the built-in
function make
,
which takes the map type and an optional capacity hint as arguments:
一个新的,空的映射值使用内建函数 make
创建,
它使该映射类型和可选容量作为实参提示:
make(map[string]int) make(map[string]int, 100)
The initial capacity does not bound its size:
maps grow to accommodate the number of items
stored in them, with the exception of nil
maps.
A nil
map is equivalent to an empty map except that no elements
may be added.
初始容量不能限定它的大小:映射通过增长来适应存储在其中的项数,除了 nil
映射以外。
一个 nil
映射等价于一个空映射,只是 nil
映射不能添加元素。
Channel types
信道类型
A channel provides a mechanism for
concurrently executing functions
to communicate by
sending and
receiving
values of a specified element type.
The value of an uninitialized channel is nil
.
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
信道为并发地执行函数 提供了一种机制,
通过发送和接受具体元素类型的值来通信。
未初始化的信道值为 nil
。
信道类型 = ( "chan" [ "chan" "<-" ] | "<-" "chan" ) 元素类型 .
The optional <-
operator specifies the channel direction,
send or receive. If no direction is given, the channel is
bidirectional.
A channel may be constrained only to send or only to receive by
conversion or assignment.
chan T // can be used to send and receive values of type T chan<- float64 // can only be used to send float64s <-chan int // can only be used to receive ints
可选的 <-
操作符指定信道的方向,发送或接收。
若没有给定方向,那么该信道就是双向的。
信道可通过类型转换 或 赋值被强制为只发送或只接收。
chan T // 可以被用来发送和接收类型 T 的值 chan<- float64 // 只能被用来发送浮点数 <-chan int // 只能被用来接收整数
The <-
operator associates with the leftmost chan
possible:
chan<- chan int // same as chan<- (chan int) chan<- <-chan int // same as chan<- (<-chan int) <-chan <-chan int // same as <-chan (<-chan int) chan (<-chan int)
<-
操作符结合最左边的 chan
可能的方式:
chan<- chan int // 等价于 chan<- (chan int) chan<- <-chan int // 等价于 chan<- (<-chan int) <-chan <-chan int // 等价于 <-chan (<-chan int) chan (<-chan int)
A new, initialized channel
value can be made using the built-in function
make
,
which takes the channel type and an optional capacity as arguments:
一个新的,已初始化的信道值可使用内建函数 make
创建,
它接受信道类型和一个可选的容量作为实参:
make(chan int, 100)
The capacity, in number of elements, sets the size of the buffer in the channel.
If the capacity is zero or absent, the channel is unbuffered and communication
succeeds only when both a sender and receiver are ready. Otherwise, the channel
is buffered and communication succeeds without blocking if the buffer
is not full (sends) or not empty (receives).
A nil
channel is never ready for communication.
容量根据元素的数量设置信道中缓存的大小。若容量为零或缺失,则信道为无缓冲的,
且仅当发送者和接收者均已准备就绪时通信才会成功;否则,信道即为带缓冲的,
且当缓冲未满(发送)或非空(接收)时,通信操作无阻塞成功。
nil
信道永远不会准备好通信。
A channel may be closed with the built-in function
close
.
The multi-valued assignment form of the
receive operator
reports whether a received value was sent before
the channel was closed.
信道可通过内建函数 close
关闭;
接收操作符的多值赋值形式可在信道关闭前
报告接收的值是否已发送。
A single channel may be used in
send statements,
receive operations,
and calls to the built-in functions
cap
and
len
by any number of goroutines without further synchronization.
Channels act as first-in-first-out queues.
For example, if one goroutine sends values on a channel
and a second goroutine receives them, the values are
received in the order sent.
单个信道可在发送语句和接收操作符中使用,
且可由任意数量的Go程对其调用内建函数 cap
和 len
而无需进一步的同步。
信道可充当先进先出的队列。例如,若Go程在信道上发送了一些值,而第二个信道接收了它们,
那么这些值会按照发送的顺序来接收。
Properties of types and values
类型与值的性质
Type identity
类型标识
Two types are either identical or different.
两个类型若非相同即为不同。
A defined type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types. In detail:
- Two array types are identical if they have identical element types and the same array length.
- Two slice types are identical if they have identical element types.
- Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical types, and identical tags. Non-exported field names from different packages are always different.
- 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, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.
- Two interface types are identical if they have the same set of methods with the same names and identical function types. Non-exported method names from different packages are always different. The order of the methods is irrelevant.
- Two map types are identical if they have identical key and element types.
- Two channel types are identical if they have identical element types and the same direction.
若两个已命名类型的类型名源自相同的类型实现,它们就是相同的。 一个已命名类型和一个未命名类型总不相同。若两个未命名类型其相应的类型字面相同, 那么它们的类型相同,即,它们的字面结构是否相同且其相应的组件类型是否相同。细节详述:
- 若两个数组类型其元素类型相同且长度相同,那么它们的类型相同。
- 若两个切片类型其元素类型相同,那么它们的类型相同。
- 若两个结构体类型其字段序列相同,相应字段名相同,类型相同,标注相同,那么它们的类型相同。 两个匿名字段其名字被认为相同。出自不同包的小写字段名总不相同。
- 若两个指针类型其基础类型相同,那么它们的类型相同。
- 若两个函数类型其形参个数相同,返回值相同,相应形参类型相同,返回值类型相同, 两函数都可变或都不可变,那么它们的类型相同。形参和返回值名无需匹配。
- 若两个接口类型其方法集相同,名字相同,函数类型相同,那么它们的类型相同。 出自不同包的小写方法名总不相同。两接口类型是否相同与方法的次序无关。
- 若两个映射类型其键值类型相同,那么它们的类型相同。
- 若两个信道类型其值类型相同,方向相同,那么它们的类型相同。
Given the declarations
给定声明
type ( A0 = []string A1 = A0 A2 = struct{ a, b int } A3 = int A4 = func(A3, float64) *A0 A5 = func(x int, _ float64) *[]string ) type ( B0 A0 B1 []string B2 struct{ a, b int } B3 struct{ a, c int } B4 func(int, float64) *B0 B5 func(x int, y float64) *A1 ) type C0 = B0
these types are identical:
A0, A1, and []string A2 and struct{ a, b int } A3 and int A4, func(int, float64) *[]string, and A5 B0 and C0 []int and []int struct{ a, b *T5 } and struct{ a, b *T5 } func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5
这些类型是相同的:
T0 和 T0 []int 和 []int struct{ a, b *T5 } 和 struct{ a, b *T5 } func(x int, y float64) *[]string 和 func(int, float64) (result *[]string)
B0
and B1
are different because they are new types
created by distinct type definitions;
func(int, float64) *B0
and func(x int, y float64) *[]string
are different because B0
is different from []string
.
T0
和 T1
是不同的,因为它们由不同声明的类型命名;
func(int, float64) *T0
和 func(x int, y float64) *[]string
是不同的,
因为 T0
不同于 []string
。
Assignability
可赋值性
A value x
is assignable to a variable of type T
("x
is assignable to T
") if one of the following conditions applies:
-
x
's type is identical toT
. -
x
's typeV
andT
have identical underlying types and at least one ofV
orT
is not a defined type. -
T
is an interface type andx
implementsT
. -
x
is a bidirectional channel value,T
is a channel type,x
's typeV
andT
have identical element types, and at least one ofV
orT
is not a defined type. -
x
is the predeclared identifiernil
andT
is a pointer, function, slice, map, channel, or interface type. -
x
is an untyped constant representable by a value of typeT
.
在下列情况下,值 x
可赋予类型为 T
的变量
("x
可赋予 T
"):
-
当
x
的类型和T
相同时。 -
当
x
的类型V
和T
有相同的 底层类型 且在V
或T
中至少有一个不是已命名类型时。 -
当
T
为接口类型且x
实现了T
时。 -
当
x
为双向信道值、T
为信道类型、x
的类型V
和T
的元素类型相同且在V
或T
中至少有一个不是已命名类型时。 -
当
x
为预声明标识符nil
且T
为指针、函数、切片、映射、通道或接口类型时。 -
当
x
为无类型化,可通过类型T
的值来表示的 常量时。
Any value may be assigned to the blank identifier.
任何类型都可赋予空白标识符.
Representability
可表示性
A constant x
is representable
by a value of type T
if one of the following conditions applies:
-
x
is in the set of values determined byT
. -
T
is a floating-point type andx
can be rounded toT
's precision without overflow. Rounding uses IEEE 754 round-to-even rules but with an IEEE negative zero further simplified to an unsigned zero. Note that constant values never result in an IEEE negative zero, NaN, or infinity. -
T
is a complex type, andx
's componentsreal(x)
andimag(x)
are representable by values ofT
's component type (float32
orfloat64
).
若满足以下条件,则常量 x
可表示 为
T
类型的值:
-
x
在由T
所确定的值的集合中。 -
T
为浮点类型且x
可被舍入到T
的精度而不会溢出。 舍入遵循 IEEE 754 「舍入到偶数」规则,不过 IEEE 负零会进一步简化为无符号零。 注意常量值永远不会产生 IEEE 负零、NaN 或无限。 -
T
为复数类型,且x
的实虚部real(x)
和imag(x)
可被表示为T
的部分类型(float32
或float64
)的值。
x T x is representable by a value of T because 'a' byte 97 is in the set of byte values 97 rune rune is an alias for int32, and 97 is in the set of 32-bit integers "foo" string "foo" is in the set of string values 1024 int16 1024 is in the set of 16-bit integers 42.0 byte 42 is in the set of unsigned 8-bit integers 1e10 uint64 10000000000 is in the set of unsigned 64-bit integers 2.718281828459045 float32 2.718281828459045 rounds to 2.7182817 which is in the set of float32 values -1e-1000 float64 -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0 0i int 0 is an integer value (42 + 0i) float32 42.0 (with zero imaginary part) is in the set of float32 values
x T x is not representable by a value of T because 0 bool 0 is not in the set of boolean values 'a' string 'a' is a rune, it is not in the set of string values 1024 byte 1024 is not in the set of unsigned 8-bit integers -1 uint16 -1 is not in the set of unsigned 16-bit integers 1.1 int 1.1 is not an integer value 42i float32 (0 + 42i) is not in the set of float32 values 1e1000 float64 1e1000 overflows to IEEE +Inf after rounding
x T x 可表示为一个 T 类型的值,因为 'a' byte 97 属于 byte 值的集合 97 rune rune 是 int32 的别名,且 97 属于 32 位整数值的集合 "foo" string "foo" 属于 string 值的集合 1024 int16 1024 属于 16 位整数的集合 42.0 byte 42 属于无符号 8 位整数的集合 1e10 uint64 10000000000 属于 64 位无符号整数的集合 2.718281828459045 float32 2.718281828459045 舍入到 2.7182817,它属于 float32 值的集合 -1e-1000 float64 -1e-1000 舍入到 IEEE -0.0,它进一步简化为 0.0 0i int 0 是一个整数值 (42 + 0i) float32 42.0(实部为零)属于 float32 值的集合
x T x 无法表示为一个 T 类型的值,因为 0 bool 0 不属于布尔值的集合 'a' string 'a' 是一个 rune,它不属于 string 值的集合 1024 byte 1024 不属于无符号 8 位整数的集合 -1 uint16 -1 不属于 16 位无符号整数的集合 1.1 int 1.1 不是一个整数值 42i float32 (0 + 42i) 不属于 float32 值的集合 1e1000 float64 1e1000 舍入后溢出到 IEEE +Inf
Blocks
块
A block is a possibly empty sequence of declarations and statements within matching brace brackets.
Block = "{" StatementList "}" . StatementList = { Statement ";" } .
块为一对大括号括住的,可能为空的一系列声明和语句。
块 = "{" 语句列表 "}" . 语句列表 = { 语句 ";" } .
In addition to explicit blocks in the source code, there are implicit blocks:
- The universe block encompasses all Go source text.
- Each package has a package block containing all Go source text for that package.
- Each file has a file block containing all Go source text in that file.
- Each "if", "for", and "switch" statement is considered to be in its own implicit block.
- Each clause in a "switch" or "select" statement acts as an implicit block.
除显式源码块外,还有隐式块:
- 全域块包含所有的 Go 源码文本。
- 每个包都有包含其所有 Go 源码文本的包块。
- 每个文件都有包含其所有 Go 源码文本的文件块。
- 每个 if、for 和 switch 语句都被视为处于其自身的隐式块中。
- 每个 switch 或 select 语句中的子句其行为如同隐式块。
Blocks nest and influence scoping.
块可嵌套并会影响作用域。
Declarations and scope
声明与作用域
A declaration binds a non-blank identifier to a constant, type, variable, function, label, or package. Every identifier in a program must be declared. No identifier may be declared twice in the same block, and no identifier may be declared in both the file and package block.
The blank identifier may be used like any other identifier
in a declaration, but it does not introduce a binding and thus is not declared.
In the package block, the identifier init
may only be used for
init
function declarations,
and like the blank identifier it does not introduce a new binding.
Declaration = ConstDecl | TypeDecl | VarDecl . TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
声明可将非空白标识符绑定到一个常量、 类型、变量、函数、 标签或包。 在程序中,每个标识符都必须被声明。同一标识符不能在同一块中声明两次,且在文件与包块中不能同时声明。
空白标识符可像其它标识符一样在声明中使用,但由于它不会引入绑定,
因此也就视作未声明的。在包块中,标识符 init
仅能用作
init
函数声明,且与空白标识符一样不会引入新的绑定。
声明 = 常量声明 | 类型声明 | 变量声明 . 顶级声明 = 声明 | 函数声明 | 方法声明 .
The scope of a declared identifier is the extent of source text in which the identifier denotes the specified constant, type, variable, function, label, or package.
已声明标识符的作用域即为该标识符所表示的具体常量、类型、变量、函数、标签或包在源文本中的作用范围。
Go is lexically scoped using blocks:
- The scope of a predeclared identifier is the universe block.
- The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
- The scope of the package name of an imported package is the file block of the file containing the import declaration.
- The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
- The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
- The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost containing block.
Go 使用块表示词法作用域:
- 预声明标识符的作用域为全域块。
- 在顶级(即在任何函数之外)声明的表示常量、类型、变量或函数 (而非方法)的标识符其作用域为该包块。
- 已导入包的包名作用域为包含该导入声明的文件块。
- 表示方法接收器、函数形参或返回值变量的标识符,其作用域为该函数体。
- 在函数中声明为常量或变量的标识符,其作用域始于该函数中具体常量实现或变量实现 (ShortVarDecl 表示短变量声明)的结尾,止于最内部包含块的结尾。
- 在函数中声明为类型的标识符,其作用域始于该函数中具体类型实现的标识符, 止于最内部包含块的结尾。
An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration.
在块中声明的标识符可在其内部块中重新声明。 当其内部声明的标识符在作用域中时,即表示其实体在该内部声明中声明。
The package clause is not a declaration; the package name does not appear in any scope. Its purpose is to identify the files belonging to the same package and to specify the default package name for import declarations.
包子句并非声明;包名不会出现在任何作用域中。 其目的是为了识别该文件是否属于相同的包并为导入声明指定默认包名。
Label scopes
标签作用域
Labels are declared by labeled statements and are used in the "break", "continue", and "goto" statements. It is illegal to define a label that is never used. In contrast to other identifiers, labels are not block scoped and do not conflict with identifiers that are not labels. The scope of a label is the body of the function in which it is declared and excludes the body of any nested function.
标签通过标签语句声明,并用于 break、continue 和 goto 语句。 定义不会使用的标签是非法的。与其它标识符相反,标签并不限定作用域且与非标签标识符并不冲突。 标签的作用域为除任何嵌套函数体外其声明的函数体。
Blank identifier
空白标识符
The blank identifier is represented by the underscore character _
.
It serves as an anonymous placeholder instead of a regular (non-blank)
identifier and has special meaning in declarations,
as an operand, and in assignments.
空白标识符用下划线字符 _
表示。它作为匿名占位符而非普通的(非空)标识符,
在声明中,作为操作数以及在赋值中有特殊的意义,
Predeclared identifiers
预声明标识符
The following identifiers are implicitly declared in the universe block:
Types: bool byte complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr Constants: true false iota Zero value: nil Functions: append cap close complex copy delete imag len make new panic print println real recover
在全域块中,以下标识符是隐式声明的:
类型: bool byte complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr 常量: true false iota 零值: nil 函数: append cap close complex copy delete imag len make new panic print println real recover
Exported identifiers
可导出标识符
An identifier may be exported to permit access to it from another package. An identifier is exported if both:
- the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
- the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
标识符可被导出以允许从另一个包访问。同时符合以下条件即为可导出标识符:
其它所有标识符均为未导出的。
Uniqueness of identifiers
标识符的唯一性
Given a set of identifiers, an identifier is called unique if it is different from every other in the set. Two identifiers are different if they are spelled differently, or if they appear in different packages and are not exported. Otherwise, they are the same.
给定一个标识符集,若其中一个标识符不同于该集中的任一标识符,那么它就是唯一的。 若两个标识符拼写不同,或它们出现在不同的包中且未 导出,那么它们就是不同的。否则,它们就是相同的。
Constant declarations
常量声明
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, and the nth identifier on the left is bound to the value of the nth expression on the right.
ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . IdentifierList = identifier { "," identifier } . ExpressionList = Expression { "," Expression } .
常量声明将一个标识符(即常量名)列表绑定至一个常量表达式列表的值。 标识符的数量必须与表达式的数量相等,且左边第 n 个标识符会绑定至右边的第 n 个表达式的值。
常量声明 = "const" ( 常量实现 | "(" { 常量实现 ";" } ")" ) . 常量实现 = 标识符列表 [ [ 类型 ] "=" 表达式列表 ] . 标识符列表 = 标识符 { "," 标识符 } . 表达式列表 = 表达式 { "," 表达式 } .
If the type is present, all constants take the type specified, and the expressions must be assignable to that type. If the type is omitted, the constants take the individual types of the corresponding expressions. If the expression values are untyped constants, the declared constants remain untyped and the constant identifiers denote the constant values. For instance, if the expression is a floating-point literal, the constant identifier denotes a floating-point constant, even if the literal's fractional part is zero.
const Pi float64 = 3.14159265358979323846 const zero = 0.0 // untyped floating-point constant const ( size int64 = 1024 eof = -1 // untyped integer constant ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants const u, v float32 = 0, 3 // u = 0.0, v = 3.0
若该类型存在,所有常量都将获得该类型实现,且该表达式对于该类型必须是 可赋值的。若该类型被省略,则该常量将获得其对应表达式的具体类型。 若该表达式值为无类型化常量,则其余已声明无类型化常量与该常量标识符表示其常量值。 例如,若该表达式为浮点数字面,则该常量标识符表示一个浮点数常量,即使该字面的小数部分为零。
const Pi float64 = 3.14159265358979323846 const zero = 0.0 // 无类型化浮点常量 const ( size int64 = 1024 eof = -1 // 无类型化整数常量 ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 无类型化整数和字符串常量 const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Within a parenthesized const
declaration list the
expression list may be omitted from any but the first ConstSpec.
Such an empty list is equivalent to the textual substitution of the
first preceding non-empty expression list and its type if any.
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
this mechanism permits light-weight declaration of sequential values:
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // this constant is not exported )
在 const
后括号中的声明列表中,除第一个 ConstSpec 外,任何表达式列表都可省略。
若前面第一个非空表达式有类型,那么这样的空列表等价于该表达式原文和类型的代换。
因此,省略表达式的列表等价于重复前面的列表。其标识符的数量必须与上一个表达式的数量相等。
连同 iota
常量生成器,该机制允许轻量级连续值声明:
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // 该常量未导出 )
Iota
Within a constant declaration, the predeclared identifier
iota
represents successive untyped integer
constants. Its value is the index of the respective ConstSpec
in that constant declaration, starting at zero.
It can be used to construct a set of related constants:
const ( c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( a = 1 << iota // a == 1 (iota == 0) b = 1 << iota // b == 2 (iota == 1) c = 3 // c == 3 (iota == 2, unused) d = 1 << iota // d == 8 (iota == 3) ) const ( u = iota * 42 // u == 0 (untyped integer constant) v float64 = iota * 42 // v == 42.0 (float64 constant) w = iota * 42 // w == 84 (untyped integer constant) ) const x = iota // x == 0 const y = iota // y == 0
在常量声明中预声明标识符 iota
表示连续的无类型化整数
常量。每当保留字 const
出现在源码中和每个
常量实现增量后,它都会被重置为 0。它可被用来构造相关常量的集:
const ( // iota 重置为 0 c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( // iota 重置为 0 a = 1 << iota // a == 1 b = 1 << iota // b == 2 c = 3 // c == 3 (iota 未使用但仍在递增) d = 1 << iota // d == 8 ) const ( // iota 重置为 0 u = iota * 42 // u == 0 (无类型化整数常量) v float64 = iota * 42 // v == 42.0 (float64 常量) w = iota * 42 // w == 84 (无类型化整数常量) ) const x = iota // x == 0 (iota 已重置) const y = iota // y == 0 (iota 已重置)
By definition, multiple uses of iota
in the same ConstSpec all have the same value:
const ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0) bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1) _, _ // (iota == 2, unused) bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3) )
在表达式列表中,每个 iota
的值都相同,因为它只在每个常量实现后增量。
const ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 bit1, mask1 // bit1 == 2, mask1 == 1 _, _ // 跳过 iota == 2 bit3, mask3 // bit3 == 8, mask3 == 7 )
This last example exploits the implicit repetition of the last non-empty expression list.
最后一个例子采用上一个非空表达式列表的隐式副本。
Type declarations
类型声明
A type declaration binds an identifier, the type name, to a type. Type declarations come in two forms: alias declarations and type definitions.
TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . TypeSpec = AliasDecl | TypeDef .
Alias declarations
An alias declaration binds an identifier to the given type.
AliasDecl = identifier "=" Type .
类型声明将标识符,即类型名绑定至一个与现存类型有相同的 底层类型的新类型,现有类型定义的操作也会为该新类型定义。 新的类型不同于现有类型。
类型声明 = "type" ( 类型实现 | "(" { 类型实现 ";" } ")" ) . 类型实现 = 标识符 类型 .
Within the scope of the identifier, it serves as an alias for the type.
type ( nodeList = []*Node // nodeList and []*Node are identical types Polar = polar // Polar and polar denote identical types )
Type definitions
A type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
TypeDef = identifier Type .
The new type is called a defined type. It is different from any other type, including the type it is created from.
type ( Point struct{ x, y float64 } // Point and struct{ x, y float64 } are different types polar Point // polar and Point denote different types ) type TreeNode struct { left, right *TreeNode value *Comparable } type Block interface { BlockSize() int Encrypt(src, dst []byte) Decrypt(src, dst []byte) }
A defined type may have methods associated with it. It does not inherit any methods bound to the given type, but the method set of an interface type or of elements of a composite type remains unchanged:
// A Mutex is a data type with two methods, Lock and Unlock. type Mutex struct { /* Mutex fields */ } func (m *Mutex) Lock() { /* Lock implementation */ } func (m *Mutex) Unlock() { /* Unlock implementation */ } // NewMutex has the same composition as Mutex but its method set is empty. type NewMutex Mutex // The method set of PtrMutex's underlying type *Mutex remains unchanged, // but the method set of PtrMutex is empty. type PtrMutex *Mutex // The method set of *PrintableMutex contains the methods // Lock and Unlock bound to its embedded field Mutex. type PrintableMutex struct { Mutex } // MyBlock is an interface type that has the same method set as Block. type MyBlock Block
声明类型不继承任何方法绑定到现存类型, 但接口类型或复合类型元素的方法集保持不变:
// Mutex 为带有 Lock 和 Unlock 两个方法的数据类型. type Mutex struct { /* Mutex 字段 */ } func (m *Mutex) Lock() { /* Lock 实现 */ } func (m *Mutex) Unlock() { /* Unlock 实现 */ } // NewMutex 和 Mutex 拥有相同的组成,但它的方法集为空. type NewMutex Mutex // PtrMutex 的基础类型的方法集保持不变. // 但 PtrMutex 的方法集为空. type PtrMutex *Mutex // *PrintableMutex 的方法集包含方法 // Lock 和 Unlock 绑定至其匿名字段 Mutex. type PrintableMutex struct { Mutex } // MyBlock 为与 Block 拥有相同方法集的接口类型. type MyBlock Block
Type definitions may be used to define different boolean, numeric, or string types and associate methods with them:
类型声明可用来定义不同的布尔值、数字或字符串类型并对其附上方法:
type TimeZone int const ( EST TimeZone = -(5 + iota) CST MST PST ) func (tz TimeZone) String() string { return fmt.Sprintf("GMT%+dh", tz) }
Variable declarations
变量声明
A variable declaration creates one or more variables, binds corresponding identifiers to them, and gives each a type and an initial value.
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
变量声明创建一个或多个变量,为它们绑定对应的标识符,赋予其类型和初始值。
变量声明 = "var" ( 变量实现 | "(" { 变量实现 ";" } ")" ) . 变量实现 = 标识符列表 ( 类型 [ "=" 表达式列表 ] | "=" 表达式列表 ) .
var i int var U, V, W float64 var k = 0 var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // map lookup; only interested in "found"
var i int var U, V, W float64 var k = 0 var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // 映射检查;只与“found”有关
If a list of expressions is given, the variables are initialized with the expressions following the rules for assignments. Otherwise, each variable is initialized to its zero value.
若给定一个表达式列表,则变量会按照§赋值规则以表达式来初始化; 否则,每个变量初始化为其 零值。
If a type is present, each variable is given that type.
Otherwise, each variable is given the type of the corresponding
initialization value in the assignment.
If that value is an untyped constant, it is first
converted to its default type;
if it is an untyped boolean value, it is first converted to type bool
.
The predeclared value nil
cannot be used to initialize a variable
with no explicit type.
若类型存在,每个变量都会赋予该类型。否则,每个变量都会赋予在赋值中初始化值对应的类型。
若该值为无类型化常量,它首先会转换为其默认类型;
若它是一个为类型化的布尔值,它首先会转换为 bool
类型。
预声明的值 nil
无法在没有显式的类型时用于初始化变量。
var d = math.Sin(0.5) // d is float64 var i = 42 // i is int var t, ok = x.(T) // t is T, ok is bool var n = nil // illegal
var d = math.Sin(0.5) // d 为 float64 var i = 42 // i 为 int var t, ok = x.(T) // t 为 T, ok 为 bool var n = nil // 非法
Implementation restriction: A compiler may make it illegal to declare a variable inside a function body if the variable is never used.
实现限制:若在函数体内声明不会使用的变量,编译器可能将其判定为非法。
Short variable declarations
短变量声明
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
短变量声明使用此语法:
短变量声明 = 标识符列表 ":=" 表达式列表 .
It is shorthand for a regular variable declaration with initializer expressions but no types:
"var" IdentifierList = ExpressionList .
i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) r, w := os.Pipe(fd) // os.Pipe() returns two values _, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
它是有初始化表达式无类型化的常规变量声明的缩写:
"var" 标识符列表 = 表达式列表 .
i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) r, w := os.Pipe(fd) // os.Pipe() 返回两个值 _, y, _ := coord(p) // coord() 返回三个值;只与和 y 同位的值相关
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
field1, offset := nextField(str, 0) field2, offset := nextField(str, offset) // redeclares offset a, a := 1, 2 // illegal: double declaration of a or no new variable if a was declared elsewhere
不同于常规变量声明,在至少有一个非空白变量时, 短变量声明可在相同块中(若块为函数体则为形参列表),对原先声明的变量以相同的类型重声明。 因此,重声明只能出现在多变量短声明中。重声明不会引入新的变量;它只能赋予新的值给原来的变量。
field1, offset := nextField(str, 0) field2, offset := nextField(str, offset) // 重声明 offset a, a := 1, 2 // 非法:重复声明了 a,或者若 a 在别处声明,但此处没有新的变量
Short variable declarations may appear only inside functions. In some contexts such as the initializers for "if", "for", or "switch" statements, they can be used to declare local temporary variables.
短变量声明只能出现在函数内部。在某些情况下,例如初始化 if、 for、或 switch 语句时, 它们可用来声明局部临时变量。
Function declarations
函数声明
A function declaration binds an identifier, the function name, to a function.
FunctionDecl = "func" FunctionName Signature [ FunctionBody ] . FunctionName = identifier . FunctionBody = Block .
函数声明将标识符,即函数名绑定至函数。
函数声明 = "func" 函数名 ( 函数 | 签名 ) . 函数名 = 标识符 . 函数 = 签名 函数体 . 函数体 = 块 .
If the function's signature declares result parameters, the function body's statement list must end in a terminating statement.
func IndexRune(s string, r rune) int { for i, c := range s { if c == r { return i } } // invalid: missing return statement }
若函数的签名声明了结果参数,那么函数体的语句列表必须以 终止语句结束。
func IndexRune(s string, r rune) int { for i, c := range s { if c == r { return i } } // 无效:缺少返回语句 }
A function declaration may omit the body. Such a declaration provides the signature for a function implemented outside Go, such as an assembly routine.
func min(x int, y int) int { if x < y { return x } return y } func flushICache(begin, end uintptr) // implemented externally
函数声明可省略函数体。这样的标识符为 Go 外部实现的函数提供签名,例如汇编例程。
func min(x int, y int) int { if x < y { return x } return y } func flushICache(begin, end uintptr) // 外部实现
Method declarations
方法声明
A method is a function with a receiver. A method declaration binds an identifier, the method name, to a method, and associates the method with the receiver's base type.
MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] . Receiver = Parameters .
方法为带接收者的函数。方法声明将标识符,即方法名绑定至方法, 并将该接收者的基础类型关联至该方法。
方法声明 = "func" 接收者 方法名 签名 [ 函数体 ] . 接收者 = 形参 .
The receiver is specified via an extra parameter section preceding the method
name. That parameter section must declare a single non-variadic parameter, the receiver.
Its type must be of the form T
or *T
(possibly using
parentheses) where T
is a type name. The type denoted by T
is called
the receiver base type; it must not be a pointer or interface type and
it must be defined in the same package as the method.
The method is said to be bound to the base type and the method name
is visible only within selectors for type T
or *T
.
接收者通过方法名之前额外的形参部分指定。该形参部分必须声明为单个非可变形参,即接收者。
其类型形式必须为 T
或 *T
(可能使用括号),其中 T
为类型名。
由 T
表示的类型称为接收者的基础类型;
它不能为指针或接口类型且必须在同一包中声明为方法。
也就是说,该方法被绑定至基础类型,且该方法名只对类型 T
或 *T
的选择器可见。
A non-blank receiver identifier must be unique in the method signature. If the receiver's value is not referenced inside the body of the method, its identifier may be omitted in the declaration. The same applies in general to parameters of functions and methods.
For a base type, the non-blank names of methods bound to it must be unique. If the base type is a struct type, the non-blank method and field names must be distinct.
非空白接收器的标识符在该方法签名中必须是唯一的。 若该接收器的值并未在该方法体中引用,其标识符可在声明中省略。这同样适用于一般函数或方法的形参。
对于基础类型,方法绑定至该类型的非空白名称必须唯一。 若其基础类型为结构体类型,则非空白方法与字段名不能相同。
Given type Point
, the declarations
给定 Point
类型,声明
func (p *Point) Length() float64 { return math.Sqrt(p.x * p.x + p.y * p.y) } func (p *Point) Scale(factor float64) { p.x *= factor p.y *= factor }
bind the methods Length
and Scale
,
with receiver type *Point
,
to the base type Point
.
将接收者类型为 *Point
的方法 Length
和 Scale
绑定至基础类型 Point
。
The type of a method is the type of a function with the receiver as first
argument. For instance, the method Scale
has type
方法的类型就是将接收者作为第一个实参的函数类型。例如,方法 Scale
拥有类型
func(p *Point, factor float64)
However, a function declared this way is not a method.
然而,通过这种方式声明的函数不是方法。
Expressions
表达式
An expression specifies the computation of a value by applying operators and functions to operands.
表达式通过将运算符和函数应用至操作数来指定值的计算。
Operands
操作数
Operands denote the elementary values in an expression. An operand may be a literal, a (possibly qualified) non-blank identifier denoting a constant, variable, or function, or a parenthesized expression.
The blank identifier may appear as an operand only on the left-hand side of an assignment.
Operand = Literal | OperandName | "(" Expression ")" . Literal = BasicLit | CompositeLit | FunctionLit . BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . OperandName = identifier | QualifiedIdent.
操作数表示表达式中的基本值。操作数可为字面,(可能为限定的) 非空白标识符可表示一个常量、变量或函数, 方法表达式可产生函数或者括号表达式。
操作数 = 字面 | 操作数名 | 方法表达式 | "(" 表达式 ")" . 字面 = 基本字面 | 复合字面 | 函数字面 . 基本字面 = 整数字面 | 浮点数字面 | 虚数字面 | 符文字面 | 字符串字面 . 操作数名 = 标识符 | 限定标识符.
Qualified identifiers
限定标识符
A qualified identifier is an identifier qualified with a package name prefix. Both the package name and the identifier must not be blank.
QualifiedIdent = PackageName "." identifier .
限定标识符为使用包名前缀限定的标识符。包名与标识符均不能为空白的。
限定标识符 = 包名 "." 标识符 .
A qualified identifier accesses an identifier in a different package, which must be imported. The identifier must be exported and declared in the package block of that package.
math.Sin // denotes the Sin function in package math
限定标识符用于访问另一个包中的标识符,它必须被导入。 标识符必须是已导出且在该包的包块中声明。
math.Sin // 表示 math 包中的 Sin 函数
Composite literals
复合字面
Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated. They consist of the type of the literal followed by a brace-bound list of elements. Each element may optionally be preceded by a corresponding key.
CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = KeyedElement { "," KeyedElement } . KeyedElement = [ Key ":" ] Element . Key = FieldName | Expression | LiteralValue . FieldName = identifier . Element = Expression | LiteralValue .
复合字面每当为结构体、数组、切片、映射构造值,或创建一个新值时,它们都会被求值。 它们由字面的类型后跟一个大括号括住的元素列表组成。每个元素前面可选一个对应的键。
复合字面 = 字面类型 字面值 . 字面类型 = 结构体类型 | 数组类型 | "[" "..." "]" 元素类型 | 切片类型 | 映射类型 | 类型名 . 字面值 = "{" [ 元素列表 [ "," ] ] "}" . 元素列表 = 带键元素 { "," 带键元素 } . 带键元素 = [ 键 ":" ] 元素 . 键 = 字段名 | 表达式 | 字面值 . 字段名 = 标识符 . 元素 = 表达式 | 字面值 .
The LiteralType's underlying type must be a struct, array, slice, or map type (the grammar enforces this constraint except when the type is given as a TypeName). The types of the elements and keys must be assignable to the respective field, element, and key types of the literal type; there is no additional conversion. The key is interpreted as a field name for struct literals, an index for array and slice literals, and a key for map literals. For map literals, all elements must have a key. It is an error to specify multiple elements with the same field name or constant key value. For non-constant map keys, see the section on evaluation order.
字面类型的底层类型必须为结构体、数组、切片或映射类型(语法规则强制实施此约束,除非该类型作为类型名给定)。 元素和键的类型对于其各自的字段、元素以及该字面类型的键类型必须为可赋值的, 它们没有附加的转换。作为结构体字面的字段名,即数组和切片的下标以及映射字面的键,其键是可解译的。 对于映射字面,所有元素都必须有键。指定多个具有相同字段名或常量键值的元素会产生一个错误。对于非常量映射键,见求值顺序一节。
For struct literals the following rules apply:
- A key must be a field name declared in the struct type.
- An element list that does not contain any keys must list an element for each struct field in the order in which the fields are declared.
- If any element has a key, every element must have a key.
- An element list that contains keys does not need to have an element for each struct field. Omitted fields get the zero value for that field.
- A literal may omit the element list; such a literal evaluates to the zero value for its type.
- It is an error to specify an element for a non-exported field of a struct belonging to a different package.
以下规则适用于结构体字面:
- 键必须为结构体类型中声明的字段名。
- 不包含任何键的元素列表必须按字段的声明顺序列出每个结构体字段的元素。
- 若其中任何一个元素有键,那么每个元素都必须有键。
- 包含键的元素列表无需每个结构体字段都有元素。被忽略的字段会获得零值
- 字面可忽略元素列表;这样的字面对其类型求值为零值。
- 为属于不同包的结构体的未导出字段指定一个元素会产生一个错误。
Given the declarations
给定声明
type Point3D struct { x, y, z float64 } type Line struct { p, q Point3D }
one may write
origin := Point3D{} // zero value for Point3D line := Line{origin, Point3D{y: -4, z: 12.3}} // zero value for line.q.x
可写为
origin := Point3D{} // Point3D 为零值 line := Line{origin, Point3D{y: -4, z: 12.3}} // line.q.x 为零值
For array and slice literals the following rules apply:
- Each element has an associated integer index marking its position in the array.
- An element with a key uses the key as its index. The
key must be a non-negative constant
representable by
a value of type
int
; and if it is typed it must be of integer type. - An element without a key uses the previous element's index plus one. If the first element has no key, its index is zero.
以下规则适用于数组和切片字面:
- 在数组中每个元素都有与之对应的整数下标来标明它的位置。
- 带键的元素使用该键作为它的下标;键必须为常量整数表达式。
- 无键的元素使用上一个元素的下标加一。若第一个元素无键,则它的下标为零。
Taking the address of a composite literal (§Address operators) generates a pointer to a unique instance of the literal's value.
Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.
获取复合字面的地址(§地址操作符)就是为字面值的唯一实例生成一个指针。
获取复合字面的地址会生成唯一的以该字面的值初始化的变量的指针。
var pointer *Point3D = &Point3D{y: 1000}
The length of an array literal is the length specified in the literal type.
If fewer elements than the length are provided in the literal, the missing
elements are set to the zero value for the array element type.
It is an error to provide elements with index values outside the index range
of the array. The notation ...
specifies an array length equal
to the maximum element index plus one.
数组字面的长度为字面类型指定的长度。
若元素少于字面提供的长度,则缺失的元素会置为该数组元素类型的零值。
向超出数组下标范围的下标值提供元素会产生一个错误。
记法 ...
指定一个数组,其长度等于最大元素下标加一。
buffer := [10]string{} // len(buffer) == 10 intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6 days := [...]string{"Sat", "Sun"} // len(days) == 2
A slice literal describes the entire underlying array literal. Thus the length and capacity of a slice literal are the maximum element index plus one. A slice literal has the form
切片字面描述全部的底层数组字面。因此,切片字面的长度和容量为其最大元素下标加一。切片字面具有形式
[]T{x1, x2, … xn}
and is shorthand for a slice operation applied to an array:
它是切片操作应用到数组的捷径。
tmp := [n]T{x1, x2, … xn} tmp[0 : n]
Within a composite literal of array, slice, or map type T
,
elements or map keys that are themselves composite literals may elide the respective
literal type if it is identical to the element or key type of T
.
Similarly, elements or keys that are addresses of composite literals may elide
the &T
when the element or key type is *T
.
[...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}} [][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}} [][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}} map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}} map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"} type PPoint *Point [2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}} [2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
在数组、切片或映射类型 T
的复合字面中,若其元素或键本身亦为复合字面,
且该复合字面的元素类型与 T
的相同,则可省略其各自的元素或映射类型。
类似地,当元素或键类型为 *T
时,若其元素或键为复合字面的地址,则可省略 &T
。
[...]Point{{1.5, -3.5}, {0, 0}} // 等价于 [...]Point{Point{1.5, -3.5}, Point{0, 0}} [][]int{{1, 2, 3}, {4, 5}} // 等价于 [][]int{[]int{1, 2, 3}, []int{4, 5}} [][]Point{{{0, 1}, {1, 2}}} // 等价于 [][]Point{[]Point{Point{0, 1}, Point{1, 2}}} map[string]Point{"orig": {0, 0}} // 等价于 map[string]Point{"orig": Point{0, 0}} map[Point]string{{0, 0}: "orig"} // 等价于 map[Point]string{Point{0, 0}: "orig"} type PPoint *Point [2]*Point{{1.5, -3.5}, {}} // 等价于 [2]*Point{&Point{1.5, -3.5}, &Point{}} [2]PPoint{{1.5, -3.5}, {}} // 等价于 [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
A parsing ambiguity arises when a composite literal using the TypeName form of the LiteralType appears as an operand between the keyword and the opening brace of the block of an "if", "for", or "switch" statement, and the composite literal is not enclosed in parentheses, square brackets, or curly braces. In this rare case, the opening brace of the literal is erroneously parsed as the one introducing the block of statements. To resolve the ambiguity, the composite literal must appear within parentheses.
当复合字面使用字面类型的类型名形式时,若它作为操作数出现在关键字 "if"、"for" 或 "switch" 语句及其对应块的开大括号之间,且该复合字面未在小括号、中括号或大括号内, 那么就会产生解析歧义。在这种罕见情况下,该字面的开大括号会被错误地解析为引入语句块的符号。 为解决这种歧义,该复合字面必须出现在小括号中。
if x == (T{a,b,c}[i]) { … } if (x == T{a,b,c}[i]) { … }
Examples of valid array, slice, and map literals:
// list of prime numbers primes := []int{2, 3, 5, 7, 9, 2147483647} // vowels[ch] is true if ch is a vowel vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true} // the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1} // frequencies in Hz for equal-tempered scale (A4 = 440Hz) noteFrequency := map[string]float32{ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83, "G0": 24.50, "A0": 27.50, "B0": 30.87, }
有效的数组、切片和映射字面的例子:
// 素数列表 primes := []int{2, 3, 5, 7, 9, 2147483647} // 若 ch 为元音则 vowels[ch] 为 true vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true} // 数组 [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1} // 平均律以 Hz 为单位的频率(A4 = 440Hz) noteFrequency := map[string]float32{ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83, "G0": 24.50, "A0": 27.50, "B0": 30.87, }
Function literals
函数字面
A function literal represents an anonymous function.
FunctionLit = "func" Signature FunctionBody .
函数字面表示一个匿名函数。
函数字面 = "func" 函数 .
func(a, b int, z float64) bool { return a*b < int(z) }
A function literal can be assigned to a variable or invoked directly.
函数字面可赋予一个变量或直接调用。
f := func(x, y int) int { return x + y } func(ch chan int) { ch <- ACK }(replyChan)
Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.
闭包的函数字面:它们可引用定义在外围函数中的变量。 那些变量共享于外围函数与函数字面之间,并且只要它们可访问就会继续存在。
Primary expressions
主表达式
Primary expressions are the operands for unary and binary expressions.
PrimaryExpr = Operand | Conversion | MethodExpr | PrimaryExpr Selector | PrimaryExpr Index | PrimaryExpr Slice | PrimaryExpr TypeAssertion | PrimaryExpr Arguments . Selector = "." identifier . Index = "[" Expression "]" . Slice = "[" [ Expression ] ":" [ Expression ] "]" | "[" [ Expression ] ":" Expression ":" Expression "]" . TypeAssertion = "." "(" Type ")" . Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
主表达式为一元和二元表达式的操作数。
主表达式 = 操作数 | 类型转换 | 主表达式 选择器 | 主表达式 下标 | 主表达式 切片 | 主表达式 类型断言 | 主表达式 实参 . 选择器 = "." 标识符 . 下标 = "[" 表达式 "]" . 切片 = "[" [ 表达式 ] ":" [ 表达式 ] "]" | "[" [ 表达式 ] ":" 表达式 ":" 表达式 "]" . 类型断言 = "." "(" 类型 ")" . 实参 = "(" [ ( 表达式列表 | 类型 [ "," 表达式列表 ] ) [ "..." ] [ "," ] ] ")" .
x 2 (s + ".txt") f(3.1415, true) Point{1, 2} m["foo"] s[i : j + 1] obj.color f.p[i].x()
Selectors
选择器
For a primary expression x
that is not a package name, the
selector expression
x.f
denotes the field or method f
of the value x
(or sometimes *x
; see below).
The identifier f
is called the (field or method) selector;
it must not be the blank identifier.
The type of the selector expression is the type of f
.
If x
is a package name, see the section on
qualified identifiers.
表示值 x
(有时为 *x
,见下)的字段或方法 f
。
标识符 f
称为(字段或方法)选择器,它不能为空白标识符。
该选择器表达式的类型即为 f
的类型。若 x
为包名,
见限定标识符的相关章节。
A selector f
may denote a field or method f
of
a type T
, or it may refer
to a field or method f
of a nested
embedded field of T
.
The number of embedded fields traversed
to reach f
is called its depth in T
.
The depth of a field or method f
declared in T
is zero.
The depth of a field or method f
declared in
an embedded field A
in T
is the
depth of f
in A
plus one.
选择器 f
可代表类型为 T
的字段或方法 f
,
或引用 T
中嵌套匿名字段的字段或方法 f
。
在 T
中遍历区域 f
的匿名字段所得的数量称为它的深度。
以 T
声明的字段或方法 f
的深度为 0。
在 T
中以匿名字段 A
声明的字段或方法 f
的深度
为 f
在 A
中的深度加 1。
The following rules apply to selectors:
-
For a value
x
of typeT
or*T
whereT
is not a pointer or interface type,x.f
denotes the field or method at the shallowest depth inT
where there is such anf
. If there is not exactly onef
with shallowest depth, the selector expression is illegal. -
For a value
x
of typeI
whereI
is an interface type,x.f
denotes the actual method with namef
of the dynamic value ofx
. If there is no method with namef
in the method set ofI
, the selector expression is illegal. -
As an exception, if the type of
x
is a defined pointer type and(*x).f
is a valid selector expression denoting a field (but not a method),x.f
is shorthand for(*x).f
. -
In all other cases,
x.f
is illegal. -
If
x
is of pointer type and has the valuenil
andx.f
denotes a struct field, assigning to or evaluatingx.f
causes a run-time panic. -
If
x
is of interface type and has the valuenil
, calling or evaluating the methodx.f
causes a run-time panic.
以下规则适用于选择器:
-
当
T
为非指针或接口类型时,对于类型T
或*T
的值x
,x.f
中的f
表示在T
中最浅深度的字段或方法。若f
并非只有一个, 该选择器表达式即为非法的。 -
对于接口类型
I
的值x
,x.f
表示x
的动态值的名为f
的真实方法。若在I
的方法集中没有名为f
的方法,该选择器即为非法的。 -
As an exception, if the type of
x
is a named pointer type and(*x).f
is a valid selector expression denoting a field (but not a method),x.f
is shorthand for(*x).f
. -
其它情况下,所有
x.f
均为非法的。 -
若
x
为指针类型且值为nil
且x.f
表示一个结构体字段,对x.f
进行赋值或求值会产生运行时恐慌。 -
If
x
is of interface type and has the valuenil
, calling or evaluating the methodx.f
causes a run-time panic.
For example, given the declarations:
type T0 struct { x int } func (*T0) M0() type T1 struct { y int } func (T1) M1() type T2 struct { z int T1 *T0 } func (*T2) M2() type Q *T2 var t T2 // with t.T0 != nil var p *T2 // with p != nil and (*p).T0 != nil var q Q = p
例如,给定声明:
type T0 struct { x int } func (*T0) M0() type T1 struct { y int } func (T1) M1() type T2 struct { z int T1 *T0 } func (*T2) M2() type Q *T2 var t T2 // 其中 t.T0 != nil var p *T2 // 其中 p != nil 且 (*p).T0 != nil var q Q = p
one may write:
t.z // t.z t.y // t.T1.y t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y p.x // (*(*p).T0).x q.x // (*(*q).T0).x (*q).x is a valid field selector p.M0() // ((*p).T0).M0() M0 expects *T0 receiver p.M1() // ((*p).T1).M1() M1 expects T1 receiver p.M2() // p.M2() M2 expects *T2 receiver t.M2() // (&t).M2() M2 expects *T2 receiver, see section on Calls
可以写:
t.z // t.z t.y // t.T1.y t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y p.x // (*(*p).T0).x q.x // (*(*q).T0).x (*q).x 是有效的字段选择器 p.M0() // ((*p).T0).M0() M0 期望 *T0 接收者 p.M1() // ((*p).T1).M1() M1 期望 T1 接收者 p.M2() // p.M2() M2 期望 *T2 接收者 t.M2() // (&t).M2() M2 期望 *T2 接收者,见“调用”一节
but the following is invalid:
q.M0() // (*q).M0 is valid but not a field selector
但以下是无效的:
q.M0() // (*q).M0 有效但并非字段选择器
Method expressions
方法表达式
If M
is in the method set of type T
,
T.M
is a function that is callable as a regular function
with the same arguments as M
prefixed by an additional
argument that is the receiver of the method.
MethodExpr = ReceiverType "." MethodName . ReceiverType = Type .
若方法 M
在类型 T
的方法集中,
那么 T.M
是可以像常规函数一样调用的函数,它通过与 M
前缀的附加实参相同的实参调用,该实参即为该方法的接收者。
方法表达式 = 接收者类型 "." 方法名 . 接收者类型 = 类型名 | "(" "*" 类型名 ")" | "(" 接收者类型 ")" .
Consider a struct type T
with two methods,
Mv
, whose receiver is of type T
, and
Mp
, whose receiver is of type *T
.
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T
考虑结构体类型 T
,它带有两个方法:Mv
的接收者类型为
T
,以及 Mp
的接收者类型为 *T
。
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // 值接收者 func (tp *T) Mp(f float32) float32 { return 1 } // 指针接收者 var t T
The expression
T.Mv
yields a function equivalent to Mv
but
with an explicit receiver as its first argument; it has signature
func(tv T, a int) int
That function may be called normally with an explicit receiver, so these five invocations are equivalent:
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
表达式
T.Mv
会产生一个等价于 Mv
的方法,不过它带有显式的接收者作为其第一个实参。
它的签名为
func(tv T, a int) int
该函数可通过显式的接收者正常调用,因此以下五种调用法是等价的:
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
Similarly, the expression
(*T).Mp
yields a function value representing Mp
with signature
func(tp *T, f float32) float32
同样,表达式
(*T).Mp
会产生一个表示 Mp
的函数值,其签名为
func(tp *T, f float32) float32
For a method with a value receiver, one can derive a function with an explicit pointer receiver, so
(*T).Mv
yields a function value representing Mv
with signature
func(tv *T, a int) int
对于带有值接收者的方法,它可导出一个带显式指针接收者的函数,因此
(*T).Mv
会产生一个表示 Mv
的函数值,其签名为
func(tv *T, a int) int
Such a function indirects through the receiver to create a value to pass as the receiver to the underlying method; the method does not overwrite the value whose address is passed in the function call.
这样的函数通过接收者间接创建了一个值来通过接收者传给底层方法; 该方法并不会覆盖在函数调用中传递地址的值。
The final case, a value-receiver function for a pointer-receiver method, is illegal because pointer-receiver methods are not in the method set of the value type.
最后一种情况,“值-接收者”函数对于“指针-接收者”方法来说是非法的, 因为“指针-接收者”方法并不在值类型的方法集中。
Function values derived from methods are called with function call syntax;
the receiver is provided as the first argument to the call.
That is, given f := T.Mv
, f
is invoked
as f(t, 7)
not t.f(7)
.
To construct a function that binds the receiver, use a
function literal or
method value.
由方法导出的函数值通过函数调用方法调用,接收者作为该调用的第一个实参。
即,给定 f := T.Mv
,f
会作为 f(t, 7)
而非 t.f(7)
调用。要构造一个绑定了接收者的函数,应使用
函数字面或方法值。
It is legal to derive a function value from a method of an interface type. The resulting function takes an explicit receiver of that interface type.
从一个接口类型的方法导出函数值是合法的,其结果函数接受一个显式的该接口类型的接收者。
Method values
方法值
If the expression x
has static type T
and
M
is in the method set of type T
,
x.M
is called a method value.
The method value x.M
is a function value that is callable
with the same arguments as a method call of x.M
.
The expression x
is evaluated and saved during the evaluation of the
method value; the saved copy is then used as the receiver in any calls,
which may be executed later.
若表达式 x
拥有静态类型 T
且 M
在类型 T
的方法集中,那么 x.M
就称作方法值。方法值 x.M
是一个函数值,它能够以 x.M
方法调用的参数作为实参调用。表达式 x
在方法值求值时被调用并保存。
之后保存的副本可在任何调用中被用作接收者,它可以之后再执行。
The type T
may be an interface or non-interface type.
类型 T
可为接口或非接口类型。
As in the discussion of method expressions above,
consider a struct type T
with two methods,
Mv
, whose receiver is of type T
, and
Mp
, whose receiver is of type *T
.
如之前方法表达式的讨论中那样,考虑一个结构体类型
T
,它有两个方法:Mv
接收者类型为 T
,以及
Mp
接收者类型为 *T
。
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // value receiver func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T var pt *T func makeT() T
type T struct { a int } func (tv T) Mv(a int) int { return 0 } // 值接收者 func (tp *T) Mp(f float32) float32 { return 1 } // 指针接收者 var t T var pt *T func makeT() T
The expression
表达式
t.Mv
yields a function value of type
产生一个类型为
func(int) int
These two invocations are equivalent:
的函数值。
以下两个调用是等价的:
t.Mv(7) f := t.Mv; f(7)
Similarly, the expression
同样,表达式
pt.Mp
yields a function value of type
会产生一个类型为
func(float32) float32
的函数值。
As with selectors, a reference to a non-interface method with a value receiver
using a pointer will automatically dereference that pointer: pt.Mv
is equivalent to (*pt).Mv
.
对于选择器,通过指针引用非接口方法的的值接收者将自动解引用该指针:
pt.Mv
等价于 (*pt).Mv
。
As with method calls, a reference to a non-interface method with a pointer receiver
using an addressable value will automatically take the address of that value: t.Mp
is equivalent to (&t).Mp
.
对于方法调用,通过可寻址值引用非接口方法的指针接收者将自动获取该值的地址:
t.Mp
等价于 (&t).Mp
。
f := t.Mv; f(7) // like t.Mv(7) f := pt.Mp; f(7) // like pt.Mp(7) f := pt.Mv; f(7) // like (*pt).Mv(7) f := t.Mp; f(7) // like (&t).Mp(7) f := makeT().Mp // invalid: result of makeT() is not addressable
f := t.Mv; f(7) // 如同 个 t.Mv(7) f := pt.Mp; f(7) // 如同 pt.Mp(7) f := pt.Mv; f(7) // 如同 (*pt).Mv(7) f := t.Mp; f(7) // 如同 (&t).Mp(7) f := makeT().Mp // 无效:makeT() 的结果不可寻址
Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type.
上面的示例使用了非接口类型,然而从接口类型的值创建方法值也是合法的。
var i interface { M(int) } = myVal f := i.M; f(7) // like i.M(7)
var i interface { M(int) } = myVal f := i.M; f(7) // 如同 i.M(7)
Index expressions
下标表达式
A primary expression of the form
形式为
a[x]
denotes the element of the array, pointer to array, slice, string or map a
indexed by x
.
The value x
is called the index or map key, respectively.
The following rules apply:
的主表达式表示数组、数组指针、切片、字符串或映射 a
的元素通过 x
检索。
值 x
称为 下标 或 映射键。以下规则适用于其对应的类型:
If a
is not a map:
- the index
x
must be of integer type or an untyped constant - a constant index must be non-negative and
representable by a value of type
int
- a constant index that is untyped is given type
int
- the index
x
is in range if0 <= x < len(a)
, otherwise it is out of range
若 a
并非一个映射:
- 下标
x
必须为整数类型或无类型化的;若0 <= x < len(a)
则该下标在界内,否则即为越界 - a 常量下标必须为可表示成
int
类型的值
For a
of array type A
:
- a constant index must be in range
- if
x
is out of range at run time, a run-time panic occurs a[x]
is the array element at indexx
and the type ofa[x]
is the element type ofA
对于数组类型 A
的 a
:
For a
of pointer to array type:
a[x]
is shorthand for(*a)[x]
对于数组指针类型的 a
:
a[x]
为(*a)[x]
的简写
For a
of slice type S
:
- if
x
is out of range at run time, a run-time panic occurs a[x]
is the slice element at indexx
and the type ofa[x]
is the element type ofS
对于切片类型 S
的 a
:
- 若
x
在运行时越界, 就会引发一个运行时恐慌 a[x]
是下标为x
的切片元素且a[x]
的类型为S
的元素类型
For a
of string type:
- a constant index must be in range
if the string
a
is also constant - if
x
is out of range at run time, a run-time panic occurs a[x]
is the non-constant byte value at indexx
and the type ofa[x]
isbyte
a[x]
may not be assigned to
对于字符串类型 的 a
:
For a
of map type M
:
x
's type must be assignable to the key type ofM
- if the map contains an entry with key
x
,a[x]
is the map element with keyx
and the type ofa[x]
is the element type ofM
- if the map is
nil
or does not contain such an entry,a[x]
is the zero value for the element type ofM
对于映射类型 M
的 a
:
x
的类型必须可赋值至M
的键类型- 若映射包含键为
x
的项,则a[x]
为键x
的映射值, 且a[x]
的类型为M
的值类型 - 若映射为
nil
或不包含这样的项,a[x]
为M
值类型的零值
Otherwise a[x]
is illegal.
否则 a[x]
即为非法的。
An index expression on a map a
of type map[K]V
used in an assignment or initialization of the special form
在类型为 map[K]V
的映射 a
中,
下标表达式可在赋值或初始化中通过特殊形式
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
yields an additional untyped boolean value. The value of ok
is
true
if the key x
is present in the map, and
false
otherwise.
产生一个附加的无类型化布尔值。若键 x
存在于映射中,则
ok
的值为 true
,否则即为 false
。
Assigning to an element of a nil
map causes a
run-time panic.
Slice expressions
切片表达式
Slice expressions construct a substring or slice from a string, array, pointer to array, or slice. There are two variants: a simple form that specifies a low and high bound, and a full form that also specifies a bound on the capacity.
切片表达式从一个字符串、数组、数组指针或切片中构造一个子串或切片。切片有两种变体: 简单形式指定了一个上界和下界,完整形式还指定了容量的边界。
Simple slice expressions
简单切片表达式
For a string, array, pointer to array, or slice a
, the primary expression
对于字符串,数组,数组指针或切片 a
,主表达式
a[low : high]
constructs a substring or slice. The indices low
and
high
select which elements of operand a
appear
in the result. The result has indices starting at 0 and length equal to
high
- low
.
After slicing the array a
会构造一个字串或切片。下标 low
和 high
则选出操作数
a
中哪些元素出现在结果中。该结果的下标起始于 0 且长度等于
high
- low
。
在切下数组 a
a := [5]int{1, 2, 3, 4, 5} s := a[1:4]
the slice s
has type []int
, length 3, capacity 4, and elements
之后,切片 s
的类型为 []int
,长度为 3,容量为 4,且元素
s[0] == 2 s[1] == 3 s[2] == 4
For convenience, any of the indices may be omitted. A missing low
index defaults to zero; a missing high
index defaults to the length of the
sliced operand:
a[2:] // same as a[2 : len(a)] a[:3] // same as a[0 : 3] a[:] // same as a[0 : len(a)]
为方便起见,任何下标都可省略。略去的 low
下标默认为零;
略去的 high
下标默认为已切下的操作数的长度:
a[2:] // 等价于 a[2 : len(a)] a[:3] // 等价于 a[0 : 3] a[:] // 等价于 a[0 : len(a)]
For arrays or strings, the indices are in range if
0
<= low
<= high
<= len(a)
,
otherwise they are out of range.
For slices, the upper index bound is the slice capacity cap(a)
rather than the length.
A constant index must be non-negative and
representable by a value of type
int
; for arrays or constant strings, constant indices must also be in range.
If both indices are constant, they must satisfy low <= high
.
If the indices are out of range at run time, a run-time panic occurs.
对于数组或字符串,若 0
<= low
<= high
<= len(a)
,
下标即在界内,否则即在界外
。
对于切片,其上界为该切片的容量 cap(a)
而非长度。常量下标必为非负值,
且可表示为 int
类型的值;对于数组或常量字符串,常量下标必须也在界内。若二者下标均为常量,它们必定满足
low <= high
。若 a
为 nil
或其下标在运行时越界,就会引发一个运行时恐慌。
Except for untyped strings, if the sliced operand is a string or slice,
the result of the slice operation is a non-constant value of the same type as the operand.
For untyped string operands the result is a non-constant value of type string
.
If the sliced operand is an array, it must be addressable
and the result of the slice operation is a slice with the same element type as the array.
除无类型化字符串外,若已切下的操作数为字符串或切片,
该切片操作的结果即为与操作数类型相同的非常量值。
对于无类型化的字符串操作数,其结果为 string
类型的非常量值。
若已切下操作数为数组,它必须为可寻址的,
且该切片操作的结果为以相同元素类型作为数组的切片。
If the sliced operand of a valid slice expression is a nil
slice, the result
is a nil
slice. Otherwise, if the result is a slice, it shares its underlying
array with the operand.
若一个有效切片表达式的被切操作数为 nil
切片,则其结果为
nil
切片。否则其结果与其操作数共享底层数组。
Full slice expressions
完整切片表达式
For an array, pointer to array, or slice a
(but not a string), the primary expression
对于数组、数组指针或切片 a
(除了字符串),主表达式
a[low : high : max]
constructs a slice of the same type, and with the same length and elements as the simple slice
expression a[low : high]
. Additionally, it controls the resulting slice's capacity
by setting it to max - low
. Only the first index may be omitted; it defaults to 0.
After slicing the array a
构造一个同类型的切片,它与简单切片 a[low : high]
的长度和元素相同。
此外,它能通过将其设置为 max - low
来控制结果切片的容量。
只有第一个下标可被忽略,它默认为 0。在对数组 a
进行切片后
a := [5]int{1, 2, 3, 4, 5} t := a[1:3:5]
the slice t
has type []int
, length 2, capacity 4, and elements
切片 t
拥有类型 []int
,长度为 2,容量为 4,且元素
t[0] == 2 t[1] == 3
As for simple slice expressions, if a
is a pointer to an array,
a[low : high : max]
is shorthand for (*a)[low : high : max]
.
If the sliced operand is an array, it must be addressable.
对于简单切片表达式,若 a
为数组指针,则 a[low : high : max]
为 (*a)[low : high : max]
的简写。若被切操作数为数组,它必须是可寻址的。
The indices are in range if 0 <= low <= high <= max <= cap(a)
,
otherwise they are out of range.
A constant index must be non-negative and
representable by a value of type
int
; for arrays, constant indices must also be in range.
If multiple indices are constant, the constants that are present must be in range relative to each
other.
If the indices are out of range at run time, a run-time panic occurs.
若 0 <= low <= high <= max <= cap(a)
,则下标在界内,
否则在界外。常量 下标必须为非负值且可被表示为
int
类型的值;对于数组,常量下标也必须在界内。若多个下标为常量,
则存在的常量必须在彼此的界内。若下标在运行时越界,就会引发一个运行时恐慌。
Type assertions
类型断言
For an expression x
of interface type
and a type T
, the primary expression
对于接口类型的表达式 x
与类型 T
,主表达式
x.(T)
asserts that x
is not nil
and that the value stored in x
is of type T
.
The notation x.(T)
is called a type assertion.
断言 x
不为 nil
且存储于 x
中的值其类型为 T
。
记法 x.(T)
称为类型断言。
More precisely, if T
is not an interface type, x.(T)
asserts
that the dynamic type of x
is identical
to the type T
.
In this case, T
must implement the (interface) type of x
;
otherwise the type assertion is invalid since it is not possible for x
to store a value of type T
.
If T
is an interface type, x.(T)
asserts that the dynamic type
of x
implements the interface T
.
更确切地说,若 T
为非接口类型,x.(T)
断言 x
的动态类型
与 T
相同。在此情况下,T
必须实现 x
的(接口)类型,除非其类型断言由于无法为
x
存储类型为 T
的值而无效。若 T
为接口类型,
x.(T)
则断言 x
的动态类型实现了接口 T
。
If the type assertion holds, the value of the expression is the value
stored in x
and its type is T
. If the type assertion is false,
a run-time panic occurs.
In other words, even though the dynamic type of x
is known only at run time, the type of x.(T)
is
known to be T
in a correct program.
var x interface{} = 7 // x has dynamic type int and value 7 i := x.(int) // i has type int and value 7 type I interface { m() } func f(y I) { s := y.(string) // illegal: string does not implement I (missing method m) r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader … }
若该类型断言成立,该表达式的值即为存储于 x
中的值,且其类型为 T
。若该类型断言不成立,
就会出现一个运行时恐慌。换句话说,即使 x
的动态类型只能在运行时可知,在正确的程序中,x.(T)
的类型也可知为 T
。
var x interface{} = 7 // x 拥有动态类型 int 与值 7 i := x.(int) // i 拥有类型 int 与值 7 type I interface { m() } func f(y I) { s := y.(string) // 非法:string 没有实现 I(缺少方法 m) r := y.(io.Reader) // r 拥有 类型 io.Reader 且 y 必须同时实现了 I 和 io.Reader … }
A type assertion used in an assignment or initialization of the special form
类型断言在赋值或初始化中通过特殊形式
v, ok = x.(T) v, ok := x.(T) var v, ok = x.(T) var v, ok T1 = x.(T)
yields an additional untyped boolean value. The value of ok
is true
if the assertion holds. Otherwise it is false
and the value of v
is
the zero value for type T
.
No run-time panic occurs in this case.
产生一个附加的无类型化布尔值。若该断言成立,ok
的值为 true
,否则即为
false
,且 v
的值为类型为 T
的零值。
此种情况不会触发运行时恐慌。
Calls
调用
Given an expression f
of function type
F
,
给定函数类型为 F
的表达式 f
,
f(a1, a2, … an)
calls f
with arguments a1, a2, … an
.
Except for one special case, arguments must be single-valued expressions
assignable to the parameter types of
F
and are evaluated before the function is called.
The type of the expression is the result type
of F
.
A method invocation is similar but the method itself
is specified as a selector upon a value of the receiver type for
the method.
math.Atan2(x, y) // function call var pt *Point pt.Scale(3.5) // method call with receiver pt
以实参 a1, a2, … an
调用 f
。
除一种特殊情况外,实参必须为 可赋予
F
的形参类型的单值表达式,且在该函数被调用前求值。
该表达式的类型为 F
的返回类型。
方法调用也类似,只不过使用接收者类型值的选择器操作来指定方法。
math.Atan2(x, y) // 函数调用 var pt *Point pt.Scale(3.5) // 带接收者 pt 的方法调用
In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the calling function when the function returns.
在函数调用中,函数值与实参按一般顺序求值。 在它们求值后,该调用的形参传值至该函数,被调用函数开始执行。 当函数返回时,该函数的返回形参将值传回调用函数。
Calling a nil
function value
causes a run-time panic.
调用 nil
函数值会引发 运行时恐慌。
As a special case, if the return values of a function or method
g
are equal in number and individually
assignable to the parameters of another function or method
f
, then the call f(g(parameters_of_g))
will invoke f
after binding the return values of
g
to the parameters of f
in order. The call
of f
must contain no parameters other than the call of g
,
and g
must have at least one return value.
If f
has a final ...
parameter, it is
assigned the return values of g
that remain after
assignment of regular parameters.
作为一种特殊情况,若函数或方法 g
的返回值在数量上等于函数或方法 f
的形参,
且分别可赋予它,那么调用 f(g(g 的形参))
将在依序绑定 g
的返回值至 f
的形参后引用 f
。除 g
的调用外,
f
的调用必须不包含任何形参。若 f
的最后有 ...
形参,
它在常规的形参赋值后,可被赋予 g
余下的返回值。
func Split(s string, pos int) (string, string) { return s[0:pos], s[pos:] } func Join(s, t string) string { return s + t } if Join(Split(value, len(value)/2)) != value { log.Panic("test fails") }
A method call x.m()
is valid if the method set
of (the type of) x
contains m
and the
argument list can be assigned to the parameter list of m
.
If x
is addressable and &x
's method
set contains m
, x.m()
is shorthand
for (&x).m()
:
若 x
(的类型)的方法集包含 m
,
且其实参列表可赋予 m
的形参列表,方法调用 x.m()
即为有效的。
若 x
为 可寻址的且 &x
的方法集包含 m
,
x.m()
即为 (&x).m()
的简写:
var p Point p.Scale(3.5)
There is no distinct method type and there are no method literals.
其中即没有明显的方法类型,也没有方法字面。
Passing arguments to ...
parameters
传递实参至...形参
If f
is variadic with a final
parameter p
of type ...T
, then within f
the type of p
is equivalent to type []T
.
If f
is invoked with no actual arguments for p
,
the value passed to p
is nil
.
Otherwise, the value passed is a new slice
of type []T
with a new underlying array whose successive elements
are the actual arguments, which all must be assignable
to T
. The length and capacity of the slice is therefore
the number of arguments bound to p
and may differ for each
call site.
若函数 f
最后一个形参 p
的类型为 ...T
,
那么它就是变参函数,在 f
中,p
的类型等价于 []T
。若 f
在调用时 p
没有实参,
那么传给 p
的值为 nil
,否则传入的值为 []T
类型的新切片,其新的底层数组中连续的元素即为实际的实参,它们必须都可赋予类型
T
。因此,该切片的长度和容量为绑定至 p
的实参的个数,
且对于每一个调用位置可能都不同。
Given the function and calls
给定函数和调用
func Greeting(prefix string, who ...string) Greeting("nobody") Greeting("hello:", "Joe", "Anna", "Eileen")
within Greeting
, who
will have the value
nil
in the first call, and
[]string{"Joe", "Anna", "Eileen"}
in the second.
在 Greeting
中,who
在第一次调用将拥有值
nil
,而在第二次调用中则拥有值
[]string{"Joe", "Anna", "Eileen"}
。
If the final argument is assignable to a slice type []T
, it may be
passed unchanged as the value for a ...T
parameter if the argument
is followed by ...
. In this case no new slice is created.
若最后的实参可赋予类型为 []T
的切片且后跟着 ...
,
它可能作为 ...T
形参的值不变而被传入。
Given the slice s
and call
给定切片 s
与调用
s := []string{"James", "Jasmine"} Greeting("goodbye:", s...)
within Greeting
, who
will have the same value as s
with the same underlying array.
在 Greeting
中,who
将作为与 s
一样的值拥有与其相同的底层数组。
Operators
操作符
Operators combine operands into expressions.
Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" . mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
操作符与操作数结合成为表达式。
表达式 = 一元表达式 | 表达式 二元操作符 一元表达式 . 一元表达式 = 主表达式 | 一元操作符 一元表达式 . 二元操作符 = "||" | "&&" | 关系操作符 | 加法操作符 | 乘法操作符 . 关系操作符 = "==" | "!=" | "<" | "<=" | ">" | ">=" . 加法操作符 = "+" | "-" | "|" | "^" . 乘法操作符 = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . 一元操作符 = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
Comparisons are discussed elsewhere. For other binary operators, the operand types must be identical unless the operation involves shifts or untyped constants. For operations involving constants only, see the section on constant expressions.
比较操作将在别处讨论。 对于其它二元操作符,操作数的类型必须相同, 除非该操作包含移位或无类型化常量。
Except for shift operations, if one operand is an untyped constant and the other operand is not, the constant is converted to the type of the other operand.
除移位操作外,若其中一个操作数为无类型化常量而另一个不是, 该常量需类型转换为另一个操作数的类型。
The right operand in a shift expression must have unsigned integer type
or be an untyped constant representable by a
value of type uint
.
If the left operand of a non-constant shift expression is an untyped constant,
it is first converted to the type it would assume if the shift expression were
replaced by its left operand alone.
var s uint = 33 var i = 1<<s // 1 has type int var j int32 = 1<<s // 1 has type int32; j == 0 var k = uint64(1<<s) // 1 has type uint64; k == 1<<33 var m int = 1.0<<s // 1.0 has type int; m == 0 if ints are 32bits in size var n = 1.0<<s == j // 1.0 has type int32; n == true var o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size var p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift var v float32 = 1<<s // illegal: 1 has type float32, cannot shift var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression var x = a[1.0<<s] // 1.0 has type int; x == a[0] if ints are 32bits in size var a = make([]byte, 1.0<<s) // 1.0 has type int; len(a) == 0 if ints are 32bits in size
移位表达式中的右操作数必须为无符号整数,或可转换为无符号整数的无类型化常量。 若非常量移位表达式的左操作数为无类型化常量,且该移位表达式已被其左操作数独自取代, 它首先会转换为其假定的类型。
var s uint = 33 var i = 1<<s // 1 的类型为 int var j int32 = 1<<s // 1 的类型为 int32;j == 0 var k = uint64(1<<s) // 1 的类型为 uint64;k == 1<<33 var m int = 1.0<<s // 1.0 的类型为 int;若 int 的大小为 32 位,则 m == 0 var n = 1.0<<s == j // 1.0 的类型为 int32;n == true var o = 1<<s == 2<<s // 1 与 2 的类型为 int;若 int 的大小为 32 位,则 o == true var p = 1<<s == 1<<33 // 若 int 的大小为 32 位即为非法:虽然 1 的类型为 int,但 1<<33 溢出了 int var u = 1.0<<s // 非法: 1.0 的类型为 float64,不能移位 var u1 = 1.0<<s != 0 // 非法: 1.0 的类型为 float64,不能移位 var u2 = 1<<s != 1.0 // 非法: 1 的类型为 float64,不能移位 var v float32 = 1<<s // 非法: 1 的类型为 float32,不能移位 var w int64 = 1.0<<33 // 1.0<<33 为常量移位表达式
Operator precedence
操作符优先级
Unary operators have the highest precedence.
As the ++
and --
operators form
statements, not expressions, they fall
outside the operator hierarchy.
As a consequence, statement *p++
is the same as (*p)++
.
一元操作符拥有最高优先级。
++
和 --
操作符是语句,而非表达式,它们不属于运算符一级。
因此,语句 *p++
等价于 (*p)++
。
There are five precedence levels for binary operators.
Multiplication operators bind strongest, followed by addition
operators, comparison operators, &&
(logical AND),
and finally ||
(logical OR):
Precedence Operator 5 * / % << >> & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 ||
二元操作符有五种优先级。
乘法操作符结合性最强,其次为加法操作符、比较操作符、&&
(逻辑与),
最后为 ||
(逻辑或):
优先级 操作符 5 * / % << >> & &^ 4 + - | ^ 3 == != < <= > >= 2 && 1 ||
Binary operators of the same precedence associate from left to right.
For instance, x / y * z
is the same as (x / y) * z
.
相同优先级的二元操作符从左到右结合。
例如,x / y * z
等价于 (x / y) * z
。
+x 23 + 3*x[i] x <= f() ^a >> b f() || g() x == y+1 && <-chanPtr > 0
Arithmetic operators
算数操作符
Arithmetic operators apply to numeric values and yield a result of the same
type as the first operand. The four standard arithmetic operators (+
,
-
, *
, /
) apply to integer,
floating-point, and complex types; +
also applies to strings.
The bitwise logical and shift operators apply to integers only.
+ sum integers, floats, complex values, strings - difference integers, floats, complex values * product integers, floats, complex values / quotient integers, floats, complex values % remainder integers & bitwise AND integers | bitwise OR integers ^ bitwise XOR integers &^ bit clear (AND NOT) integers << left shift integer << unsigned integer >> right shift integer >> unsigned integer
算数操作符适用于数值,并产生相同类型的结果作为第一个操作数。四个基本算数操作符
(+
,-
,*
,/
)适用于整数、浮点数和复数类型;
+
也适用于字符串。按位逻辑和移位运算符仅适用于整数。
+ 和 integers, floats, complex values, strings - 差 integers, floats, complex values * 积 integers, floats, complex values / 商 integers, floats, complex values % 余 integers & 按位与 integers | 按位或 integers ^ 按位异或 integers &^ 位清除(与非) integers << 向左移位 integer << unsigned integer >> 向右移位 integer >> unsigned integer
Strings can be concatenated using the +
operator
or the +=
assignment operator:
字符串可使用 +
操作符连结或 +=
赋值操作符:
For two integer values x
and y
, the integer quotient
q = x / y
and remainder r = x % y
satisfy the following
relationships:
x = q*y + r and |r| < |y|
with x / y
truncated towards zero
("truncated division").
对于两个整数值 x
与 y
,整数除法 q = x / y
和取余 r = x % y
满足以下关系:
x = q*y + r 且 |r| < |y|
将 x / y
向零截断(“除法截断”)。
x y x / y x % y 5 3 1 2 -5 3 -1 -2 5 -3 -1 2 -5 -3 1 -2
The one exception to this rule is that if the dividend x
is
the most negative value for the int type of x
, the quotient
q = x / -1
is equal to x
(and r = 0
)
due to two's-complement integer overflow:
作为该规则的一个例外,若被除数 x
为 x
的 int 类型的最小负值,商
q = x / -1
等于 x
(且 r = 0
)。
x, q int8 -128 int16 -32768 int32 -2147483648 int64 -9223372036854775808
If the divisor is a constant, it must not be zero. If the divisor is zero at run time, a run-time panic occurs. If the dividend is non-negative and the divisor is a constant power of 2, the division may be replaced by a right shift, and computing the remainder may be replaced by a bitwise AND operation:
若被除数为常量,则它必不为零。若被除数在运行时为零, 就会出现一个运行时恐慌。若被除数为非负数,且除数为 2 的常量次幂, 则该除法可被向右移位取代,且计算其余数可被按位“与”操作取代:
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.
There is no upper limit on the shift count. Shifts behave
as if the left operand is shifted n
times by 1 for a shift
count of n
.
As a result, x << 1
is the same as x*2
and x >> 1
is the same as
x/2
but truncated towards negative infinity.
移位操作符通过右操作数指定的移位计数来移位左操作数。若左操作数为带符号整数,它们就执行算术移位;
若左操作数为无符号整数,它们则执行逻辑移位。移位计数没有上界。
若左操作数移 n
位,其行为如同移 1 位 n
次。
按照其结果,x << 1
等价于 x*2
,而 x >> 1
等价于 x/2
但向负无穷大截断。
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" for unsigned x and m = -1 for signed x
对于整数操作数,一元操作符 +
、-
和 ^
的定义如下:
+x 即为 0 + x -x 相反数 即为 0 - x ^x 按位补码 即为 m ^ x 对于无符号的 x,m = "所有位置为 1" 对于带符号的 x,m = -1
For floating-point and complex numbers,
+x
is the same as x
,
while -x
is the negation of x
.
The result of a floating-point or complex division by zero is not specified beyond the
IEEE-754 standard; whether a run-time panic
occurs is implementation-specific.
对于浮点数与复数来说,+x
等价于 x
,而 -x
则为 x
的相反数。
浮点数或复数除以零的结果仅满足 IEEE-754 标准而无额外保证;是否会出现运行时恐慌取决于具体实现。
Integer overflow
整数溢出
For unsigned integer values, the operations +
,
-
, *
, and <<
are
computed modulo 2n, where n is the bit width of
the unsigned integer's type.
Loosely speaking, these unsigned integer operations
discard high bits upon overflow, and programs may rely on "wrap around".
对于无符号整数值,操作 +
、-
、*
和 <<
均被计算为取模 2n,其中 n 为该无符号整数类型的位宽。
不严格地说,这些无符号整数操作抛弃高位向上溢出,程序可依赖这种形式的“回卷”。
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.
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.
对于带符号整数,操作 +
、-
、*
和 <<
可合法溢出,
而由此产生的值会继续存在,并由该带符号整数表现、操作、与其操作数决定性地定义。
除溢出外没有例外会导致此情况。在溢出不会发生的假定情况下编译器可能不会优化代码。
例如,我们无法假定 x < x + 1
总为真。
Floating-point operators
浮点数运算符
For floating-point and complex numbers,
+x
is the same as x
,
while -x
is the negation of x
.
The result of a floating-point or complex division by zero is not specified beyond the
IEEE-754 standard; whether a run-time panic
occurs is implementation-specific.
对于浮点数和复数,+x
与 x
相同,而 -x
为 x
的相反数。浮点数或复数被零除的结果在 IEEE-754 标准中并未指定,
是否引发 运行时恐慌 取决于具体实现。
An implementation may combine multiple floating-point operations into a single fused operation, possibly across statements, and produce a result that differs from the value obtained by executing and rounding the instructions individually. A floating-point type conversion explicitly rounds to the precision of the target type, preventing fusion that would discard that rounding.
For instance, some architectures provide a "fused multiply and add" (FMA) instruction
that computes x*y + z
without rounding the intermediate result x*y
.
These examples show when a Go implementation can use that instruction:
// FMA allowed for computing r, because x*y is not explicitly rounded: r = x*y + z r = z; r += x*y t = x*y; r = t + z *p = x*y; r = *p + z r = x*y + float64(z) // FMA disallowed for computing r, because it would omit rounding of x*y: r = float64(x*y) + z r = z; r += float64(x*y) t = float64(x*y); r = t + z
String concatenation
字符串连接
Strings can be concatenated using the +
operator
or the +=
assignment operator:
字符串可使用 +
操作符或 +=
赋值操作符:
s := "hi" + string(c) s += " and good bye"
String addition creates a new string by concatenating the operands.
字符串加法会通过连接操作数创建一个新的字符串。
Comparison operators
比较操作符
Comparison operators compare two operands and yield an untyped boolean value.
== equal != not equal < less <= less or equal > greater >= greater or equal
比较操作符比较两个操作数并产生一个无类型化的布尔值。
== 等于 != 不等于 < 小于 <= 小于等于 > 大于 >= 大于等于
In any comparison, the first operand must be assignable to the type of the second operand, or vice versa.
在任何比较中,第一个操作数必须为可赋予第二个操作数的类型,反之亦然。
The equality operators ==
and !=
apply
to operands that are comparable.
The ordering operators <
, <=
, >
, and >=
apply to operands that are ordered.
These terms and the result of the comparisons are defined as follows:
-
Boolean values are comparable.
Two boolean values are equal if they are either both
true
or bothfalse
. - Integer values are comparable and ordered, in the usual way.
- Floating-point values are comparable and ordered, as defined by the IEEE-754 standard.
-
Complex values are comparable.
Two complex values
u
andv
are equal if bothreal(u) == real(v)
andimag(u) == imag(v)
. - String values are comparable and ordered, lexically byte-wise.
-
Pointer values are comparable.
Two pointer values are equal if they point to the same variable or if both have value
nil
. Pointers to distinct zero-size variables may or may not be equal. -
Channel values are comparable.
Two channel values are equal if they were created by the same call to
make
or if both have valuenil
. -
Interface values are comparable.
Two interface values are equal if they have identical dynamic types
and equal dynamic values or if both have value
nil
. -
A value
x
of non-interface typeX
and a valuet
of interface typeT
are comparable when values of typeX
are comparable andX
implementsT
. They are equal ift
's dynamic type is identical toX
andt
's dynamic value is equal tox
. - Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
- Array values are comparable if values of the array element type are comparable. Two array values are equal if their corresponding elements are equal.
相等性操作符 ==
和 !=
适用于可比较操作数。
顺序操作符 <
、<=
、>
和 >=
适用于有序的操作数。这些比较操作的关系和值定义如下:
-
布尔值之间可比较。若两个布尔值同为
true
或同为false
,它们即为相等。 - 通常情况下,整数值之间可比较或排序。
- 根据 IEEE-754 标准的定义,浮点数值之间可比较或排序。
-
复数值之间可比较。对于两个复数值
u
与v
, 若real(u) == real(v)
且imag(u) == imag(v)
,它们即为相等。 - 根据按字节词法,字符串值之间可比较或排序。
-
指针值之间可比较。若两个指针指向相同的值或其值同为
nil
,它们即为相等。 指向明显为零大小变量的指针可能相等也可能不相等。 -
信道值可比较。若两个信道值通过相同的
make
调用创建或同为nil
值,它们即为相等。 -
接口值可比较。若两个接口值拥有相同的动态类型与相等的动态值,或同为
nil
值,它们即为相等。 -
当非接口类型
X
的值可比较且X
实现了T
时, 非接口类型X
的值x
与接口类型T
的值t
则可比较。 若t
的动态类型与X
相同且t
动态值等于x
,它们即为相等。 - 若两个结构体值的所有字段可比较,它们即可比较。若其相应的非空白字段相等,它们即为相等。
- 若两个数组元素类型的值可比较,则数组值可比较。若其相应的元素相等,它们即为相等。
A comparison of two interface values with identical dynamic types causes a run-time panic if values of that type are not comparable. This behavior applies not only to direct interface value comparisons but also when comparing arrays of interface values or structs with interface-valued fields.
两个动态类型相同的接口值进行比较,若该动态类型的值不可比较,将引发一个运行时恐慌。 此行为不仅适用于直接的接口值比较,当比较接口值的数组或接口值作为字段的结构体时也适用。
Slice, map, and function values are not comparable.
However, as a special case, a slice, map, or function value may
be compared to the predeclared identifier nil
.
Comparison of pointer, channel, and interface values to nil
is also allowed and follows from the general rules above.
切片、映射和函数值同类型之间不可比较。然而,作为一种特殊情况,切片、映射或函数值可与预声明标识符 nil
进行比较。指针、信道和接口值与 nil
之间的比较也允许并遵循上面的一般规则。
const c = 3 < 4 // c is the untyped boolean constant true type MyBool bool var x, y int var ( // The result of a comparison is an untyped boolean. // The usual assignment rules apply. b3 = x == y // b3 has type bool b4 bool = x == y // b4 has type bool b5 MyBool = x == y // b5 has type MyBool )
const c = 3 < 4 // c 为无类型化常量 true type MyBool bool var x, y int var ( // 比较的结果为无类型化布尔值。 // 通常的复制规则也适用。 b3 = x == y // b3 的类型为 bool b4 bool = x == y // b4 的类型为 bool b5 MyBool = x == y // b5 的类型为 MyBool )
Logical operators
逻辑操作符
Logical operators apply to boolean values and yield a result of the same type as the operands. The right operand is evaluated conditionally.
&& conditional AND p && q is "if p then q else false" || conditional OR p || q is "if p then true else q" ! NOT !p is "not p"
逻辑操作符适用于布尔值并根据操作数产生一个相同类型的结果。右操作数有条件地求值。
&& 条件与 p && q 即 “若 p 成立则判断 q 否则返回 false” || 条件或 p || q 即 “若 p 成立则返回 true 否则判断 q” ! 非 !p 即 “非 p”
Address operators
地址操作符
For an operand x
of type T
, the address operation
&x
generates a pointer of type *T
to x
.
The operand must be addressable,
that is, either a variable, pointer indirection, or slice indexing
operation; or a field selector of an addressable struct operand;
or an array indexing operation of an addressable array.
As an exception to the addressability requirement, x
may also be a
(possibly parenthesized)
composite literal.
If the evaluation of x
would cause a run-time panic,
then the evaluation of &x
does too.
对于类型为 T
的操作数 x
,地址操作符 &x
将生成一个类型为
*T
的指针指向 x
。操作数必须可寻址,即,变量、间接指针、切片索引操作,
或可寻址结构体操作数的字段选择器,或可寻址数组的数组索引操作均不可寻址。作为可寻址性需求的例外,
x
也可为(可能带有括号的)复合字面.
x
的求值会引发一个运行时恐慌,那么
&x
的求值也会。
For an operand x
of pointer type *T
, the pointer
indirection *x
denotes the variable of type T
pointed
to by x
.
If x
is nil
, an attempt to evaluate *x
will cause a run-time panic.
对于指针类型为 *T
的操作数 x
,间接指针 *x
表示类型为 T
的变量指向 x
。若 x
为 nil
,
尝试求值 *x
将会引发运行时恐慌。
&x &a[f(2)] &Point{2, 3} *p *pf(x) var x *int = nil *x // causes a run-time panic &*x // causes a run-time panic
&x &a[f(2)] &Point{2, 3} *p *pf(x) var x *int = nil *x // 引发运行时恐慌 &*x // 引发运行时恐慌
Receive operator
接收操作符
For an operand ch
of channel type,
the value of the receive operation <-ch
is the value received
from the channel ch
. The channel direction must permit receive operations,
and the type of the receive operation is the element type of the channel.
The expression blocks until a value is available.
Receiving from a nil
channel blocks forever.
A receive operation on a closed channel can always proceed
immediately, yielding the element type's zero value
after any previously sent values have been received.
v1 := <-ch v2 = <-ch f(<-ch) <-strobe // wait until clock pulse and discard received value
对于信道类型的操作数 ch
,接收操作符
<-ch
的值即为从信道 ch
接收的值。该信道的方向必须允许接收操作,
且该接收操作的类型即为该信道的元素类型。该值前的表达式块是有效的。
从 nil
信道接收将永远阻塞。从已关闭的信道接收能够总是立即进行,
在之前发送的任何值均被接收后,它会产生其元素类型的零值
v1 := <-ch v2 = <-ch f(<-ch) <-strobe // 在时钟脉冲和丢弃接收值之前等待
A receive expression used in an assignment or initialization of the special form
接收表达式在赋值或初始化中通过特殊形式
x, ok = <-ch x, ok := <-ch var x, ok = <-ch var x, ok T = <-ch
yields an additional untyped boolean result reporting whether the
communication succeeded. The value of ok
is true
if the value received was delivered by a successful send operation to the
channel, or false
if it is a zero value generated because the
channel is closed and empty.
产生一个附加的为类型化布尔值来报告通信是否成功。
若接收的值由一次成功向信道发送的操作发出的,则 ok
的值为 true
;
若接收的值是由于信道被关闭或为空而产生的零值,则为 false
。
Conversions
类型转换
Conversions are expressions of the form T(x)
where T
is a type and x
is an expression
that can be converted to type T
.
Conversion = Type "(" Expression [ "," ] ")" .
类型转换是形式为 T(x)
的表达式,其中 T
为类型,而
x
是可转换为类型 T
的表达式。
类型转换 = 类型 "(" 表达式 [ "," ] ")" .
If the type starts with the operator *
or <-
,
or if the type starts with the keyword func
and has no result list, it must be parenthesized when
necessary to avoid ambiguity:
*Point(p) // same as *(Point(p)) (*Point)(p) // p is converted to *Point <-chan int(c) // same as <-(chan int(c)) (<-chan int)(c) // c is converted to <-chan int func()(x) // function signature func() x (func())(x) // x is converted to func() (func() int)(x) // x is converted to func() int func() int(x) // x is converted to func() int (unambiguous)
若类型以操作符 *
、<-
或关键字 func
开始则必须加上括号:
*Point(p) // 等价于 *(Point(p)) (*Point)(p) // p 被转换为 (*Point) <-chan int(c) // 等价于 <-(chan int(c)) (<-chan int)(c) // c 被转换为 (<-chan int) func()(x) // 函数签名 func() x (func())(x) // x 被转换为 (func())
A constant value x
can be converted to
type T
if x
is representable
by a value of T
.
As a special case, an integer constant x
can be converted to a
string type using the
same rule
as for non-constant x
.
当常量值 x
可表示为一个
T
类型的值时,x
可转换为类型 T
。
作为一个特殊情况,整数常量 x
可作为非常量 x
使用
同一规则被转换为字符串类型。
Converting a constant yields a typed constant as result.
uint(iota) // iota value of type uint float32(2.718281828) // 2.718281828 of type float32 complex128(1) // 1.0 + 0.0i of type complex128 float32(0.49999999) // 0.5 of type float32 float64(-1e-1000) // 0.0 of type float64 string('x') // "x" of type string string(0x266c) // "♬" of type string MyString("foo" + "bar") // "foobar" of type MyString string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant (*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type int(1.2) // illegal: 1.2 cannot be represented as an int string(65.0) // illegal: 65.0 is not an integer constant
转换一个常量将产生一个类型化的常量作为结果。
uint(iota) // 类型为 uint 的 iota 值 float32(2.718281828) // 类型为 float32 的 2.718281828 complex128(1) // 类型为 complex128 的 1.0 + 0.0i float32(0.49999999) // 类型为 float32 的 0.5 float64(-1e-1000) // 类型为 float64 的 0.0 string('x') // 类型为 string 的 "x" string(0x266c) // 类型为 string 的 "♬" MyString("foo" + "bar") // 类型为 MyString 的 "foobar" string([]byte{'a'}) // 非常量:[]byte{'a'} 不为常量 (*int)(nil) // 非常量:nil 不为常量,*int 不为布尔、 数值或字符串类型 int(1.2) // 非法:1.2 不能表示为 int string(65.0) // 非法:65.0 不为整数常量
A non-constant value x
can be converted to type T
in any of these cases:
-
x
is assignable toT
. -
ignoring struct tags (see below),
x
's type andT
have identical underlying types. -
ignoring struct tags (see below),
x
's type andT
are pointer types that are not defined types, and their pointer base types have identical underlying types. -
x
's type andT
are both integer or floating point types. -
x
's type andT
are both complex types. -
x
is an integer or a slice of bytes or runes andT
is a string type. -
x
is a string andT
is a slice of bytes or runes.
非常量值 x
在这些情况下可转换为类型 T
:
-
当
x
可赋予T
时。 -
当
x
的类型与T
拥有相同的基本类型时。 -
当
x
的类型与T
为未命名指针类型,且它们的指针基础类型拥有相同的基本类型时。 -
当
x
的类型与T
同为整数或浮点数类型时。 -
当
x
的类型与T
同为复数类型时。 -
当
x
为整数、字节切片或符文切片且T
为字符串类型时。 -
当
x
为字符串且T
为字节切片或符文切片时。
Struct tags are ignored when comparing struct types for identity for the purpose of conversion:
在为了转换而通过比较识别结构体类型时,结构体标注 会被忽略:
type Person struct { Name string Address *struct { Street string City string } } var data *struct { Name string `json:"name"` Address *struct { Street string `json:"street"` City string `json:"city"` } `json:"address"` } var person = (*Person)(data) // ignoring tags, the underlying types are identical
Specific rules apply to (non-constant) conversions between numeric types or
to and from a string type.
These conversions may change the representation of x
and incur a run-time cost.
All other conversions only change the type but not the representation
of x
.
具体规则应用于(非常量)与数值类型之间,或在字符串类型之间转换。
这些类型转换会改变 x
的表示并引发运行时的代价。
其它转换只改变类型而不改变 x
的表示。
There is no linguistic mechanism to convert between pointers and integers.
The package unsafe
implements this functionality under
restricted circumstances.
没有语言机制能在指针和整数之间转换。包 unsafe
可在受限情况下实现此功能。
Conversions between numeric types
数值类型间的转换
For the conversion of non-constant numeric values, the following rules apply:
-
When converting between integer types, if the value is a signed integer, it is
sign extended to implicit infinite precision; otherwise it is zero extended.
It is then truncated to fit in the result type's size.
For example, if
v := uint16(0x10F0)
, thenuint32(int8(v)) == 0xFFFFFFF0
. The conversion always yields a valid value; there is no indication of overflow. - When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero).
-
When converting an integer or floating-point number to a floating-point type,
or a complex number to another complex type, the result value is rounded
to the precision specified by the destination type.
For instance, the value of a variable
x
of typefloat32
may be stored using additional precision beyond that of an IEEE-754 32-bit number, but float32(x) represents the result of roundingx
's value to 32-bit precision. Similarly,x + 0.1
may use more than 32 bits of precision, butfloat32(x + 0.1)
does not.
对于非常量数值类型的类型转换,以下规则适用:
-
当在整数类型间转换时,若该值为无符号整数,其符号将扩展为隐式无限精度,反之为零扩展。
然后截断以符合该返回类型的大小。例如,若
v := uint16(0x10F0)
,则uint32(int8(v)) == 0xFFFFFFF0
。类型转换总产生有效值,且无溢出指示。 - 当转换浮点数为整数时,小数部分将被丢弃(向零截断)。
-
当转换整数或浮点数为浮点类型,或转换复数类型为另一个复数类型时,其返回值将舍入至目标类型指定的精度。
例如,类型为
float32
的变量x
的值可能使用超出 IEEE-754 标准 32 位数的额外精度来存储,但 float32(x) 表示将x
的值舍入为 32 位精度的结果。 同样,x + 0.1
会使用超过 32 位的精度,但float32(x + 0.1)
却不会。
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
在所有涉及非常量浮点数或复数值的类型转换中,若该返回类型不能表示该转换成功的值,则该返回值取决于具体实现。
Conversions to and from a string type
字符串类型的转换
-
Converting a signed or unsigned integer value to a string type yields a
string containing the UTF-8 representation of the integer. Values outside
the range of valid Unicode code points are converted to
"\uFFFD"
.string('a') // "a" string(-1) // "\ufffd" == "\xef\xbf\xbd" string(0xf8) // "\u00f8" == "ø" == "\xc3\xb8" type MyString string MyString(0x65e5) // "\u65e5" == "日" == "\xe6\x97\xa5"
-
Converting a slice of bytes to a string type yields
a string whose successive bytes are the elements of the slice.
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø" string([]byte{}) // "" string([]byte(nil)) // "" type MyBytes []byte string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
-
Converting a slice of runes to a string type yields
a string that is the concatenation of the individual rune values
converted to strings.
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔" string([]rune{}) // "" string([]rune(nil)) // "" type MyRunes []rune string(MyRunes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
-
Converting a value of a string type to a slice of bytes type
yields a slice whose successive elements are the bytes of the string.
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []byte("") // []byte{} MyBytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
-
Converting a value of a string type to a slice of runes type
yields a slice containing the individual Unicode code points of the string.
[]rune(MyString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4} []rune("") // []rune{} MyRunes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4}
-
将有符号或无符号整数值转换为字符串类型将产生一个包含 UTF-8 表示的该整数的字符串。
有效 Unicode 码点范围之外的值将转换为
"\uFFFD"
。string('a') // "a" string(-1) // "\ufffd" == "\xef\xbf\xbd " string(0xf8) // "\u00f8" == "ø" == "\xc3\xb8" type MyString string MyString(0x65e5) // "\u65e5" == "日" == "\xe6\x97\xa5"
-
将字节切片转换为字符串类型将产生一个连续字节为该切片元素的字符串。
string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø" string([]byte{}) // "" string([]byte(nil)) // "" type MyBytes []byte string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø"
-
将符文切片转换为字符串类型将产生一个已转换为字符串的单个符文值的串联字符串。
string([]rune{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔" string([]rune{}) // "" string([]rune(nil)) // "" type MyRunes []rune string(MyRunes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔"
-
将字符串类型值转换为字节类型切片将产生一个连续元素为该字符串字节的切片。
[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []byte("") // []byte{} MyBytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
-
将字符串类型的值转换为符文类型切片将产生一个包含该字符串单个 Unicode 码点的切片。
[]rune(MyString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4} []rune("") // []rune{} MyRunes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4}
Constant expressions
常量表达式
Constant expressions may contain only constant operands and are evaluated at compile time.
常量表达式可只包含常量操作数并在编译时求值。
Untyped boolean, numeric, and string constants may be used as operands wherever it is legal to use an operand of boolean, numeric, or string type, respectively. Except for shift operations, if the operands of a binary operation are different kinds of untyped constants, the operation and, for non-boolean operations, the result use the kind that appears later in this list: integer, rune, floating-point, complex. For example, an untyped integer constant divided by an untyped complex constant yields an untyped complex constant.
无类型化布尔、数值和字符串常量可被用作操作数,无论使用布尔、数值或字符串类型的操作数是否合法。 除移位操作外,若二元操作的操作数是不同种类的无类型化常量,对于非布尔操作,该操作与其结果使用出现在此列表中较后的种类: 整数、符文、浮点数、复数。例如,由无类型化复数常量分离的无类型化整数常量将产生一个无类型化复数常量。
A constant comparison always yields an untyped boolean constant. If the left operand of a constant shift expression is an untyped constant, the result is an integer constant; otherwise it is a constant of the same type as the left operand, which must be of integer type. Applying all other operators to untyped constants results in an untyped constant of the same kind (that is, a boolean, integer, floating-point, complex, or string constant).
const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant) const b = 15 / 4 // b == 3 (untyped integer constant) const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant) const Θ float64 = 3/2 // Θ == 1.0 (type float64, 3/2 is integer division) const Π float64 = 3/2. // Π == 1.5 (type float64, 3/2. is float division) const d = 1 << 3.0 // d == 8 (untyped integer constant) const e = 1.0 << 3 // e == 8 (untyped integer constant) const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32) const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant) const h = "foo" > "bar" // h == true (untyped boolean constant) const j = true // j == true (untyped boolean constant) const k = 'w' + 1 // k == 'x' (untyped rune constant) const l = "hi" // l == "hi" (untyped string constant) const m = string(k) // m == "x" (type string) const Σ = 1 - 0.707i // (untyped complex constant) const Δ = Σ + 2.0e-4 // (untyped complex constant) const Φ = iota*1i - 1/1i // (untyped complex constant)
常量比较总是产生无类型化布尔常量。若常量移位表达式 的左操作数为无类型化常量,则该结果为整数常量;否则为与左操作数类型相同的常量,左操作数必须为整数类型。 将其它所有操作符应用于同种类(即,布尔、整数、浮点数、复数或字符串常量) 无类型化常量的结果:
const a = 2 + 3.0 // a == 5.0 (无类型化浮点数常量) const b = 15 / 4 // b == 3 (无类型化整数常量) const c = 15 / 4.0 // c == 3.75 (无类型化浮点数常量) const Θ float64 = 3/2 // Θ == 1.0 (类型为 float64,3/2 是整数除法) const Π float64 = 3/2. // Π == 1.5 (类型为 float64,3/2. 是浮点数除法) const d = 1 << 3.0 // d == 8 (无类型化整数常量) const e = 1.0 << 3 // e == 8 (无类型化整数常量) const f = int32(1) << 33 // 非法 (常量 8589934592 溢出 int32) const g = float64(2) >> 1 // 非法 (float64(2)为无类型化浮点数常量) const h = "foo" > "bar" // h == true (无类型化布尔常量) const j = true // j == true (无类型化布尔常量) const k = 'w' + 1 // k == 'x' (无类型化符文常量) const l = "hi" // l == "hi" (无类型化字符串常量) const m = string(k) // m == "x" (类型为 string) const Σ = 1 - 0.707i // (无类型化复数常量) const Δ = Σ + 2.0e-4 // (无类型化复数常量) const Φ = iota*1i - 1/1i // (无类型化复数常量)
Applying the built-in function complex
to untyped
integer, rune, or floating-point constants yields
an untyped complex constant.
const ic = complex(0, c) // ic == 3.75i (untyped complex constant) const iΘ = complex(0, Θ) // iΘ == 1i (type complex128)
将内建函数 complex
应用于无类型化整数、符文或浮点数常量将产生一个无类型化复数常量。
const ic = complex(0, c) // ic == 3.75i (无类型化复数常量) const iΘ = complex(0, Θ) // iΘ == 1i (类型为 complex128)
Constant expressions are always evaluated exactly; intermediate values and the constants themselves may require precision significantly larger than supported by any predeclared type in the language. The following are legal declarations:
常量表达式总是精确地求值;中间值与该常量本身可能需要明显大于该语言中任何预声明类型所支持的精度。以下为合法声明:
const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant) const Four int8 = Huge >> 98 // Four == 4 (type int8)
The divisor of a constant division or remainder operation must not be zero:
3.14 / 0.0 // illegal: division by zero
常量除法或求余的除数必不能为零:
3.14 / 0.0 // 非法:除以零
The values of typed constants must always be accurately representable by values of the constant type. The following constant expressions are illegal:
uint(-1) // -1 cannot be represented as a uint int(3.14) // 3.14 cannot be represented as an int int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64 Four * 300 // operand 300 cannot be represented as an int8 (type of Four) Four * 100 // product 400 cannot be represented as an int8 (type of Four)
带类型常量的值必须总是可被精确地表示为该常量类型的值。 以下为非法常量表达式:
uint(-1) // -1 无法表示为 uint int(3.14) // 3.14 无法表示为 int int64(Huge) // 1267650600228229401496703205376 无法表示为 int64 Four * 300 // 操作数 300 无法表示为 int8(Four 的类型) Four * 100 // 其结果 400 无法表示为 int8(Four 的类型)
The mask used by the unary bitwise complement operator ^
matches
the rule for non-constants: the mask is all 1s for unsigned constants
and -1 for signed and untyped constants.
^1 // untyped integer constant, equal to -2 uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8 ^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE) int8(^1) // same as int8(-2) ^int8(1) // same as -1 ^ int8(1) = -2
用于一元按位补码操作符 ^
的屏蔽与非常量相匹配的规则:对于无符号常量屏蔽全为 1,
而对于带符号或无类型化常量为 -1。
^1 // 无类型化整数常量,等于 -2 uint8(^1) // 非法,等价于 uint8(-2),-2 无法表示为 uint8 ^uint8(1) // 类型化 uint8 常量,等价于 0xFF ^ uint8(1) = uint8(0xFE) int8(^1) // 等价于 int8(-2) ^int8(1) // 等价于 -1 ^ int8(1) = -2
Implementation restriction: A compiler may use rounding while computing untyped floating-point or complex constant expressions; see the implementation restriction in the section on constants. This rounding may cause a floating-point constant expression to be invalid in an integer context, even if it would be integral when calculated using infinite precision, and vice versa.
实现限制:在计算无类型化浮点数或复数常量表达式时,编译器可能使用舍入,参考章节常量 的实现限制。次舍入可能会导致浮点常量表达式在整数上下文中无效,即使在它使用无限精度计算时会成为整体,反之亦然。
Order of evaluation
求值顺序
At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
在包级别内,初始化依赖确定了 变量声明 内独立初始化与局的求值顺序。 否则,当对一个表达式、赋值或返回语句的 操作数 进行求值时, 所有函数调用、方法调用以及通信操作均按从左到右的词法顺序求值。
For example, in the (function-local) assignment
例如,在(函数局部)赋值
y[f()], ok = g(h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order
f()
, h()
, i()
, j()
,
<-c
, g()
, and k()
.
However, the order of those events compared to the evaluation
and indexing of x
and the evaluation
of y
is not specified.
a := 1 f := func() int { a++; return a } x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
中,函数调用与通信按顺序 f()
、h()
、i()
、j()
、
<-c
、g()
和 k()
发生。然而,相较于这些事件的顺序,x
的求值与索引及 y
的求值并未指定。
a := 1 f := func() int { a++; return a } x := []int{a, f()} // x 可能为 [1, 2] 或 [2, 2]:a 与 f() 之间的求值顺序并未指定 m := map[int]int{a: 1, a: 2} // m 可能为 {2: 1} 或 {2: 2}:两个映射赋值之间的求值顺序并未指定 n := map[int]int{a: f()} // n 可能为 {2: 3} 或 {3: 3}:键和值之间的求值顺序并未指定
At package level, initialization dependencies override the left-to-right rule for individual initialization expressions, but not for operands within each expression:
在包级别内,初始化依赖覆盖了独立初始化从左到右的规则,但不会影响到每个表达式中的操作数:
var a, b, c = f() + v(), g(), sqr(u()) + v() func f() int { return c } func g() int { return a } func sqr(x int) int { return x*x } // functions u and v are independent of all other variables and functions
var a, b, c = f() + v(), g(), sqr(u()) + v() func f() int { return c } func g() int { return a } func sqr(x int) int { return x*x } // 函数 u 和 v 独立于其它所有变量和函数
The function calls happen in the order
u()
, sqr()
, v()
,
f()
, v()
, and g()
.
函数调用按 u()
、sqr()
、v()
、
f()
、v()
、g()
的顺序发生。
Floating-point operations within a single expression are evaluated according to
the associativity of the operators. Explicit parentheses affect the evaluation
by overriding the default associativity.
In the expression x + (y + z)
the addition y + z
is performed before adding x
.
单表达式中的浮点数操作根据该操作符的结合性求值。显式的圆括号通过覆盖默认结合性来影响求值。
在表达式 x + (y + z)
中,加法 y + z
会在与 x
相加前执行。
Statements
语句
Statements control execution.
Statement = Declaration | LabeledStmt | SimpleStmt | GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | DeferStmt . SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
语句控制执行。
语句 = 声明 | 标签语句 | 简单语句 | Go语句 | Return语句 | Break语句 | Continue语句 | Goto语句 | Fallthrough语句 | 块 | If语句 | Switch语句 | Select语句 | For语句 | Defer语句 . 简单语句 = 空语句 | 表达式语句 | 发送语句 | 递增递减语句 | 赋值 | 短变量声明 .
Terminating statements
终止语句
A terminating statement prevents execution of all statements that lexically appear after it in the same block. The following statements are terminating:
-
A "return" or
"goto" statement.
-
A call to the built-in function
panic
. -
A block in which the statement list ends in a terminating statement.
-
An "if" statement in which:
- the "else" branch is present, and
- both branches are terminating statements.
-
A "for" statement in which:
- there are no "break" statements referring to the "for" statement, and
- the loop condition is absent.
-
A "switch" statement in which:
- there are no "break" statements referring to the "switch" statement,
- there is a default case, and
- the statement lists in each case, including the default, end in a terminating statement, or a possibly labeled "fallthrough" statement.
-
A "select" statement in which:
- there are no "break" statements referring to the "select" statement, and
- the statement lists in each case, including the default if present, end in a terminating statement.
- A labeled statement labeling a terminating statement.
All other statements are not terminating.
终止语句为以下之一:
-
一个"return" 或
"goto" 语句。
-
一个内建函数
panic
的调用。 -
一个语句列表以终止语句结束的块。
-
一个 "if" 语句,其中:
- 存在 "else" 分支,且
- 两个分支均以终止语句结束。
-
一个 "for" 语句,其中:
- 没有 "break" 语句引用到该 "for" 语句,且
- 缺少循环条件。
-
一个 "switch" 语句,其中:
- 没有 "break" 语句引用到该 "switch" 语句,
- 没有默认分支,且
- 包括默认分支,每一个分支中的语句列表均以终止语句结束,或一个可能带标签的 "fallthrough" 语句。
-
一个 "select" 语句,其中:
- 没有 "break" 语句引用到该 "select" 语句,且
- 包括默认分支(如果有的话),每一个分支中的语句列表均以终止语句结束。
- 一个标在终止语句上的标签语句。
其它所有语句均非终止语句。
A statement list ends in a terminating statement if the list is not empty and its final non-empty statement is terminating.
若语句列表非空且其最后一个非空语句为终止语句,那么它以终止语句结束。
Empty statements
空语句
The empty statement does nothing.
EmptyStmt = .
空语句不执行任何操作。
空语句 = .
Labeled statements
标签语句
A labeled statement may be the target of a goto
,
break
or continue
statement.
LabeledStmt = Label ":" Statement . Label = identifier .
标签语句可作为 goto
、break
或 continue
语句的目标
标签语句 = 标签 ":" 语句 . 标签 = 标识符 .
Error: log.Panic("error encountered")
Expression statements
表达式语句
With the exception of specific built-in functions, function and method calls and receive operations can appear in statement context. Such statements may be parenthesized.
ExpressionStmt = Expression .
除特殊的内建函数外,函数与方法的调用及 接收操作均可出现在语句上下文中。这样的语句可能需要加小括号。
表达式语句 = 表达式 .
The following built-in functions are not permitted in statement context:
以下内建函数不允许出现在语句上下文中:
append cap complex imag len make new real unsafe.Alignof unsafe.Offsetof unsafe.Sizeof
h(x+y) f.Close() <-ch (<-ch) len("foo") // illegal if len is the built-in function
h(x+y) f.Close() <-ch (<-ch) len("foo") // 若 len 为内建函数即为非法
Send statements
发送语句
A send statement sends a value on a channel. The channel expression must be of channel type, the channel direction must permit send operations, and the type of the value to be sent must be assignable to the channel's element type.
SendStmt = Channel "<-" Expression . Channel = Expression .
发送语句在信道上发送值。信道表达式必须为信道类型, 信道的方向必须允许发送操作,且被发送的值的类型必须可赋予该信道的元素类型。
发送语句 = 信道 "<-" 表达式 . 信道 = 表达式 .
Both the channel and the value expression are evaluated before communication
begins. Communication blocks until the send can proceed.
A send on an unbuffered channel can proceed if a receiver is ready.
A send on a buffered channel can proceed if there is room in the buffer.
A send on a closed channel proceeds by causing a run-time panic.
A send on a nil
channel blocks forever.
信道与值表达式均在通信开始前求值。通信会阻塞,直到发送可继续进行。
若接收者已就绪,在无缓存信道上发送可继续进行。
若缓存中有空间,在有缓存信道上发送可继续进行。
在已关闭信道上进行发送会引发一个运行时恐慌。
在 nil
信道上进行发送将永远阻塞。
ch <- 3 // send value 3 to channel ch
ch <- 3 // 发送值 3 至信道 ch
IncDec statements
递增递减语句
The "++" and "--" statements increment or decrement their operands
by the untyped constant 1
.
As with an assignment, the operand must be addressable
or a map index expression.
IncDecStmt = Expression ( "++" | "--" ) .
"++" 与 "--" 语句会以无类型化常量 1
来递增或递减它们的操作数。
就赋值来说,操作数必须为可寻址的,或为映射的下标表达式。
递增递减语句 = 表达式 ( "++" | "--" ) .
The following assignment statements are semantically equivalent:
IncDec statement Assignment x++ x += 1 x-- x -= 1
以下赋值语句在语义上等价:
递增递减语句 赋值 x++ x += 1 x-- x -= 1
Assignments
赋值
Assignment = ExpressionList assign_op ExpressionList . assign_op = [ add_op | mul_op ] "=" .
赋值 = 表达式列表 赋值操作符 表达式列表 . 赋值操作符 = [ 加法操作符 | 乘法操作符 ] "=" .
Each left-hand side operand must be addressable,
a map index expression, or (for =
assignments only) the
blank identifier.
Operands may be parenthesized.
x = 1 *p = f() a[i] = 23 (k) = <-ch // same as: k = <-ch
每个左操作数必须为可寻址的、映射下标表达式或(仅对于 =
赋值)空白标识符。操作数可加小括号。
x = 1 *p = f() a[i] = 23 (k) = <-ch // 等价于:k = <-ch
An assignment operation x
op=
y
where op is a binary arithmetic operator
is equivalent to x
=
x
op
(y)
but evaluates x
only once. The op=
construct is a single token.
In assignment operations, both the left- and right-hand expression lists
must contain exactly one single-valued expression, and the left-hand
expression must not be the blank identifier.
赋值操作 x
op=
y
,其中 op 为一个二元算术操作符,它等价于
x
=
x
op (y)
,但只对 x
求值一次。
op=
为单个标记。在赋值操作中,左、右表达式列表必须均刚好包含一个单值表达式,
且左表达式必须不为空白标识符。
a[i] <<= 2 i &^= 1<<n
A tuple assignment assigns the individual elements of a multi-valued
operation to a list of variables. There are two forms. In the
first, the right hand operand is a single multi-valued expression
such as a function call, a channel or
map operation, or a type assertion.
The number of operands on the left
hand side must match the number of values. For instance, if
f
is a function returning two values,
x, y = f()
assigns the first value to x
and the second to y
.
In the second form, the number of operands on the left must equal the number
of expressions on the right, each of which must be single-valued, and the
nth expression on the right is assigned to the nth
operand on the left:
one, two, three = '一', '二', '三'
元组赋值将多值操作的个体元素赋予变量列表。它有两种形式。首先,右操作数为单个多值表达式,比如一个函数调用、
信道、映射操作或一个类型断言。
左操作数的数量必须与值的数量相匹配。例如,若 f
为返回两个值的函数,则
x, y = f()
会将第一个值赋予 x
,而第二个值则会赋予 y
。
在第二种形式中,左侧操作数的数量必须等于右侧表达式的数量,其中每一个必须为单值,且右侧第
n 个表达式赋予左侧第 n 个操作数:
one, two, three = '一', '二', '三'
The blank identifier provides a way to ignore right-hand side values in an assignment:
_ = x // evaluate x but ignore it x, _ = f() // evaluate f() but ignore second result value
空白标识符 提供了一种在赋值中忽略右侧值的方法:
_ = x // 求值 x 但忽略它 x, _ = f() // 求值 f() 但忽略第二个结果值
The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.
a, b = b, a // exchange a and b x := []int{1, 2, 3} i := 0 i, x[i] = 1, 2 // set i = 1, x[0] = 2 i = 0 x[i], i = 2, 1 // set x[0] = 2, i = 1 x[0], x[0] = 1, 2 // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end) x[1], x[3] = 4, 5 // set x[1] = 4, then panic setting x[3] = 5. type Point struct { x, y int } var p *Point x[2], p.x = 6, 7 // set x[2] = 6, then panic setting p.x = 7 i = 2 x = []int{3, 5, 7} for i, x[i] = range x { // set i, x[2] = 0, x[0] break } // after this loop, i == 0 and x == []int{3, 5, 3}
赋值过程分为两个阶段。 首先,左边的下标表达式与指针间接寻址的操作数 (包括选择器中隐式的指针间接寻址)和右边的表达式都会按通常顺序求值。 其次,赋值会按照从左到右的顺序进行。
a, b = b, a // 交换 a 和 b x := []int{1, 2, 3} i := 0 i, x[i] = 1, 2 // 置 i = 1,x[0] = 2 i = 0 x[i], i = 2, 1 // 置 x[0] = 2,i = 1 x[0], x[0] = 1, 2 // 置 x[0] = 1,然后置 x[0] = 2(因此最后 x[0] == 2) x[1], x[3] = 4, 5 // 置 x[1] = 4,然后恐慌置 x[3] = 5 type Point struct { x, y int } var p *Point x[2], p.x = 6, 7 // 置 x[2] = 6,然后恐慌置 p.x = 7 i = 2 x = []int{3, 5, 7} for i, x[i] = range x { // 置 i, x[2] = 0, x[0] break } // 该循环结束之后,i == 0 且 x == []int{3, 5, 3}
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
- Any typed value may be assigned to the blank identifier.
- If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
-
If an untyped boolean value is assigned to a variable of interface type or
the blank identifier, it is first converted to type
bool
.
在赋值中,每个值必须可赋予被赋值操作数的类型,以下为特殊情况:
- 任何类型化值均可赋予空白标识符。
- 若一个无类型化常量被赋予一个接口类型的变量或空白标识符,该常量首先会 转换为其默认类型。
- 若无类型化布尔值被赋予一个接口类型的变量或空白标识符,它首先会转换为布尔类型。
If statements
If语句
"If" statements specify the conditional execution of two branches according to the value of a boolean expression. If the expression evaluates to true, the "if" branch is executed, otherwise, if present, the "else" branch is executed.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
"If"语句根据一个布尔表达式的值指定两个分支的条件来执行。 若该表达式求值为 true,则执行"if"分支,否则执行"else"分支。
If语句 = "if" [ 简单语句 ";" ] 表达式 块 [ "else" ( If语句 | 块 ) ] .
if x > max { x = max }
The expression may be preceded by a simple statement, which executes before the expression is evaluated.
简单语句可能先于表达式,它将在表达式求值前执行。
if x := f(); x < y { return x } else if x > z { return z } else { return y }
Switch statements
Switch语句
"Switch" statements provide multi-way execution. An expression or type specifier is compared to the "cases" inside the "switch" to determine which branch to execute.
SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
"Switch"语句提供多路执行。表达式或类型说明符与"switch"中的"cases"相比较从而决定执行哪一分支。
Switch语句 = 表达式选择语句 | 类型选择语句 .
There are two forms: expression switches and type switches. In an expression switch, the cases contain expressions that are compared against the value of the switch expression. In a type switch, the cases contain types that are compared against the type of a specially annotated switch expression. The switch expression is evaluated exactly once in a switch statement.
它有两种形式:表达式选择与类型选择。在表达式选择中,case 包含的表达式针对 switch 表达式的值进行比较, 在类型选择中,case 包含的类型针对特别注明的 switch 表达式的类型进行比较。 switch 表达式在 switch 语句中刚好求值一次。
Expression switches
表达式选择
In an expression switch,
the switch expression is evaluated and
the case expressions, which need not be constants,
are evaluated left-to-right and top-to-bottom; the first one that equals the
switch expression
triggers execution of the statements of the associated case;
the other cases are skipped.
If no case matches and there is a "default" case,
its statements are executed.
There can be at most one default case and it may appear anywhere in the
"switch" statement.
A missing switch expression is equivalent to the boolean value
true
.
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" . ExprCaseClause = ExprSwitchCase ":" StatementList . ExprSwitchCase = "case" ExpressionList | "default" .
在表达式选择中,switch 表达式会被求值,而 case 表达式无需为常量,它按从上到下,从左到右的顺序求值;
第一个等于 switch 表达式的 case 表达式将引发相应情况的语句的执行;其它的情况将被跳过。
若没有情况匹配且有"default"情况,则该语句将被执行。
最多只能有一个默认情况且它可以出现在"switch"语句的任何地方。
缺失的 switch 表达式等价于布尔值 true
。
表达时选择语句 = "switch" [ 简单语句 ";" ] [ 表达式 ] "{" { 表达式情况子句 } "}" . 表达式情况子句 = 表达式选择情况 ":" 语句列表 . 表达式选择情况 = "case" 表达式列表 | "default" .
If the switch expression evaluates to an untyped constant, it is first
converted to its default type;
if it is an untyped boolean value, it is first converted to type bool
.
The predeclared untyped value nil
cannot be used as a switch expression.
若 switch 求值出一个无类型化的常量,它首先会转换为其默认类型;
若它是无类型化的布尔值,它首先会转换为 bool
类型。
预声明的无类型化值 nil
无法用作 switch 表达式。
If a case expression is untyped, it is first converted
to the type of the switch expression.
For each (possibly converted) case expression x
and the value t
of the switch expression, x == t
must be a valid comparison.
若 case 表达式为无类型化的,它首先会转换为 switch 表达式的类型。
对于每个(可能已转换的)case 表达式 x
与 switch 表达式的值 t
,
x == t
必须为有效的 比较。
In other words, the switch expression is treated as if it were used to declare and
initialize a temporary variable t
without explicit type; it is that
value of t
against which each case expression x
is tested
for equality.
换句话说,switch 表达式可视作用它来声明并初始化变量 t
而不显示指定类型,
并用 t
的值对每一个 case 表达式 x
测试是否相等。
In a case or default clause, the last non-empty statement may be a (possibly labeled) "fallthrough" statement to indicate that control should flow from the end of this clause to the first statement of the next clause. Otherwise control flows to the end of the "switch" statement. A "fallthrough" statement may appear as the last statement of all but the last clause of an expression switch.
在 case 或 default 子句中,最后一个非空语句可能为(可能带标签的) "fallthrough" 语句 它表明该控制流应从该子句的结尾转至下一个子句的第一个语句。 否则,控制流转至该"switch"语句的结尾。 "fallthrough" 语句可出现在 switch 表达式中除最后一个子句外所有子句的末尾。
The switch expression may be preceded by a simple statement, which executes before the expression is evaluated.
switch tag { default: s3() case 0, 1, 2, 3: s1() case 4, 5, 6, 7: s2() } switch x := f(); { // missing switch expression means "true" case x < 0: return -x default: return x } switch { case x < y: f1() case x < z: f2() case x == 4: f3() }
简单语句可能先于 switch 表达式,它将在表达式求值前执行。
switch tag { default: s3() case 0, 1, 2, 3: s1() case 4, 5, 6, 7: s2() } switch x := f(); { // 缺失的 switch 表达式意为"true" case x < 0: return -x default: return x } switch { case x < y: f1() case x < z: f2() case x == 4: f3() }
Implementation restriction: A compiler may disallow multiple case expressions evaluating to the same constant. For instance, the current compilers disallow duplicate integer, floating point, or string constants in case expressions.
实现限制:编译器可能不允许多个 case 表达式求值为同一个常量。 例如,当前的编译器不允许 case 表达式出现重复的整数、浮点数或字符串常量。
Type switches
类型选择
A type switch compares types rather than values. It is otherwise similar
to an expression switch. It is marked by a special switch expression that
has the form of a type assertion
using the reserved word type
rather than an actual type:
switch x.(type) { // cases }
Cases then match actual types T
against the dynamic type of the
expression x
. As with type assertions, x
must be of
interface type, and each non-interface type
T
listed in a case must implement the type of x
.
TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . TypeCaseClause = TypeSwitchCase ":" StatementList . TypeSwitchCase = "case" TypeList | "default" . TypeList = Type { "," Type } .
类型选择比较类型而非值。它与表达式选择并不相似。它被一个特殊的 switch 表达式标记,
该表达式为使用保留字 type
而非实际类型的类型断言的形式:
switch x.(type) { // cases }
此时的 case 针对表达式 x
的动态类型匹配实际的类型 T
。
就像类型断言一样,x
必须为接口类型,
而每一个在 case 中列出的非接口类型 T
必须实现了 x
的类型。
类型选择语句 = "switch" [ 简单语句 ";" ] 类型选择监视 "{" { 类型情况子句 } "}" . 类型选择监视 = [ 标识符 ":=" ] 主表达式 "." "(" "type" ")" . 类型情况子句 = 类型选择情况 ":" 语句列表 . 类型选择情况 = "case" 类型列表 | "default" . 类型列表 = 类型 { "," 类型 } .
The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the end of the TypeSwitchCase in the implicit block of each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.
类型选择监视可包含一个短变量声明。 当使用此形式时,变量会在每个子句的隐式块中类型选择情况的末尾处声明。 在 case 列表刚好只有一个类型的子句中,该变量即拥有此类型;否则,该变量拥有在类型选择监视中表达式的类型。
Instead of a type, a case may use the predeclared identifier
nil
;
that case is selected when the expression in the TypeSwitchGuard
is a nil
interface value.
There may be at most one nil
case.
除类型外,case 也可为 nil
,
这种情况在类型选择监视中的表达式为 nil
接口值时使用。
此处最多有一种 nil
的情况。
Given an expression x
of type interface{}
,
the following type switch:
switch i := x.(type) { case nil: printString("x is nil") // type of i is type of x (interface{}) case int: printInt(i) // type of i is int case float64: printFloat64(i) // type of i is float64 case func(int) float64: printFunction(i) // type of i is func(int) float64 case bool, string: printString("type is bool or string") // type of i is type of x (interface{}) default: printString("don't know the type") // type of i is type of x (interface{}) }
could be rewritten:
v := x // x is evaluated exactly once if v == nil { i := v // type of i is type of x (interface{}) printString("x is nil") } else if i, isInt := v.(int); isInt { printInt(i) // type of i is int } else if i, isFloat64 := v.(float64); isFloat64 { printFloat64(i) // type of i is float64 } else if i, isFunc := v.(func(int) float64); isFunc { printFunction(i) // type of i is func(int) float64 } else { _, isBool := v.(bool) _, isString := v.(string) if isBool || isString { i := v // type of i is type of x (interface{}) printString("type is bool or string") } else { i := v // type of i is type of x (interface{}) printString("don't know the type") } }
给定类型为 interface{}
的表达式 x
,以下类型选择:
switch i := x.(type) { case nil: printString("x is nil") // i 的类型为 x 的类型(interface{}) case int: printInt(i) // i 的类型为 int case float64: printFloat64(i) // i 的类型为 float64 case func(int) float64: printFunction(i) // i 的类型为 func(int) float64 case bool, string: printString("type is bool or string") // i 的类型为 x 的类型(interface{}) default: printString("don't know the type") // i 的类型为 x 的类型(interface{}) }
可被重写为:
v := x // x 只被求值一次 if v == nil { i := v // i 的类型为 x 的类型(interface{}) printString("x is nil") } else if i, isInt := v.(int); isInt { printInt(i) // i 的类型为 int } else if i, isFloat64 := v.(float64); isFloat64 { printFloat64(i) // i 的类型为 float64 } else if i, isFunc := v.(func(int) float64); isFunc { printFunction(i) // i 的类型为 func(int) float64 } else { _, isBool := v.(bool) _, isString := v.(string) if isBool || isString { i := v // i 的类型为 x 的类型(interface{}) printString("type is bool or string") } else { i := v // i 的类型为 x 的类型(interface{}) printString("don't know the type") } }
The type switch guard may be preceded by a simple statement, which executes before the guard is evaluated.
简单语句可能先于类型选择监视,它将在类型选择监视求值前执行。
The "fallthrough" statement is not permitted in a type switch.
"fallthrough"语句在类型选择中不被允许。
For statements
For语句
A "for" statement specifies repeated execution of a block. There are three forms: The iteration may be controlled by a single condition, a "for" clause, or a "range" clause.
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . Condition = Expression .
"for"语句指定块的重复执行。它有三种形式:迭代通过条件、"for"子句或"range"子句控制。
For语句 = "for" [ 条件 | For子句 | Range子句 ] 块 . 条件 = 表达式 .
For statements with single condition
单条件 for 语句
In its simplest form, a "for" statement specifies the repeated execution of
a block as long as a boolean condition evaluates to true.
The condition is evaluated before each iteration.
If the condition is absent, it is equivalent to the boolean value
true
.
在最简单的形式中,只要布尔条件求值为真,"for"语句指定的块就重复执行。
条件会在每次迭代前求值。若缺少条件,则它等价于布尔值 true
。
for a < b { a *= 2 }
For statements with for
clause
带 for
从句的 for 语句
A "for" statement with a ForClause is also controlled by its condition, but additionally it may specify an init and a post statement, such as an assignment, an increment or decrement statement. The init statement may be a short variable declaration, but the post statement must not. Variables declared by the init statement are re-used in each iteration.
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . InitStmt = SimpleStmt . PostStmt = SimpleStmt .
带 For 子句的"for"语句也通过其条件控制,此外,它也可指定一个初始化或步进语句, 例如一个赋值、一个递增或递减语句。初始化语句可为一个短变量声明, 而步进语句则不能。由 init 语句声明的变量会在每次迭代中重用。
For子句 = [ 初始化语句 ] ";" [ 条件 ] ";" [ 步进语句 ] . 初始化语句 = 简单语句 . 步进语句 = 简单语句 .
for i := 0; i < 10; i++ { f(i) }
If non-empty, the init statement is executed once before evaluating the
condition for the first iteration;
the post statement is executed after each execution of the block (and
only if the block was executed).
Any element of the ForClause may be empty but the
semicolons are
required unless there is only a condition.
If the condition is absent, it is equivalent to the boolean value
true
.
for cond { S() } is the same as for ; cond ; { S() } for { S() } is the same as for true { S() }
For statements with range
clause
若初始化语句非空,则只在第一次迭代的条件求值前执行一次。
步进语句会在块的每一次执行(且仅当块被执行)后执行。
任何 For 子句的元素都可为空,但除非只有一个条件,否则分号是必须的。
若缺少条件,则它等价于布尔值 true
。
for cond { S() } 等价于 for ; cond ; { S() } for { S() } 等价于 for true { S() }
A "for" statement with a "range" clause iterates through all entries of an array, slice, string or map, or values received on a channel. For each entry it assigns iteration values to corresponding iteration variables if present and then executes the block.
RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
带"range"子句的"for"语句通过遍历数组、切片、字符串或映射的所有项,以及从信道上接收的值来迭代。 对于每一项,它将迭代值(若存在)赋予其相应的迭代变量,然后执行该块。
Range子句 = [ 表达式列表 "=" | 标识符列表 ":=" ] "range" 表达式 .
The expression on the right in the "range" clause is called the range expression, which may be an array, pointer to an array, slice, string, map, or channel permitting receive operations. As with an assignment, if present the operands on the left must be addressable or map index expressions; they denote the iteration variables. If the range expression is a channel, at most one iteration variable is permitted, otherwise there may be up to two. If the last iteration variable is the blank identifier, the range clause is equivalent to the same clause without that identifier.
"range"子句右边的表达式称为range 表达式,它可以是一个允许接受操作 的数组、数组指针、切片、字符串、映射或信道。就赋值来说,若存在左边的操作数,则它必须为 可寻址的或映射下标表达式;它们表示迭代变量。若 range 表达式为信道, 则最多只允有一个迭代变量,否则可多于两个。若最后一个迭代变量为 空白标识符,则 range 子句等价于无该标识符的相同子句。
The range expression x
is evaluated once before beginning the loop,
with one exception: if at most one iteration variable is present and
len(x)
is constant,
the range expression is not evaluated.
Function calls on the left are evaluated once per iteration. For each iteration, iteration values are produced as follows if the respective iteration variables are present:
Range expression 1st value 2nd value array or slice a [n]E, *[n]E, or []E index i int a[i] E string s string type index i int see below rune map m map[K]V key k K m[k] V channel c chan E, <-chan E element e E
-
For an array, pointer to array, or slice value
a
, the index iteration values are produced in increasing order, starting at element index 0. If at most one iteration variable is present, the range loop produces iteration values from 0 up tolen(a)-1
and does not index into the array or slice itself. For anil
slice, the number of iterations is 0. -
For a string value, the "range" clause iterates over the Unicode code points
in the string starting at byte index 0. On successive iterations, the index value will be the
index of the first byte of successive UTF-8-encoded code points in the string,
and the second value, of type
rune
, will be the value of the corresponding code point. If the iteration encounters an invalid UTF-8 sequence, the second value will be0xFFFD
, the Unicode replacement character, and the next iteration will advance a single byte in the string. -
The iteration order over maps is not specified
and is not guaranteed to be the same from one iteration to the next.
If a map entry that has not yet been reached is removed during iteration,
the corresponding iteration value will not be produced. If a map entry is
created during iteration, that entry may be produced during the iteration or
may be skipped. The choice may vary for each entry created and from one
iteration to the next.
If the map is
nil
, the number of iterations is 0. -
For channels, the iteration values produced are the successive values sent on
the channel until the channel is closed. If the channel
is
nil
, the range expression blocks forever.
range 表达式在循环前会求值一次,除了一种情况:若 range 表达式为数组或数组指针, 且最多存在一个迭代变量,此时只有 range 表达式的长度会被求值;若该长度为常量, 那么根据定义,range 表达式本身不会被求值。
左边的函数调用会在每次迭代时求值一次。对于每一次迭代,若各自的迭代变量存在,那么迭代值按照以下方式产生:
Range 表达式 第一个值 第二个值 数组或切片 a [n]E、*[n]E 或 []E 下标 i int a[i] E 字符串 s string type 下标 i int 见下 rune 映射 m map[K]V 键 k K m[k] V 信道 c chan E, <-chan E 元素 e E
-
对于数组、数组指针或切片值
a
,下标迭代值按照递增顺序产生,从元素下标 0 开始。 作为一种特殊情况,若最多有一个迭代变量,则 range 循环提供从 0 到len(a)-1
的迭代变量而非索引该数组或切片自身。对于nil
切片,迭代次数为 0。 -
对于字符串值,"range"子句从字节下标 0 开始,遍历该字符串中的 Unicode 码点。在连续迭代中,
其下标值为该字符串中连续 UTF-8 编码码点第一个字节的下标。而类型为
rune
的第二个值为则其相应码点的值。若该迭代遇到无效的 UTF-8 序列,则第二个值将为 Unicode 占位字符0xFFD
,且下一次迭代将推进至此字符串中的单个字节。 -
映射的遍历顺序并不确定且从某一次迭代到下一次并不保证相同。若在迭代过程中移除的映射项尚未受到影响,
则相应的迭代值不会产生。若在迭代过程中创建映射项,则该项可能会在迭代中产生或被跳过。
这种选择可能会改变已经创建的每一个项,并从一次迭代进入到下一次迭代中。
若该映射为
nil
,则迭代的次数为 0. -
对于信道,其迭代值产生为在该信道上发送的连续值,直到该信道被关闭。若该信道为
nil
,则 range 表达式将永远阻塞。
The iteration values are assigned to the respective iteration variables as in an assignment statement.
迭代值在赋值语句中将分别赋予其各自的迭代变量。
The iteration variables may be declared by the "range" clause using a form of
short variable declaration
(:=
).
In this case their types are set to the types of the respective iteration values
and their scope is the block of the "for"
statement; they are re-used in each iteration.
If the iteration variables are declared outside the "for" statement,
after execution their values will be those of the last iteration.
var testdata *struct { a *[7]int } for i, _ := range testdata.a { // testdata.a is never evaluated; len(testdata.a) is constant // i ranges from 0 to 6 f(i) } var a [10]string 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 {} // element type of m is assignable to val m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6} for key, val = range m { h(key, val) } // key == last map key encountered in iteration // val == map[key] var ch chan Work = producer() for w := range ch { doWork(w) } // empty a channel for range ch {}
迭代变量可通过"range"子句使用短变量声明形式(:=
)来声明。
在这种情况下,它们的类型将置为其各自的迭代值,且它们的作用域
在"for"语句块内,它们将在每次迭代时被重用。若迭代变量在"for"语句之外声明,则在每次执行后,
它们的值为最后一次迭代的值。
var testdata *struct { a *[7]int } for i, _ := range testdata.a { // testdata.a 永不会被求值,len(testdata.a)为常量 // i 从 0 延伸到 6 f(i) } var a [10]string for i, s := range a { // i 的类型为 int // s 的类型为 string // s == a[i] g(i, s) } var key string var val interface {} // m 值的类型可赋予 val m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6} for key, val = range m { h(key, val) } // key == 在迭代中遇到的最后一个映射键 // val == map[key] var ch chan Work = producer() for w := range ch { doWork(w) } // 清空一个信道 for range ch {}
Go statements
Go 语句
A "go" statement starts the execution of a function call as an independent concurrent thread of control, or goroutine, within the same address space.
GoStmt = "go" Expression .
"go"语句将函数调用的执行作为控制独立的并发线程或相同地址空间中的Go程来启动。
Go语句 = "go" 表达式 .
The expression must be a function or method call; it cannot be parenthesized. Calls of built-in functions are restricted as for expression statements.
表达式必须为一个函数或方法调用,它不能被括号括住。内建函数调用被限制为表达式语句。
The function value and parameters are evaluated as usual in the calling goroutine, but unlike with a regular call, program execution does not wait for the invoked function to complete. Instead, the function begins executing independently in a new goroutine. When the function terminates, its goroutine also terminates. If the function has any return values, they are discarded when the function completes.
在调用 Go 程中,函数值与形参按照惯例求值, 但不像一般的调用,程序的执行并不等待已被调用的函数完成。取而代之,该函数在一个新的 Go 程中独立执行。 当该函数终止后,其 Go 程也将终止。若该函数拥有任何返回值,它们将在该函数完成后被丢弃。
go Server() go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
Select statements
Select语句
A "select" statement chooses which of a set of possible send or receive operations will proceed. It looks similar to a "switch" statement but with the cases all referring to communication operations.
SelectStmt = "select" "{" { CommClause } "}" . CommClause = CommCase ":" StatementList . CommCase = "case" ( SendStmt | RecvStmt ) | "default" . RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr . RecvExpr = Expression .
"select" 语句选择哪些可进行 发送或接收的操作会被处理。 它看起来与"switch" 语句类似,但其 case 为所有涉及到通信的操作。
Select语句 = "select" "{" { 通信子句 } "}" . 通信子句 = 通信情况 ":" 语句列表 . 通信情况 = "case" ( 发送语句 | 接收语句 ) | "default" . 接收语句 = [ 表达式列表 [ "," 标识符列表 ] ( "=" | ":=" ) ] 接收表达式 . 接收表达式 = 表达式 .
A case with a RecvStmt may assign the result of a RecvExpr to one or two variables, which may be declared using a short variable declaration. The RecvExpr must be a (possibly parenthesized) receive operation. There can be at most one default case and it may appear anywhere in the list of cases.
带接收语句的 case 可将接收表达式的结果赋予一或两个变量,该变量可使用 短变量声明的形式声明。接收表达式必须为(可能带括号的) 接收操作。最多可以有一个默认 case 且可以出现在 case 列表中的任何地方。
Execution of a "select" statement proceeds in several steps:
"select" 语句的执行过程分为以下几步:
- For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed. Expressions on the left-hand side of a RecvStmt with a short variable declaration or assignment are not yet evaluated.
- If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
- Unless the selected case is the default case, the respective communication operation is executed.
- If the selected case is a RecvStmt with a short variable declaration or an assignment, the left-hand side expressions are evaluated and the received value (or values) are assigned.
- The statement list of the selected case is executed.
- 对于语句中的所有 case,接收操作的信道操作数和信道,以及右侧发送语句的表达式会在进入 "select" 语句时按照源码的顺序刚好执行一次。其结果为用于接收或发送的信道的集合, 以及对应的用于发送的值。该求值中的任何副作用都与已选择进行处理的通信操作无关 (如果存在的话)。接收语句左侧的短变量声明或赋值表达式尚未求值。
- 若一个或多个通信可以进行,就会按照均匀分布的伪随机数选择其中一个。否则,若存在一个默认 case,就会选择它。若没有默认 case,"select" 语句就会阻塞直到至少一个通信可以进行。
- 除非已选择的 case 为默认 case,否则对应的通信操作就会执行。
- 若选择的 case 为带短变量声明或赋值的接收语句,那么左边的表达式会被求值并被赋予接收的值。
- 已选择的 case 的语句列表会被执行。
Since communication on nil
channels can never proceed,
a select with only nil
channels and no default case blocks forever.
var a []int var c, c1, c2, c3, c4 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") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { print("received ", i3, " from c3\n") } else { print("c3 is closed\n") } case a[f()] = <-c4: // same as: // case t := <-c4 // a[f()] = t 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: } } select {} // block forever
由于在 nil
信道上的通信永远不会被处理,因此只带
nil
信道且无默认 case 的 select 会永远阻塞。
var a []int var c, c1, c2, c3, c4 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") case i3, ok := (<-c3): // 等价于 i3, ok := <-c3 if ok { print("received ", i3, " from c3\n") } else { print("c3 is closed\n") } case a[f()] = <-c4: // same as: // case t := <-c4 // a[f()] = t default: print("no communication\n") } for { // 向 c 发送位的随机序列 select { case c <- 0: // 注意:没有语句,没有 fallthrough,也没有 case 折叠 case c <- 1: } } select {} // 永远阻塞
Return statements
Return语句
A "return" statement in a function F
terminates the execution
of F
, and optionally provides one or more result values.
Any functions deferred by F
are executed before F
returns to its caller.
ReturnStmt = "return" [ ExpressionList ] .
函数 F
中的“return”语句终止 F
的执行,并可选地提供一个或多个返回值。
任何被 F
推迟的函数会在 F
返回给其调用者前执行。
Return语句 = "return" [ 表达式列表 ] .
In a function without a result type, a "return" statement must not specify any result values.
在没有返回类型的函数中,"return"语句不能指定任何返回值。
func noResult() { return }
There are three ways to return values from a function with a result type:
- The return value or values may be explicitly listed
in the "return" statement. Each expression must be single-valued
and assignable
to the corresponding element of the function's result type.
func simpleF() int { return 2 } func complexF1() (re float64, im float64) { return -7.0, -4.0 }
- The expression list in the "return" statement may be a single
call to a multi-valued function. The effect is as if each value
returned from that function were assigned to a temporary
variable with the type of the respective value, followed by a
"return" statement listing these variables, at which point the
rules of the previous case apply.
func complexF2() (re float64, im float64) { return complexF1() }
- The expression list may be empty if the function's result
type specifies names for its result parameters.
The result parameters act as ordinary local variables
and the function may assign values to them as necessary.
The "return" statement returns the values of these variables.
func complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return } func (devnull) Write(p []byte) (n int, _ error) { n = len(p) return }
从具有返回类型的函数返回值的三种方式:
- 返回值可在"return"语句中显式地列出。每个表达式必须为单值,
且可赋予相应的函数返回类型的元素。
func simpleF() int { return 2 } func complexF1() (re float64, im float64) { return -7.0, -4.0 }
-
"return"语句中的表达式列表可为多值函数的单个调用。
其效果相当于将该函数返回的每一个值赋予同类型的临时变量,
并在"return"语句后面列出这些变量,在这点上与前面的情况规则相同。
func complexF2() (re float64, im float64) { return complexF1() }
-
若函数的返回类型为其返回形参指定了名字,
则表达式列表可为空。返回形参的行为如同一般的局部变量,且必要时该函数可向他们赋值。
"return"语句返回这些变量的值。
func complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return } func (devnull) Write(p []byte) (n int, _ error) { n = len(p) return }
Regardless of how they are declared, all the result values are initialized to the zero values for their type upon entry to the function. A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
无论它们如何声明,在进入该函数时,所有的返回值都会被初始化为该类型的零值。 指定了结果的“return”语句会在任何被推迟的函数执行前设置结果形参。
Implementation restriction: A compiler may disallow an empty expression list in a "return" statement if a different entity (constant, type, or variable) with the same name as a result parameter is in scope at the place of the return.
func f(n int) (res int, err error) { if _, err := f(n-1); err != nil { return // invalid return statement: err is shadowed } return }
实现限制:若不同的条目以相同的名字作为结果形参出现在返回的作用域内, 那么编译器可能禁止空表达式列表出现在 "return" 语句中。
func f(n int) (res int, err error) { if _, err := f(n-1); err != nil { return // 无效的返回语句:err 被屏蔽 } return }
Break statements
Break语句
A "break" statement terminates execution of the innermost "for", "switch", or "select" statement within the same function.
BreakStmt = "break" [ Label ] .
"break"语句终止同函数内最内层的 "for"、 "switch" 或 "select" 语句的执行。
Break语句 = "break" [ 标签 ] .
If there is a label, it must be that of an enclosing "for", "switch", or "select" statement, and that is the one whose execution terminates.
若存在标签,则它必须为闭合的"for"、"switch"或"select"语句,而此执行就会终止。
OuterLoop: for i = 0; i < n; i++ { for j = 0; j < m; j++ { switch a[i][j] { case nil: state = Error break OuterLoop case item: state = Found break OuterLoop } } }
Continue statements
Continue语句
A "continue" statement begins the next iteration of the innermost "for" loop at its post statement. The "for" loop must be within the same function.
ContinueStmt = "continue" [ Label ] .
"continue"语句在最内层"for" 循环的步进语句处开始下一次迭代。 “for”循环必须在同一函数内。
Continue语句 = "continue" [ 标签 ] .
If there is a label, it must be that of an enclosing "for" statement, and that is the one whose execution advances.
若存在标签,则它必须为闭合的"for"语句,而此执行就会前进。
RowLoop: for y, row := range rows { for x, data := range row { if data == endOfRow { continue RowLoop } row[x] = data + bias(x, y) } }
Goto statements
Goto语句
A "goto" statement transfers control to the statement with the corresponding label within the same function.
GotoStmt = "goto" Label .
"goto"语句用于将控制转移到同函数内与其标签相应的语句。
Goto语句 = "goto" 标签 .
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:
执行"goto"不能在跳转点处产生任何还未在作用域中的变量来使其进入作用域。 比如,例子:
goto L // 这样不好 v := 3 L:
is erroneous because the jump to label L
skips
the creation of v
.
是错误的,因为跳转至标签 L
处将跳过 v
的创建。
A "goto" statement outside a block cannot jump to a label inside that block. For instance, this example:
在块外的"goto"语句不能跳转至该块中的标签。 比如,例子:
if n%2 == 1 { goto L1 } for n > 0 { f() n-- L1: f() n-- }
is erroneous because the label L1
is inside
the "for" statement's block but the goto
is not.
是错误的,因为标签 L1
在"for"语句的块中而 goto
则不在。
Fallthrough statements
Fallthrough语句
A "fallthrough" statement transfers control to the first statement of the next case clause in an expression "switch" statement. It may be used only as the final non-empty statement in such a clause.
FallthroughStmt = "fallthrough" .
"fallthrough"语句将控制转移到表达式 "switch" 语句 中下一个 case 子句的第一个语句。它可能只被用作这类子句里最后的非空语句。
Fallthrough语句 = "fallthrough" .
Defer statements
Defer语句
A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.
DeferStmt = "defer" Expression .
"defer"语句调用的函数将被推迟到其外围函数返回时执行,不论是因为该外围函数执行了 return 语句,到达了其函数体的末尾, 还是因为其对应的 Go 程进入了恐慌过程。
Defer语句 = "defer" 表达式 .
The expression must be a function or method call; it cannot be parenthesized. Calls of built-in functions are restricted as for expression statements.
Each time a "defer" statement
executes, the function value and parameters to the call are
evaluated as usual
and saved anew but the actual function is not invoked.
Instead, deferred functions are invoked immediately before
the surrounding function returns, in the reverse order
they were deferred.
If a deferred function value evaluates
to nil
, execution panics
when the function is invoked, not when the "defer" statement is executed.
For instance, if the deferred function is a function literal and the surrounding function has named result parameters that are in scope within the literal, the deferred function may access and modify the result parameters before they are returned. If the deferred function has any return values, they are discarded when the function completes. (See also the section on handling panics.)
lock(l) defer unlock(l) // unlocking happens before surrounding function returns // prints 3 2 1 0 before surrounding function returns for i := 0; i <= 3; i++ { defer fmt.Print(i) } // f returns 1 func f() (result int) { defer func() { result++ }() return 0 }
该表达必须为一个函数或方法调用,它不能被括号括住。内建函数调用被限制为表达式语句。
"defer"语句每执行一次,它所调用的函数值与形参就会
像平时一样求值并重新保存,但实际的函数并不会被调用。
取而代之的是,在外围的函数返回前,被推迟的函数会按照它们被推迟的相反顺序立即执行。
若已推迟函数值求值为 nil
,当该函数被调用时就会执行 panic
when the function is invoked, not when the "defer" statement is executed.
例如,若被推迟的函数为函数字面,而其外围函数在其作用域中的函数字面内拥有 已命名结果形参,则被推迟的函数可在该结果形参被返回前访问并更改。 若被推迟函数拥有任何返回值,则它们会在该函数完成时丢弃。 (另请参阅恐慌处理)一节。
lock(l) defer unlock(l) // 解锁在外围函数返回前发生 // 在外围函数返回前打印 3 2 1 0 for i := 0; i <= 3; i++ { defer fmt.Print(i) } // f 返回 1 func f() (result int) { defer func() { result++ }() return 0 }
Built-in functions
内建函数
Built-in functions are predeclared. They are called like any other function but some of them accept a type instead of an expression as the first argument.
内建函数是预声明的。它们可以像其他任何函数一样被调用, 但其中某些函数则接受类型而非表达式来作为第一个实参。
The built-in functions do not have standard Go types, so they can only appear in call expressions; they cannot be used as function values.
BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" . BuiltinArgs = Type [ "," ArgumentList ] | ArgumentList .
内建函数并没有标准的 Go 类型,因此它们只能出现在调用表达式中,而不能作为函数值被使用。
内建调用 = 标识符 "(" [ 内建实参 [ "," ] ] ")" . 内建实参 = 类型 [ "," 实参列表 ] | 实参列表 .
Close
关闭
For a channel c
, the built-in function close(c)
records that no more values will be sent on the channel.
It is an error if c
is a receive-only channel.
Sending to or closing a closed channel causes a run-time panic.
Closing the nil channel also causes a run-time panic.
After calling close
, and after any previously
sent values have been received, receive operations will return
the zero value for the channel's type without blocking.
The multi-valued receive operation
returns a received value along with an indication of whether the channel is closed.
对于一个信道 c
,内建函数 close(c)
标明不再有值会在该信道上发送。
若 c
为只接收信道,则会产生一个错误。向已关闭的信道发送信息或再次关闭它将引发
运行时恐慌。关闭 nil
信道也会引发运行时恐慌。
在调用 close
之后,任何以前发送的值都会被接收,接收操作将无阻塞地返回该信道类型的零值。
多值 接收操作 会随着一个该信道是否关闭的指示返回一个已接收的值。
Length and capacity
长度与容量
The built-in functions len
and cap
take arguments
of various types and return a result of type int
.
The implementation guarantees that the result always fits into an int
.
Call Argument type Result len(s) string type string length in bytes [n]T, *[n]T array length (== n) []T slice length map[K]T map length (number of defined keys) chan T number of elements queued in channel buffer cap(s) [n]T, *[n]T array length (== n) []T slice capacity chan T channel buffer capacity
内建函数 len
与 cap
接受各种类型的实参并返回 int
类型的结果。
该实现保证其结果总符合 int
类型。
调用 实参类型 结果 len(s) string type 字符串的字节长度。 [n]T, *[n]T 数组长度(== n) []T 切片长度 map[K]T 映射长度(已定义键的数量) chan T 信道缓存中元素队列的长度 cap(s) [n]T, *[n]T 数组长度(== n) []T 切片容量 chan T 信道缓存容量
The capacity of a slice is the number of elements for which there is space allocated in the underlying array. At any time the following relationship holds:
切片的容量为其底层数组中已分配的空间元素的数量。以下关系在任何时候都成立:
0 <= len(s) <= cap(s)
The length of a nil
slice, map or channel is 0.
The capacity of a nil
slice or channel is 0.
nil
切片、映射或信道的长度为 0。nil
切片或信道的容量为 0。
The expression len(s)
is constant if
s
is a string constant. The expressions len(s)
and
cap(s)
are constants if the type of s
is an array
or pointer to an array and the expression s
does not contain
channel receives or (non-constant)
function calls; in this case s
is not evaluated.
Otherwise, invocations of len
and cap
are not
constant and s
is evaluated.
若 s
为字符串常量,则表达式 len(s)
即为 常量。
若 s
的类型为数组或数组指针,且表达式 s
不包含信道接收
或(非常量)函数调用,则表达式 len(s)
与 cap(s)
即为常量,在这种用情况下,
s
不会被求值。否则,len
与 cap
的调用不为常量,且 s
会被求值。
const ( c1 = imag(2i) // imag(2i) = 2.0 is a constant c2 = len([10]float64{2}) // [10]float64{2} contains no function calls c3 = len([10]float64{c1}) // [10]float64{c1} contains no function calls c4 = len([10]float64{imag(2i)}) // imag(2i) is a constant and no function call is issued c5 = len([10]float64{imag(z)}) // invalid: imag(z) is a (non-constant) function call ) var z complex128
const ( c1 = imag(2i) // imag(2i) = 2.0 为常量 c2 = len([10]float64{2}) // [10]float64{2} 不包含函数调用 c3 = len([10]float64{c1}) // [10]float64{c1} 不包含函数调用 c4 = len([10]float64{imag(2i)}) // imag(2i) 为常量且无函数调用问题 c5 = len([10]float64{imag(z)}) // 无效:imag(z) 为(非常量)函数调用 ) var z complex128
Allocation
分配
The built-in function new
takes a type T
,
allocates storage for a variable of that type
at run time, and returns a value of type *T
pointing to it.
The variable is initialized as described in the section on
initial values.
内建函数 new
接受类型 T
,在运行时为该类型的
变量 分配空间并返回类型为 *T
的值指向它。该变量根据§初始值一节中的描述来初始化。
new(T)
For instance
例如
type S struct { a int; b float64 } new(S)
allocates storage for a variable of type S
,
initializes it (a=0
, b=0.0
),
and returns a value of type *S
containing the address
of the location.
将为类型为 S
的变量分配存储、初始化(a=0
,b=0.0
)并返回类型为
*S
的包含位置地址的值。
Making slices, maps and channels
创建切片、映射与信道
The built-in function make
takes a type T
,
which must be a slice, map or channel type,
optionally followed by a type-specific list of expressions.
It returns a value of type T
(not *T
).
The memory is initialized as described in the section on
initial values.
Call Type T Result make(T, n) slice slice of type T with length n and capacity n make(T, n, m) slice slice of type T with length n and capacity m make(T) map map of type T make(T, n) map map of type T with initial space for approximately n elements make(T) channel unbuffered channel of type T make(T, n) channel buffered channel of type T, buffer size n
内建函数 make
接受的类型 T
必须为切片、映射或信道类型,
可选地跟着一个特殊类型的表达式列表。它返回类型为 T
(而非 *T
)的值。
其内存根据§初始值一节中的描述来初始化。
调用 类型 T 结果 make(T, n) slice 类型为 T,长度为 n,容量为 n 的切片 make(T, n, m) slice 类型为 T,长度为 n,容量为 m 的切片 make(T) map 类型为 T 的映射 make(T, n) map 类型为 T,初始空间为 n 个元素的映射 make(T) channel 类型为 T 的无缓冲信道 make(T, n) channel 类型为 T,缓存大小为 n 的带缓冲信道
Each of the size arguments n
and m
must be of integer type
or an untyped constant.
A constant size argument must be non-negative and representable
by a value of type int
; if it is an untyped constant it is given type int
.
If both n
and m
are provided and are constant, then
n
must be no larger than m
.
If n
is negative or larger than m
at run time,
a run-time panic occurs.
s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100 s := make([]int, 1e3) // slice with len(s) == cap(s) == 1000 s := make([]int, 1<<63) // illegal: len(s) is not representable by a value of type int s := make([]int, 10, 0) // illegal: len(s) > cap(s) c := make(chan int, 10) // channel with a buffer size of 10 m := make(map[string]int, 100) // map with initial space for approximately 100 elements
用于指定大小的实参 n
与 m
必须为整数类型或无类型化的。
常量大小的实参必须为非负值,且可表示为 int
类型的值。
若 n
和 m
已给定且为常量,则 n
必不大于
m
。若 n
在运行时为负值或大于 m
,
就会引发运行时恐慌。
s := make([]int, 10, 100) // len(s) == 10,cap(s) == 100 的切片 s := make([]int, 1e3) // len(s) == cap(s) == 1000 的切片 s := make([]int, 1<<63) // 非法:len(s) 不能表示为 int 类型的值 s := make([]int, 10, 0) // 非法:len(s) > cap(s) c := make(chan int, 10) // 缓存大小为 10 的信道 m := make(map[string]int, 100) // 初始空间约为 100 个元素的映射
Calling make
with a map type and size hint n
will
create a map with initial space to hold n
map elements.
The precise behavior is implementation-dependent.
Appending to and copying slices
追加与复制切片
The built-in functions append
and copy
assist in
common slice operations.
For both functions, the result is independent of whether the memory referenced
by the arguments overlaps.
内建函数 append
与 copy
协助一般的切片操作。对于这两个函数,
无论其内存引用是否与其实参重复,其结果都是独立的。
The variadic function append
appends zero or more values x
to s
of type S
, which must be a slice type, and
returns the resulting slice, also of type S
.
The values x
are passed to a parameter of type ...T
where T
is the element type of
S
and the respective
parameter passing rules apply.
As a special case, append
also accepts a first argument
assignable to type []byte
with a second argument of
string type followed by ...
. This form appends the
bytes of the string.
append(s S, x ...T) S // T is the element type of S
变参函数 append
追加零个或更多值 x
至 类型为
S
的s
,它必须为切片类型,且返回类型为 S
的结果切片,
值 x
被传至类型为 ...T
的形参,其中 T
为 S
的元素类型,且其各自的形参传递规则均适用。
作为一个特例,append
也接受第一个实参可赋予类型 []byte
,
且第二个字符串类型的实参后跟 ...
。此形式追加字符串类型的字节。
append(s S, x ...T) S // T 是类型为 S 的元素
If the capacity of s
is not large enough to fit the additional
values, append
allocates a new, sufficiently large underlying
array that fits both the existing slice elements and the additional values.
Otherwise, append
re-uses the underlying array.
s0 := []int{0, 0} s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2} s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7} s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3, 5, 7, 0, 0} s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0} var t []interface{} t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"} var b []byte b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
若 s
的容量不足够大以适应附加的值,append
会分配一个新的,
足够大的底层数组以适应现有切片元素与附加的值。否则,append
会重用底层数组。
s0 := []int{0, 0} s1 := append(s0, 2) // 追加单个元素 s1 == []int{0, 0, 2} s2 := append(s1, 3, 5, 7) // 追加多个元素 s2 == []int{0, 0, 2, 3, 5, 7} s3 := append(s2, s0...) // 追加一个切片 s3 == []int{0, 0, 2, 3, 5, 7, 0, 0} s4 := append(s3[3:6], s3[2:]...) // 追加重复切片 s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0} var t []interface{} t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"} var b []byte b = append(b, "bar"...) // 追加字符串常量 b == []byte{'b', 'a', 'r' }
The function copy
copies slice elements from
a source src
to a destination dst
and returns the
number of elements copied.
Both arguments must have identical element type T
and must be
assignable to a slice of type []T
.
The number of elements copied is the minimum of
len(src)
and len(dst)
.
As a special case, copy
also accepts a destination argument assignable
to type []byte
with a source argument of a string type.
This form copies the bytes from the string into the byte slice.
函数 copy
将切片元素从来源 src
复制到目标 dst
并返回复制的元素数量。两个实参必须都拥有相同的元素类型
T
,且必须都可赋予类型为 []T
的切片。
被复制的元素数量为 len(src)
与 len(dst)
中最小的那个。
作为一个特例,copy
也接受一个可赋予类型 []byte
的目标实参以及一个字符串类型的来源实参。此形式从该字符串中复制字节到该字节切片。
copy(dst, src []T) int copy(dst []byte, src string) int
Examples:
例如:
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7} var s = make([]int, 6) var b = make([]byte, 5) n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5} n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5} n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
Deletion of map elements
映射元素的删除
The built-in function delete
removes the element with key
k
from a map m
. The
type of k
must be assignable
to the key type of m
.
delete(m, k) // remove element m[k] from map m
内建函数 delete
从映射 m
中移除键为 k
的元素。k
的类型必须可赋予 m
类型的键。
delete(m, k) // 从映射 m 中移除元素 m[k]
If the map m
is nil
or the element m[k]
does not exist, delete
is a no-op.
若映射 m
为 nil
或元素 m[k]
不存在,则
delete
就是一个空操作。
Manipulating complex numbers
复数操作
Three functions assemble and disassemble complex numbers.
The built-in function complex
constructs a complex
value from a floating-point real and imaginary part, while
real
and imag
extract the real and imaginary parts of a complex value.
三个函数用于组合并分解复数。内建函数 complex
从一个浮点数实部和虚部构造一个复数值。
而 real
和 imag
则提取一个复数值的实部和虚部。
complex(realPart, imaginaryPart floatT) complexT real(complexT) floatT imag(complexT) floatT
The type of the arguments and return value correspond.
For complex
, the two arguments must be of the same
floating-point type and the return type is the complex type
with the corresponding floating-point constituents:
complex64
for float32
arguments, and
complex128
for float64
arguments.
If one of the arguments evaluates to an untyped constant, it is first
converted to the type of the other argument.
If both arguments evaluate to untyped constants, they must be non-complex
numbers or their imaginary parts must be zero, and the return value of
the function is an untyped complex constant.
For real
and imag
, the argument must be
of complex type, and the return type is the corresponding floating-point
type: float32
for a complex64
argument, and
float64
for a complex128
argument.
If the argument evaluates to an untyped constant, it must be a number,
and the return value of the function is an untyped floating-point constant.
实参与返回值的类型一致。对于 complex
,两实参必须为相同的浮点类型且其返回类型为
浮点数组成部分一致的复数类型:complex64
对应于 float32
实参,
complex128
对应于 float64
实参。
若其中一个实参求值为无类型化常量,它首先会转换为其它实参的类型。
若两个实参均求值为无类型化常量,它们必须为非复数或它们的虚部必须为零,该函数的返回值为无类型化复数。
对于 real
和 imag
,其实参必须为复数类型,
且返回类型为对应的浮点数类型:float32
对应于 complex64
实参,
float64
对应于 complex128
实参。
若该实参求值为无类型化常量,那么它必须为数值,该函数的返回值为无类型化浮点数。
The real
and imag
functions together form the inverse of
complex
, so for a value z
of a complex type Z
,
z == Z(complex(real(z), imag(z)))
.
real
和 imag
函数一起组成了 complex
的反函数,
因此对于复数类型 Z
的值 z
,有
z == Z(complex(real(z), imag(z)))
。
If the operands of these functions are all constants, the return value is a constant.
若这些函数的操作数均为常量,则返回值亦为常量。
var a = complex(2, -2) // complex128 const b = complex(1.0, -1.4) // untyped complex constant 1 - 1.4i x := float32(math.Cos(math.Pi/2)) // float32 var c64 = complex(5, -x) // complex64 var s uint = complex(1, 0) // untyped complex constant 1 + 0i can be converted to uint _ = complex(1, 2<<s) // illegal: 2 assumes floating-point type, cannot shift var rl = real(c64) // float32 var im = imag(a) // float64 const c = imag(b) // untyped constant -1.4 _ = imag(3 << s) // illegal: 3 assumes complex type, cannot shift
var a = complex(2, -2) // complex128 const b = complex(1.0, -1.4) // 无类型化复数常量 1 - 1.4i x := float32(math.Cos(math.Pi/2)) // float32 var c64 = complex(5, -x) // complex64 const s uint = complex(1, 0) // 无类型化复数常量 1 + 0i 可转换为 uint _ = complex(1, 2<<s) // 非法:2 为浮点数类型,无法移位 var rl = real(c64) // float32 var im = imag(a) // float64 const c = imag(b) // 无类型化常量 -1.4 _ = imag(3 << s) // 非法:3 视为复数类型,无法移位
Handling panics
恐慌处理
Two built-in functions, panic
and recover
,
assist in reporting and handling run-time panics
and program-defined error conditions.
内建函数 panic
和 recover
用于协助报告并处理运行时恐慌以及由程序定义的错误情况。
func panic(interface{}) func recover() interface{}
While executing a function F
,
an explicit call to panic
or a run-time panic
terminates the execution of F
.
Any functions deferred by F
are then executed as usual.
Next, any deferred functions run by F's
caller are run,
and so on up to any deferred by the top-level function in the executing goroutine.
At that point, the program is terminated and the error
condition is reported, including the value of the argument to panic
.
This termination sequence is called panicking.
当执行函数 F
时,一个显式的 panic
调用或运行时恐慌
均会终止 F
的执行。任何被 F
推迟的函数都会像往常一样继续执行。
接着,任何被 F
的调用者推迟的函数开始运行,如此继续,直到该执行的Go程中被顶级函数推迟的任何函数均开始运行。
到那时,该程序将被终止,而该错误情况会被报告,包括引发 panic
的实参值。
此终止序列称为恐慌过程。
panic(42) panic("unreachable") panic(Error("cannot parse"))
The recover
function allows a program to manage behavior
of a panicking goroutine.
Suppose a function G
defers a function D
that calls
recover
and a panic occurs in a function on the same goroutine in which G
is executing.
When the running of deferred functions reaches D
,
the return value of D
's call to recover
will be the value passed to the call of panic
.
If D
returns normally, without starting a new
panic
, the panicking sequence stops. In that case,
the state of functions called between G
and the call to panic
is discarded, and normal execution resumes.
Any functions deferred by G
before D
are then run and G
's
execution terminates by returning to its caller.
recover
函数允许程序管理恐慌状态的Go程的行为。
假设函数 G
推迟了一个函数 D
,该函数调用了
recover
,而执行了 G
的Go程中的函数又引发了恐慌,
那么当被推迟函数的运行到达 D
时,D
调用 recover
的返回值会正常返回,若未开始新的 panic
,那么恐慌过程序列就会停止。
在此情况下,G
和 panic
调用之间的函数调用会被丢弃,
然后继续正常执行。任何在 D
之前被 G
推迟的函数继续运行,G
的执行则会因返回给其调用者而终止。
The return value of recover
is nil
if any of the following conditions holds:
-
panic
's argument wasnil
; - the goroutine is not panicking;
-
recover
was not called directly by a deferred function.
若满足以下任一条件,recover
的返回值即为 nil
:
-
panic
的实参为nil
; - Go程未处于恐慌状态
-
recover
未直接被已推迟函数。
The protect
function in the example below invokes
the function argument g
and protects callers from
run-time panics raised by g
.
func protect(g func()) { defer func() { log.Println("done") // Println executes normally even if there is a panic if x := recover(); x != nil { log.Printf("run time panic: %v", x) } }() log.Println("start") g() }
func protect(g func()) { defer func() { log.Println("done") // 即使有恐慌 Println 也会正常执行 if x := recover(); x != nil { log.Printf("run time panic: %v", x) } }() log.Println("start") g() }
下面例子中的 protect
函数调用函数实参 g
并保护由 g
提升的来自运行时恐慌的调用者。
Bootstrapping
引导
Current implementations provide several built-in functions useful during bootstrapping. These functions are documented for completeness but are not guaranteed to stay in the language. They do not return a result.
Function Behavior print prints all arguments; formatting of arguments is implementation-specific println like print but prints spaces between arguments and a newline at the end
当前实现提供了几个在引导过程中有用的内建函数。这些函数因完整性而被保留, 但不保证会继续留在该语言中。它们并不返回结果。
函数 行为 print 打印所有实参;实参的格式取决于具体实现 println 类似 print,但会在实参之间打印空格并在末尾打印新行
Implementation restriction: print
and println
need not
accept arbitrary argument types, but printing of boolean, numeric, and string
types must be supported.
Packages
包
Go programs are constructed by linking together packages. A package in turn is constructed from one or more source files that together declare constants, types, variables and functions belonging to the package and which are accessible in all files of the same package. Those elements may be exported and used in another package.
Go 程序由联系在一起的包构造。包由一个或更多源文件构造转化而来, 源文件与其常量、类型、变量和函数声明一同属于该包,且在相同包的所有文件中它们可互相访问。 这些元素可被导出并用于其它包。
Source file organization
源文件的组织
Each source file consists of a package clause defining the package to which it belongs, followed by a possibly empty set of import declarations that declare packages whose contents it wishes to use, followed by a possibly empty set of declarations of functions, types, variables, and constants.
SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
每个源文件都由这些部分构成:首先是一个定义该源文件所属包的包子句, 然后是一个可能为空的声明所需内容所在包的导入声明的集,最后是一个可能为空的函数、 类型、变量与常量声明的集。
源文件 = 包子句 ";" { 导入声明 ";" } { 顶级声明 ";" } .
Package clause
包子句
A package clause begins each source file and defines the package to which the file belongs.
PackageClause = "package" PackageName . PackageName = identifier .
包子句起始于每个源文件并定义该文件所属的包。
包子句 = "package" 包名 . 包名 = 标识符 .
The PackageName must not be the blank identifier.
包名不能为空白标识符.
package math
A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.
一个文件集通过共享相同的包名来构成包的实现。实现可能要求包的所有源文件放置在同一目录下。
Import declarations
导入声明
An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported.
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) . ImportSpec = [ "." | PackageName ] ImportPath . ImportPath = string_lit .
导入声明陈述了源文件中所包含的声明,这取决于已导入包的功能 (§程序初始化与执行), 并使其能够访问该包的可导出标识符。 导入通过命名一个标识符(包名)用于访问,而导入路径则指定可导出的包。
导入声明 = "import" ( 导入指定 | "(" { 导入指定 ";" } ")" ) . 导入指定 = [ "." | 包名 ] 导入路径 . 导入路径 = 字符串字面 .
The PackageName is used in qualified identifiers
to access exported identifiers of the package within the importing source file.
It is declared in the file block.
If the PackageName is omitted, it defaults to the identifier specified in the
package clause of the imported package.
If an explicit period (.
) appears instead of a name, all the
package's exported identifiers declared in that package's
package block will be declared in the importing source
file's file block and must be accessed without a qualifier.
包名作为限定标识符来访问导入的源文件中包的可导出标识符。
它在文件块中声明。若该包名已省略,则默认由已导入包的包子句中的标识符指定。
若出现一个显式的点号(.
)来代替名字,
所有在该包的包块中声明的可导出标识符将在导入源文件的文件块中声明,且无需标识符必能访问。
The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.
导入路径的解释取决于具体实现,但它是一个典型的已编译包的完整文件名的子串,且可能是相对于一个已安装包的仓库的。
Implementation restriction: A compiler may restrict ImportPaths to
non-empty strings using only characters belonging to
Unicode's
L, M, N, P, and S general categories (the Graphic characters without
spaces) and may also exclude the characters
!"#$%&'()*,:;<=>?[\]^`{|}
and the Unicode replacement character U+FFFD.
实现限制:编译器会限制导入路径使用只属于Unicode
中 L、M、N、P 及 S 一般类别(不带空格的图形字符)中的非空字符串,且不含字符
!"#$%&'()*,:;<=>?[\]^`{|}
以及 Unicode 占位字符 U+FFFD。
Assume we have compiled a package containing the package clause
package math
, which exports function Sin
, and
installed the compiled package in the file identified by
"lib/math"
.
This table illustrates how Sin
is accessed in files
that import the package after the
various types of import declaration.
Import declaration Local name of Sin import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
假定我们拥有包含包子句 package math
的已编译包,它导出函数 Sin
,
且该包已被安装在标识为"lib/math"
的文件中。此表单阐明了在各种类型的导入声明之后,
Sin
在导入该包的文件中如何访问。
导入声明 Sin 的本地名 import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:
导入声明用来声明导入包与被导入包之间的从属关系。包直接或间接地导入其自身, 或直接导入一个包而不引用其中任何一个已导出标识符是非法的。 要为包的副作用(初始化)而单独导入它,需使用空白标识符作为明确的包名:
import _ "lib/math"
An example package
一个例子包
Here is a complete Go package that implements a concurrent prime sieve.
package main import "fmt" // 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 'src' to channel 'dst', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i // Send 'i' to channel 'dst'. } } } // 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 fmt.Print(prime, "\n") ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1 } } func main() { sieve() }
以下为实现了并发质数筛的完整 Go 包。
package main import "fmt" // 将序列 2, 3, 4, … 发送至信道'ch'。 func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // 将 'i' 发送至信道'ch'。 } } // 将值从信道'src'中复制至信道'dst', // 移除可被'prime'整除的数。 func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // 循环遍历从'src'接收的值。 if i%prime != 0 { dst <- i // 将'i'发送至'dst'。 } } } // 质数筛:将过滤器串联在一起处理。 func sieve() { ch := make(chan int) // 创建一个新信道。 go generate(ch) // 将 generate()作为子进程开始。 for { prime := <-ch fmt.Print(prime, "\n") ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1 } } func main() { sieve() }
Program initialization and execution
程序初始化与执行
The zero value
零值
When storage is allocated for a variable,
either through a declaration or a call of new
, or when
a new value is created, either through a composite literal or a call
of make
,
and no explicit initialization is provided, the variable or value is
given a default value. Each element of such a variable or value is
set to the zero value for its type: false
for booleans,
0
for numeric types, ""
for strings, and nil
for pointers, functions, interfaces, slices, channels, and maps.
This initialization is done recursively, so for instance each element of an
array of structs will have its fields zeroed if no value is specified.
当为变量分配存储时,不是通过声明就是通过 new
调用;
或当创建一个新值时,不是通过复合字面就是通过 make
调用。
而在未提供显式的初始化时,变量或值将被赋予一个默认值。每个这样的变量或值的元素将置为该类型的零值:
布尔类型为 false
,整数类型为 0
,浮点数类型为 0.0
,
字符串类型为 ""
,而指针、函数、接口、切片、信道及映射类型则为 nil
。
该初始化递归地完成,例如,对于结构体的数组的每一个元素,若没有值被指定,则将其拥有的字段归零。
These two simple declarations are equivalent:
以下两个简单声明是等价的:
var i int var i int = 0
After
在
type T struct { i int; f float64; next *T } t := new(T)
the following holds:
之后,以下表达式成立:
t.i == 0 t.f == 0.0 t.next == nil
The same would also be true after
同样,在
var t T
之后,上面的表达式仍然为真。
Package initialization
包初始化
Within a package, package-level variables are initialized in declaration order but after any of the variables they depend on.
在包中,包级变量在其依赖的变量初始化后按照声明顺序初始化,
More precisely, a package-level variable is considered ready for initialization if it is not yet initialized and either has no initialization expression or its initialization expression has no dependencies on uninitialized variables. Initialization proceeds by repeatedly initializing the next package-level variable that is earliest in declaration order and ready for initialization, until there are no variables ready for initialization.
更精确地说,包级变量在它尚未初始化或无初始化表达式 或其初始化表达式无依赖的未初始化变量时才考虑准备初始化。 初始化过程通过重复地初始化下一个在声明顺序中最早的且准备好初始化的包级变量来进行, 直到不再有准备好初始化的变量为止。
If any variables are still uninitialized when this process ends, those variables are part of one or more initialization cycles, and the program is not valid.
若初始化过程结束后仍有未初始化的变量,该变量会变为一个或更多初始化循环的一部分, 该程序即为无效的。
The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on.
在多个文件中声明的变量的声明顺序由该文件呈现给编译器的顺序决定: 第一个文件中声明的变量会在第二个文件中声明的任何变量前声明,如此继续。
Dependency analysis does not rely on the actual values of the
variables, only on lexical references to them in the source,
analyzed transitively. For instance, if a variable x
's
initialization expression refers to a function whose body refers to
variable y
then x
depends on y
.
Specifically:
依赖分析不会依赖于变量的实际值,只会根据源码中对它们的引用传递性地分析。
例如,若变量 x
的初始化表达式引用了一个函数,其函数体又引用了变量
y
,那么 x
依赖于 y
。特别地:
- A reference to a variable or function is an identifier denoting that variable or function.
-
A reference to a method
m
is a method value or method expression of the formt.m
, where the (static) type oft
is not an interface type, and the methodm
is in the method set oft
. It is immaterial whether the resulting function valuet.m
is invoked. -
A variable, function, or method
x
depends on a variabley
ifx
's initialization expression or body (for functions and methods) contains a reference toy
or to a function or method that depends ony
.
- 对变量或函数的引用为表示该变量或函数的标识符。
-
对方法
m
的引用为形式为t.m
的方法值或方法表达式, 其中t
的(静态)类型不为接口类型,且方法m
在t
的方法集中。t.m
被调用后的结果函数值并不重要。 -
若变量、函数或方法
x
的初始化表达式或主体(函数体或方法体) 包含一个对y
的引用或依赖于y
的函数或方法, 那么x
即依赖y
。
Dependency analysis is performed per package; only references referring to variables, functions, and methods declared in the current package are considered.
依赖分析会为每个包执行,只有引用了在当前包中声明的变量、函数或方法引用才会被考虑。
For example, given the declarations
例如,给定声明
var ( a = c + b b = f() c = f() d = 3 ) func f() int { d++ return d }
the initialization order is d
, b
, c
, a
.
那么初始化顺序为 d
、b
、c
、a
。
Variables may also be initialized using functions named init
declared in the package block, with no arguments and no result parameters.
变量也可使用包块中声明的名为 init
的函数初始化,该函数无实参和结果形参。
func init() { … }
Multiple such functions may be defined per package, even within a single
source file. In the package block, the init
identifier can
be used only to declare init
functions, yet the identifier
itself is not declared. Thus
init
functions cannot be referred to from anywhere
in a program.
这样的函数在每个包中都可定义多个,甚至在单个源文件内。在包块中,init
仅能用于声明 init
方法,而标识符本身并非声明,
因此 init
函数并不能在程序中的任何地方引用。
A package with no imports is initialized by assigning initial values
to all its package-level variables followed by calling all init
functions in the order they appear in the source, possibly in multiple files,
as presented to the compiler.
If a package has imports, the imported packages are initialized
before initializing the package itself. If multiple packages import
a package, the imported package will be initialized only once.
The importing of packages, by construction, guarantees that there
can be no cyclic initialization dependencies.
无导入的包在初始化时,会在为所有包级变量赋予初始值后,
按照将包内的多个源码文件呈现给编译器的顺序依次调用其中所有的 init
函数。
若包中存在导入,被导入的包会先于该包初始化。若有多个包导入了一个包,被导入的包只会初始化一次。
根据构造导入的包可保证在初始化中没有循环依赖。
Package initialization—variable initialization and the invocation of
init
functions—happens in a single goroutine,
sequentially, one package at a time.
An init
function may launch other goroutines, which can run
concurrently with the initialization code. However, initialization
always sequences
the init
functions: it will not invoke the next one
until the previous one has returned.
包初始化 —变量初始化与 init
函数的调用 —连续地发生在单一的 Go 程中,一次一包。
一个 init
函数可能在其它 Go 程中启动,它可以与初始化代码一同运行。然而,初始化总是按顺序执行
init
函数:直到上一个返回后,它才会调用下一个。
To ensure reproducible initialization behavior, build systems are encouraged to present multiple files belonging to the same package in lexical file name order to a compiler.
为确保可重现的初始化行为,规范鼓励构建系统将属于同一包中的多个文件按词法文件名顺序呈现给编译器。
Program execution
程序执行
A complete program is created by linking a single, unimported package
called the main package with all the packages it imports, transitively.
The main package must
have package name main
and
declare a function main
that takes no
arguments and returns no value.
一个完整的程序通过链接一个单一的、不会被导入的、称为 主包 的,带所有其传递地导入包的包创建。
主包必须拥有包名 main
且声明一个无实参无返回值的函数 main
。
func main() { … }
Program execution begins by initializing the main package and then
invoking the function main
.
When that function invocation returns, the program exits.
It does not wait for other (non-main
) goroutines to complete.
程序通过初始化主包然后调用函数 main
开始执行。当该函数调用返回后,
程序退出。它不会等待其它(非 main
)Go 程完成。
Errors
错误
The predeclared type error
is defined as
预声明类型 error
定义为
type error interface { Error() string }
It is the conventional interface for representing an error condition, with the nil value representing no error. For instance, a function to read data from a file might be defined:
它是表示一种错误状态的传统接口,用 nil
值表示没有错误。
例如,一个从文件中读取数据的函数可被定义为:
func Read(f *File, b []byte) (n int, err error)
Run-time panics
运行时恐慌
Execution errors such as attempting to index an array out
of bounds trigger a run-time panic equivalent to a call of
the built-in function panic
with a value of the implementation-defined interface type runtime.Error
.
That type satisfies the predeclared interface type
error
.
The exact error values that
represent distinct run-time error conditions are unspecified.
package runtime type Error interface { error // and perhaps other methods }
例如试图索引一个越界的数组这类的执行错误会引发运行时恐慌,它等价于
一个定义实现了接口类型 runtime.Error
的值的内建函数
panic
的调用。该类型满足预声明接口类型
error
。表示明显的运行时错误状态的准确错误值是不确定的。
package runtime type Error interface { error // 可能还有其它方法 }
System considerations
系统考虑
Package unsafe
包 unsafe
The built-in package unsafe
, known to the compiler
and accessible through the import path "unsafe"
,
provides facilities for low-level programming including operations
that violate the type system. A package using unsafe
must be vetted manually for type safety and may not be portable.
The package provides the following interface:
package unsafe type ArbitraryType int // shorthand for an arbitrary Go type; it is not a real type type Pointer *ArbitraryType func Alignof(variable ArbitraryType) uintptr func Offsetof(selector ArbitraryType) uintptr func Sizeof(variable ArbitraryType) uintptr
编译器已知的内建包 unsafe
为包括违反类型系统操作在内的低级编程提供工具。使用
unsafe
的包为了类型安全必须手动进行审查且可能无法移植。该包提供以下接口:
package unsafe type ArbitraryType int // 任意 Go 类型的简写,它并非真正的类型 type Pointer *ArbitraryType func Alignof(variable ArbitraryType) uintptr func Offsetof(selector ArbitraryType) uintptr func Sizeof(variable ArbitraryType) uintptr
A Pointer
is a pointer type but a Pointer
value may not be dereferenced.
Any pointer or value of underlying type uintptr
can be converted to
a type of underlying type Pointer
and vice versa.
The effect of converting between Pointer
and uintptr
is implementation-defined.
Pointer
为指针类型但 Pointer
值可能并未解引用。
任何基本类型为 uintptr
的指针或值均可转换为底层类型 Pointer
,反之亦然。
Pointer
和 uintptr
的转换效果由实现定义。
var f float64 bits = *(*uint64)(unsafe.Pointer(&f)) type ptr unsafe.Pointer bits = *(*uint64)(ptr(&f)) var p ptr = nil
The functions Alignof
and Sizeof
take an expression x
of any type and return the alignment or size, respectively, of a hypothetical variable v
as if v
was declared via var v = x
.
函数 Alignof
与 Sizeof
接受一个任何类型的表达式 x
,
就好像通过 var v = x
声明的变量 v
一样,分别返回其对齐或大小。
The function Offsetof
takes a (possibly parenthesized) selector
s.f
, denoting a field f
of the struct denoted by s
or *s
, and returns the field offset in bytes relative to the struct's address.
If f
is an embedded field, it must be reachable
without pointer indirections through fields of the struct.
For a struct s
with field f
:
函数 Offsetof
接受一个(可能带括号的)选择器
s.f
,它表示一个由 s
或 *s
表示的结构体的字段 f
,
并返回该字段相对于该结构体地址偏移的字节。若 f
是一个内嵌字段,
它必须能通过(无指针间接引用的)结构体字段获取。
对于带字段 f
的结构体 s
:
uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))
Computer architectures may require memory addresses to be aligned;
that is, for addresses of a variable to be a multiple of a factor,
the variable's type's alignment. The function Alignof
takes an expression denoting a variable of any type and returns the
alignment of the (type of the) variable in bytes. For a variable
x
:
计算机架构可能需要内存地址 对齐,即,为使变量的地址为因数的倍数,该变量的类型需要对齐。函数
Alignof
接受一个表示任何类型变量的表达式并返回该(类型的)变量对齐的字节。对于变量 x
:
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
Calls to Alignof
, Offsetof
, and
Sizeof
are compile-time constant expressions of type uintptr
.
调用 Alignof
、Offsetof
和 Sizeof
是类型为
uintptr
的编译时常量表达式。
Size and alignment guarantees
大小与对齐保证
For the numeric types, the following sizes are guaranteed:
type size in bytes byte, uint8, int8 1 uint16, int16 2 uint32, int32, float32 4 uint64, int64, float64, complex64 8 complex128 16
对于数值类型,以下大小给予保证:
类型 字节大小 byte, uint8, int8 1 uint16, int16 2 uint32, int32, float32 4 uint64, int64, float64, complex64 8 complex128 16
The following minimal alignment properties are guaranteed:
- For a variable
x
of any type:unsafe.Alignof(x)
is at least 1. - For a variable
x
of struct type:unsafe.Alignof(x)
is the largest of all the valuesunsafe.Alignof(x.f)
for each fieldf
ofx
, but at least 1. - For a variable
x
of array type:unsafe.Alignof(x)
is the same as the alignment of a variable of the array's element type.
以下最小对齐属性给予保证:
- 对于任何类型的变量
x
:unsafe.Alignof(x)
至少为 1。 - 对于结构体类型的变量
x
:对于x
的每一个字段f
,unsafe.Alignof(x)
的值为所有unsafe.Alignof(x.f)
值中最大的,但至少为 1。 - 对于数组类型的变量
x
:unsafe.Alignof(x)
与unsafe.Alignof(x[0])
相同,但至少为 1。
A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.
若结构体或数组类型不包含大小大于零的字段或元素,它们的大小即为零。两个不同的零大小变量在内存中可能有相同的地址。