The Go Programming Language Specification
Go 编程语言规范
Language version go1.24 (Dec 30, 2024)
语言版本 go1.24 (2024 年 12 月 30 日)
Introduction¶ 引言¶
This is the reference manual for the Go programming language.
The pre-Go1.18 version, without generics, can be found
here.
For more information and other documents, see go.dev.
这是 Go 编程语言的参考手册。Go1.18 之前的版本(不含泛型)可在此处查阅。更多信息及其他文档请参见 go.dev。
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 syntax is compact and simple to parse, allowing for easy analysis
by automatic tools such as integrated development environments.
语法结构紧凑且易于解析,便于集成开发环境等自动化工具进行轻松分析。
Notation¶ 标记 ¶
The syntax is specified using a
variant
of Extended Backus-Naur Form (EBNF):
语法规范采用扩展巴科斯范式(EBNF)的变体进行定义:
Syntax = { Production } .
Production = production_name "=" [ Expression ] "." .
Expression = Term { "|" Term } .
Term = Factor { Factor } .
Factor = production_name | token [ "…" token ] | Group | Option | Repetition .
Group = "(" Expression ")" .
Option = "[" Expression "]" .
Repetition = "{" Expression "}" .
Productions are expressions constructed from terms and the following
operators, in increasing precedence:
Productions 是由项和以下运算符构造的表达式,按优先级递增排列:
| alternation
() grouping
[] option (0 or 1 times)
{} repetition (0 to n times)
Lowercase production names are used to identify lexical (terminal) tokens.
Non-terminals are in CamelCase. Lexical tokens are enclosed in
double quotes "" or back quotes ``.
小写形式的生产名称用于标识词法标记(终结符),非终结符采用驼峰式命名法。词法标记需用双引号 "" 或反引号 `` 包裹。
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 语言的词法标记。
A link of the form [Go 1.xx] indicates that a described
language feature (or some aspect of it) was changed or added with language version 1.xx and
thus requires at minimum that language version to build.
For details, see the linked section
in the appendix.
格式为 [ Go 1.xx] 的链接表示所述语言特性(或其某些方面)在语言版本 1.xx 中发生变更或新增,因此构建时至少需要该语言版本。详细信息请参见附录中的相关章节。
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, uppercase and lowercase letters
are different characters.
每个码位各不相同;例如,大写字母与小写字母属于不同字符。
Implementation restriction: For compatibility with other tools, a
compiler may disallow the NUL character (U+0000) in the source text.
实现限制:为与其他工具兼容,编译器可能不允许在源代码中出现 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.
实现限制:为兼容其他工具,若源文本首个 Unicode 码点为 UTF-8 编码的字节顺序标记(U+FEFF),编译器可忽略该标记。字节顺序标记在源文本其他位置可能不被允许。
Characters¶ 字符 ¶
The following terms are used to denote specific Unicode character categories:
以下术语用于表示特定 Unicode 字符类别:
newline = /* the Unicode code point U+000A */ . unicode_char = /* an arbitrary Unicode code point except newline */ . unicode_letter = /* a Unicode code point categorized as "Letter" */ . unicode_digit = /* a Unicode code point categorized as "Number, decimal digit" */ .
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 节"通用类别"中定义了一套字符分类体系。Go 语言将属于字母类别 Lu、Ll、Lt、Lm 或 Lo 的所有字符视为 Unicode 字母,而将数字类别 Nd 中的字符视为 Unicode 数字。
Letters and digits¶ 字母和数字 ¶
The underscore character _ (U+005F) is considered a lowercase letter.
下划线字符 _ (U+005F)被视为小写字母。
letter = unicode_letter | "_" . decimal_digit = "0" … "9" . binary_digit = "0" | "1" . octal_digit = "0" … "7" . hex_digit = "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)构成的空白字符会被忽略,除非它们用于分隔原本会组合成单一标记的词法单元。此外,换行符或文件结束符可能触发分号插入机制。在将输入分解为词法标记时,下一个词法标记始终是能构成有效标记的最长字符序列。
Semicolons¶ 分号 ¶
The formal syntax 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
关键词之一break、continue、fallthrough或return - 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"}".
为使复杂语句可占据单行,结尾的")"或"}"前的分号可省略。
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 } .
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
[Go 1.18]:
以下字符序列代表运算符(包括赋值运算符)和标点符号 [Go 1.18]:
+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^= ~
Integer literals¶ 整数字面量 ¶
An integer literal is a sequence of digits representing an
integer constant.
An optional prefix sets a non-decimal base: 0b or 0B
for binary, 0, 0o, or 0O for octal,
and 0x or 0X for hexadecimal
[Go 1.13].
A single 0 is considered a decimal zero.
In hexadecimal literals, letters a through f
and A through F represent values 10 through 15.
整数字面量是由一串数字组成的整数常量。可选前缀用于设定非十进制基数: 0b 或 0B 表示二进制, 0 、 0o 或 0O 表示八进制, 0x 或 0X 表示十六进制[Go 1.13]。单个 0 被视为十进制零。在十六进制字面量中,字母 a 至 f 以及 A 至 F 分别代表数值 10 至 15。
For readability, an underscore character _ may appear after
a base prefix or between successive digits; such underscores do not change
the literal's value.
为提升可读性,可在进制前缀后或连续数字间插入下划线字符 _ ;这些下划线不会改变字面量的数值。
int_lit = decimal_lit | binary_lit | octal_lit | hex_lit .
decimal_lit = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
binary_lit = "0" ( "b" | "B" ) [ "_" ] binary_digits .
octal_lit = "0" [ "o" | "O" ] [ "_" ] octal_digits .
hex_lit = "0" ( "x" | "X" ) [ "_" ] hex_digits .
decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
binary_digits = binary_digit { [ "_" ] binary_digit } .
octal_digits = octal_digit { [ "_" ] octal_digit } .
hex_digits = hex_digit { [ "_" ] hex_digit } .
42 4_2 0600 0_600 0o600 0O600 // second character is capital letter 'O' 0xBadFace 0xBad_Face 0x_67_7a_2f_cc_40_c6 170141183460469231731687303715884105727 170_141183_460469_231731_687303_715884_105727 _42 // an identifier, not an integer literal 42_ // invalid: _ must separate successive digits 4__2 // invalid: only one _ at a time 0_xBadFace // invalid: _ must separate successive digits
Floating-point literals¶
浮点数字面量 ¶
A floating-point literal is a decimal or hexadecimal representation of a
floating-point constant.
浮点数字面值是浮点常数的十进制或十六进制表示法。
A decimal floating-point literal consists of an integer part (decimal digits),
a decimal point, a fractional part (decimal digits), and an exponent part
(e or E followed by an optional sign and decimal digits).
One of the integer part or the fractional part may be elided; one of the decimal point
or the exponent part may be elided.
An exponent value exp scales the mantissa (integer and fractional part) by 10exp.
十进制浮点数字面值由整数部分(十进制数字)、小数点、小数部分(十进制数字)及指数部分( e 或 E 后接可选符号和十进制数字)组成。整数部分或小数部分可省略其一;小数点或指数部分可省略其一。指数值 exp 通过 10 exp 对尾数(整数和小数部分)进行缩放。
A hexadecimal floating-point literal consists of a 0x or 0X
prefix, an integer part (hexadecimal digits), a radix point, a fractional part (hexadecimal digits),
and an exponent part (p or P followed by an optional sign and decimal digits).
One of the integer part or the fractional part may be elided; the radix point may be elided as well,
but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.)
An exponent value exp scales the mantissa (integer and fractional part) by 2exp
[Go 1.13].
十六进制浮点数字面值由 0x 或 0X 前缀、整数部分(十六进制数字)、小数点、小数部分(十六进制数字)及指数部分( p 或 P 后接可选符号和十进制数字)组成。整数部分或小数部分可省略其一;小数点亦可省略,但指数部分必须保留。(该语法符合 IEEE 754-2008 标准第 5.12.3 节定义。)指数值 exp 通过 2 的 exp 次方对尾数(整数和小数部分)进行缩放[Go 1.13]。
For readability, an underscore character _ may appear after
a base prefix or between successive digits; such underscores do not change
the literal value.
为提高可读性,基数前缀后或连续数字之间可能出现下划线字符 _ ;此类下划线不会改变字面值。
float_lit = decimal_float_lit | hex_float_lit .
decimal_float_lit = decimal_digits "." [ decimal_digits ] [ decimal_exponent ] |
decimal_digits decimal_exponent |
"." decimal_digits [ decimal_exponent ] .
decimal_exponent = ( "e" | "E" ) [ "+" | "-" ] decimal_digits .
hex_float_lit = "0" ( "x" | "X" ) hex_mantissa hex_exponent .
hex_mantissa = [ "_" ] hex_digits "." [ hex_digits ] |
[ "_" ] hex_digits |
"." hex_digits .
hex_exponent = ( "p" | "P" ) [ "+" | "-" ] decimal_digits .
0. 72.40 072.40 // == 72.40 2.71828 1.e+0 6.67428e-11 1E6 .25 .12345E+5 1_5. // == 15.0 0.15e+0_2 // == 15.0 0x1p-2 // == 0.25 0x2.p10 // == 2048.0 0x1.Fp+0 // == 1.9375 0X.8p-0 // == 0.5 0X_1FFFP-16 // == 0.1249847412109375 0x15e-2 // == 0x15e - 2 (integer subtraction) 0x.p1 // invalid: mantissa has no digits 1p-2 // invalid: p exponent requires hexadecimal mantissa 0x1.5e-2 // invalid: hexadecimal mantissa requires p exponent 1_.5 // invalid: _ must separate successive digits 1._5 // invalid: _ must separate successive digits 1.5_e1 // invalid: _ must separate successive digits 1.5e_1 // invalid: _ must separate successive digits 1.5e1_ // invalid: _ must separate successive digits
Imaginary literals¶ 虚数字面量 ¶
An imaginary literal represents the imaginary part of a
complex constant.
It consists of an integer or
floating-point literal
followed by the lowercase letter i.
The value of an imaginary literal is the value of the respective
integer or floating-point literal multiplied by the imaginary unit i
[Go 1.13]
虚数字面量表示复数常量的虚部部分,由一个整数或浮点数字面量后跟小写字母 i 组成。虚数字面量的值等于相应整数或浮点数字面量的值乘以虚数单位 i[Go 1.13]。
imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .
For backward compatibility, an imaginary literal's integer part consisting
entirely of decimal digits (and possibly underscores) is considered a decimal
integer, even if it starts with a leading 0.
为向后兼容,虚数字面量的整数部分即使以 0 开头,只要完全由十进制数字(可能包含下划线)组成,仍被视为十进制整数。
0i 0123i // == 123i for backward-compatibility 0o123i // == 0o123 * 1i == 83i 0xabci // == 0xabc * 1i == 2748i 0.i 2.71828i 1.e+0i 6.67428e-11i 1E6i .25i .12345E+5i 0x1p-2i // == 0x1p-2 * 1i == 0.25i
Rune literals¶ rune 字面量¶
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 码点的整数值。符文字面量由单引号包裹的一个或多个字符构成,例如 '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.
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)
An unrecognized character following a backslash in a rune literal is illegal.
在 rune 字面值中,反斜杠后跟随不被识别的字符是非法的。
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 '\k' // illegal: k is not recognized after a backslash '\xa' // illegal: too few hexadecimal digits '\0' // illegal: too few octal digits '\400' // illegal: octal value over 255 '\uDFFF' // illegal: surrogate half '\U00110000' // illegal: invalid Unicode code point
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, as in
`foo`. Within the quotes, any character may appear 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.
原始字符串字面量是位于反引号之间的字符序列,例如 `foo` 。引号内可出现除反引号外的任意字符。其值是由引号间未解析(隐式 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 (\xnn) 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.
解释型字符串字面值是双引号内的字符序列,例如 "bar" 。引号内除换行符和未转义的双引号外,可包含任意字符。引号间的文本构成字面值内容,其中反斜杠转义规则与符文字面值相同(但 \' 非法而 \" 合法),且遵循相同限制。三位八进制转义( \ nnn)和两位十六进制转义( \x nn)代表结果字符串的单个字节;其余转义则代表单个字符的(可能是多字节的)UTF-8 编码。因此在字符串字面值中, \377 和 \xFF 表示单个字节值 0xFF =255,而 ÿ 、 \u00FF 、 \U000000FF 及 \xc3\xbf 则代表字符 U+00FF 的 UTF-8 编码双字节 0xc3 0xbf 。
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
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
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.
若源代码用两个码点表示一个字符(例如涉及重音符号和字母的组合形式),当将其置于 rune 字面量时将引发错误(因非单一码点),而在字符串字面量中则会显示为两个码点。
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
min or max applied to constant arguments,
unsafe.Sizeof applied to certain values,
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.
常量值可由符文、整数、浮点数、虚数或字符串字面量表示,也可由表示常量的标识符、常量表达式、结果为常量的类型转换、或某些内置函数作用于常量参数的结果值构成(例如作用于常量参数的 min 或 max ,作用于特定值的 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 statement or as an
operand in an expression.
It is an error if the constant value
cannot be represented as a value of the respective type.
If the type is a type parameter, the constant is converted into a non-constant
value of the type parameter.
常量可通过常量声明或转换显式指定类型,也可在变量声明、赋值语句或作为表达式操作数时隐式赋予类型。若常量值无法表示为相应类型的值,则视为错误。若类型为类型参数,则该常量会被转换为该类型参数的非常量值。
An untyped constant has a default type which is the type to which the
constant is implicitly converted in contexts where a typed value is required,
for instance, in a short variable declaration
such as 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.
使用至少 256 位表示整数常量。 - 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.
使用至少 256 位的尾数和至少 16 位的带符号二进制指数来表示浮点型常量,包括复数常量的组成部分。 - 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.
这些要求既适用于字面常量,也适用于常量表达式求值的结果。
Variables¶ 变量 ¶
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 (non-interface) 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
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.
变量的值通过在表达式中引用该变量来获取,即该变量最新被赋予的值。若变量尚未赋值,则其值为该变量类型的零值。
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, which must be
followed by type arguments if the type is generic.
A type may also be specified using a type literal, which composes a type
from existing types.
类型决定了一组值以及特定于这些值的操作和方法。若类型具有名称,则可通过类型名表示,且若为泛型,类型名后必须跟随类型实参。类型也可通过类型字面量来指定,该字面量通过组合现有类型构成新类型。
Type = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
TypeName = identifier | QualifiedIdent .
TypeArgs = "[" TypeList [ "," ] "]" .
TypeList = Type { "," Type } .
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
SliceType | MapType | ChannelType .
The language predeclares certain type names.
Others are introduced with type declarations
or type parameter lists.
Composite types—array, struct, pointer, function,
interface, slice, map, and channel types—may be constructed using
type literals.
语言预声明了某些类型名称,其余类型则通过类型声明或类型形参列表引入。复合类型——数组、结构体、指针、函数、接口、切片、映射和信道类型——可通过类型字面量构建。
Predeclared types, defined types, and type parameters are called named types.
An alias denotes a named type if the type given in the alias declaration is a named type.
预声明类型、定义类型和类型参数统称为命名类型。若别名声明中指定的类型为命名类型,则该别名表示一个命名类型。
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¶ 数值类型 ¶
An integer, floating-point, or complex type
represents the set of integer, floating-point, or complex values, respectively.
They are collectively called numeric types.
The predeclared architecture-independent numeric types are:
整数、浮点数或复数类型分别表示整数、浮点数或复数值的集合。它们统称为数值类型。预声明的与体系结构无关的数值类型包括:
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
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 integer 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
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.
Explicit 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.
The number of bytes is called the length of the string and is never negative.
Strings are immutable: once created,
it is impossible to change the contents of a string.
The predeclared string type is string;
it is a defined type.
字符串类型表示字符串值的集合。字符串值是一个(可能为空的)字节序列。字节数称为字符串长度,该值永不为负。字符串是不可变的:一旦创建,便无法更改其内容。预声明的字符串类型为 string ;它是一个已定义的类型。
The length of a string s 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 of the array 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.
长度是数组类型的一部分,其计算结果必须是 int 类型所能表示的非负常量。数组 a 的长度可通过内置函数 len 获取。数组元素可以使用 0 到 len(a)-1 的整数索引进行寻址。数组类型始终是一维的,但可组合成多维类型。
[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64 // same as [2]([2]([2]float64))
An array type T may not have an element of type T,
or of a type containing T as a component, directly or indirectly,
if those containing types are only array or struct types.
数组类型 T 不可直接或间接包含类型为 T 的元素,亦不可包含以 T 作为组件的类型,前提是这些包含类型仅为数组或结构体类型。
// invalid array types
type (
T1 [10]T1 // element type of T1 is T1
T2 [10]struct{ f T2 } // T2 contains T2 as component of a struct
T3 [10]T4 // T3 contains T3 as component of a struct in T4
T4 struct{ f T3 } // T4 contains T4 as component of array T3 in a struct
)
// valid array types
type (
T5 [10]*T5 // T5 contains T5 as component of a pointer
T6 [10]func() T6 // T6 contains T6 as component of a function type
T7 [10]struct{ f []T7 } // T7 contains T7 as component of a slice in a struct
)
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 number of elements is called the length of the slice and is never negative.
The value of an uninitialized slice is nil.
切片是底层数组中一段连续片段的描述符,提供了对该数组中一系列有序元素的访问。切片类型表示其元素类型数组的所有切片的集合。元素数量称为切片的长度,永不为负。未初始化的切片值为 nil 。
SliceType = "[" "]" ElementType .
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 may be
made using the built-in function
make,
which takes a slice type
and parameters specifying the length and optionally the capacity.
A slice created with make always allocates a new, hidden array
to which the returned slice value refers. That is, executing
对于给定元素类型 T 的新初始化切片值,可通过内置函数 make 创建。该函数接收切片类型及指定长度的参数,并可选择性地指定容量。使用 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.
结构体是由一系列具名字段组成的序列,每个字段包含名称和类型。字段名可通过显式声明(IdentifierList)或隐式声明(EmbeddedField)指定。在结构体中,非空字段名必须保持唯一。
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName [ TypeArgs ] .
Tag = string_lit .
// An empty struct.
struct {}
// A struct with 6 fields.
struct {
x, y int
u float32
_ float32 // padding
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 or type parameter. The unqualified type name acts as the field name.
声明了类型但无显式字段名的字段称为嵌入式字段。嵌入式字段必须指定为类型名称 T 或指向非接口类型名称 *T 的指针,且 T 其本身不能是指针类型或类型参数。该非限定类型名将作为字段名。
// 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
}
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
}
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 中嵌入式字段的字段或方法 f 被称为提升字段或方法,当 x.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 type name
T, promoted methods are included in the method set of the struct as follows:
给定结构体类型 S 和类型名称 T 时,提升方法将按以下方式包含在结构体的方法集中:
-
If
Scontains an embedded fieldT, the method sets ofSand*Sboth include promoted methods with receiverT. The method set of*Salso includes promoted methods with receiver*T.
若S包含内嵌字段T,则S和*S的方法集都包含接收者为T的提升方法。*S的方法集还包含接收者为*T的提升方法。 -
If
Scontains an embedded field*T, the method sets ofSand*Sboth include promoted methods with receiverTor*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"`
}
A struct type T may not contain a field of type T,
or of a type containing T as a component, directly or indirectly,
if those containing types are only array or struct types.
当包含类型仅为数组或结构体类型时,结构体类型 T 可能不得直接或间接包含类型为 T 的字段,或包含以 T 为组成部分的类型字段。
// invalid struct types
type (
T1 struct{ T1 } // T1 contains a field of T1
T2 struct{ f [10]T2 } // T2 contains T2 as component of an array
T3 struct{ T4 } // T3 contains T3 as component of an array in struct T4
T4 struct{ f [10]T3 } // T4 contains T4 as component of struct T3 in an array
)
// valid struct types
type (
T5 struct{ f *T5 } // T5 contains T5 as component of a pointer
T6 struct{ f func() T6 } // T6 contains T6 as component of a function type
T7 struct{ f [10][]T7 } // T7 contains T7 as component of a slice in an array
)
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.
指针类型表示指向给定类型(称为指针的基类型)变量的所有指针集合。未初始化的指针值为 nil 。
PointerType = "*" BaseType . BaseType = Type .
*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.
函数类型表示具有相同参数和结果类型的所有函数的集合。未初始化的函数类型变量的值为 nil 。
FunctionType = "func" Signature .
Signature = Parameters [ Result ] .
Result = Parameters | Type .
Parameters = "(" [ ParameterList [ "," ] ] ")" .
ParameterList = ParameterDecl { "," ParameterDecl } .
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
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 defines a type set.
A variable of interface type can store a value of any type that is in the type
set of the interface. Such a type is said to
implement the interface.
The value of an uninitialized variable of
interface type is nil.
接口类型定义了一个类型集合。接口类型的变量可以存储属于该接口类型集合中任意类型的值。这样的类型被称为实现了该接口。未初始化的接口类型变量的值是 nil 。
InterfaceType = "interface" "{" { InterfaceElem ";" } "}" .
InterfaceElem = MethodElem | TypeElem .
MethodElem = MethodName Signature .
MethodName = identifier .
TypeElem = TypeTerm { "|" TypeTerm } .
TypeTerm = Type | UnderlyingType .
UnderlyingType = "~" Type .
An interface type is specified by a list of interface elements.
An interface element is either a method or a type element,
where a type element is a union of one or more type terms.
A type term is either a single type or a single underlying type.
接口类型由一组接口元素指定。接口元素可以是方法或类型元素,其中类型元素是一个或多个类型项的联合体。类型项可以是单一类型或单一基础类型。
Basic interfaces¶ 基本接口 ¶
In its most basic form an interface specifies a (possibly empty) list of methods.
The type set defined by such an interface is the set of types which implement all of
those methods, and the corresponding method set consists
exactly of the methods specified by the interface.
Interfaces whose type sets can be defined entirely by a list of methods are called
basic interfaces.
在最基本的形式中,接口规定了(可能为空的)方法列表。该接口定义的类型集是实现了所有这些方法的类型集合,其对应的方法集仅由接口指定的方法组成。其类型集可完全通过方法列表定义的接口称为基本接口。
// A simple File interface.
interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
Close() error
}
The name of each explicitly specified method must be unique
and not blank.
每个显式指定的方法名称必须唯一且非空。
interface {
String() string
String() string // illegal: String not unique
_(x int) // illegal: method must have non-blank name
}
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(p []byte) (n int, err error) func (p T) Write(p []byte) (n int, err error) func (p T) Close() error
(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 可能拥有或共享何种其他方法。
Every type that is a member of the type set of an interface implements that interface.
Any given type may implement several distinct interfaces.
For instance, all types implement the empty interface which stands for the set
of all (non-interface) types:
每个属于接口类型集的类型都实现了该接口。任何给定类型可实现多个不同的接口。例如,所有类型都实现了代表所有(非接口)类型集合的空接口:
interface{}
For convenience, the predeclared type any is an alias for the empty interface.
[Go 1.18]
为方便起见,预声明类型 any 是空接口的别名。[Go 1.18]
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 接口。
Embedded interfaces¶ 嵌入式接口 ¶
In a slightly more general form
an interface T may use a (possibly qualified) interface type
name E as an interface element. This is called
embedding interface E in T
[Go 1.14].
The type set of T is the intersection of the type sets
defined by T's explicitly declared methods and the type sets
of T’s embedded interfaces.
In other words, the type set of T is the set of all types that implement all the
explicitly declared methods of T and also all the methods of
E
[Go 1.18].
在稍具通用性的形式中,接口 T 可将(可能经过限定的)接口类型名称 E 作为接口元素使用。这被称为在 T 中嵌入接口 E [Go 1.14]。 T 的类型集合是由 T 显式声明方法所定义的型集与 T 嵌入接口的类型集合的交集。换言之, T 的类型集合是实现 T 所有显式声明方法以及 E 所有方法的类型组成的集合[Go 1.18]。
type Reader interface {
Read(p []byte) (n int, err error)
Close() error
}
type Writer interface {
Write(p []byte) (n int, err error)
Close() error
}
// ReadWriter's methods are Read, Write, and Close.
type ReadWriter interface {
Reader // includes methods of Reader in ReadWriter's method set
Writer // includes methods of Writer in ReadWriter's method set
}
When embedding interfaces, methods with the
same names must
have identical signatures.
嵌入接口时,同名方法必须具有完全一致的签名。
type ReadCloser interface {
Reader // includes methods of Reader in ReadCloser's method set
Close() // illegal: signatures of Reader.Close and Close are different
}
General interfaces¶ 通用接口 ¶
In their most general form, an interface element may also be an arbitrary type term
T, or a term of the form ~T specifying the underlying type T,
or a union of terms t1|t2|…|tn
[Go 1.18].
Together with method specifications, these elements enable the precise
definition of an interface's type set as follows:
接口元素最通用的形式可以是任意类型术语 T ,或指定基础类型 T 的 ~T 形式术语,或类型的联合 t1|t2|…|tn [Go 1.18]。结合方法规约,这些元素能精确定义接口的类型集合:
- The type set of the empty interface is the set of all non-interface types.
空接口的类型集合是所有非接口类型的集合。 - The type set of a non-empty interface is the intersection of the type sets
of its interface elements.
非空接口的类型集合是其接口元素类型集合的交集。 - The type set of a method specification is the set of all non-interface types
whose method sets include that method.
方法规范的型别集是指所有方法集包含该方法的非接口类型的集合。 - The type set of a non-interface type term is the set consisting
of just that type.
非接口类型项的类型集是仅包含该类型的集合。 - The type set of a term of the form
~Tis the set of all types whose underlying type isT.
形式项~T的类型集合是所有底层类型为T的类型的集合。 - The type set of a union of terms
t1|t2|…|tnis the union of the type sets of the terms.
项的并集t1|t2|…|tn的类型集即为各项类型集的并集。
The quantification "the set of all non-interface types" refers not just to all (non-interface)
types declared in the program at hand, but all possible types in all possible programs, and
hence is infinite.
Similarly, given the set of all non-interface types that implement a particular method, the
intersection of the method sets of those types will contain exactly that method, even if all
types in the program at hand always pair that method with another method.
量化表述“所有非接口类型的集合”不仅指当前程序中声明的所有(非接口)类型,还涵盖所有可能程序中的所有可能类型,因此该集合是无限的。同理,给定实现了特定方法的所有非接口类型集合时,这些类型的方法集交集将精确包含该方法——即便当前程序中所有类型总是将该方法与另一方法搭配使用。
By construction, an interface's type set never contains an interface type.
根据构造,一个接口的类型集合永远不会包含接口类型。
// An interface representing only the type int.
interface {
int
}
// An interface representing all types with underlying type int.
interface {
~int
}
// An interface representing all types with underlying type int that implement the String method.
interface {
~int
String() string
}
// An interface representing an empty type set: there is no type that is both an int and a string.
interface {
int
string
}
In a term of the form ~T, the underlying type of T
must be itself, and T cannot be an interface.
在 ~T 形式的项中, T 的基础类型必须为其自身,且 T 不能是接口。
type MyInt int
interface {
~[]byte // the underlying type of []byte is itself
~MyInt // illegal: the underlying type of MyInt is not MyInt
~error // illegal: error is an interface
}
Union elements denote unions of type sets:
联合元素表示类型集合的联合:
// The Float interface represents all floating-point types
// (including any named types whose underlying types are
// either float32 or float64).
type Float interface {
~float32 | ~float64
}
The type T in a term of the form T or ~T cannot
be a type parameter, and the type sets of all
non-interface terms must be pairwise disjoint (the pairwise intersection of the type sets must be empty).
Given a type parameter P:
类型 T 在形式为 T 或 ~T 的项中不能是类型参数,且所有非接口项的类型集合必须两两不相交(类型集合的两两交集必须为空集)。给定类型参数 P :
interface {
P // illegal: P is a type parameter
int | ~P // illegal: P is a type parameter
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
float32 | Float // overlapping type sets but Float is an interface
}
Implementation restriction:
A union (with more than one term) cannot contain the
predeclared identifier comparable
or interfaces that specify methods, or embed comparable or interfaces
that specify methods.
实现限制:包含多个项的联合类型不能含有预声明标识符 comparable 或指定方法的接口,也不能嵌入 comparable 或指定方法的接口。
Interfaces that are not basic may only be used as type
constraints, or as elements of other interfaces used as constraints.
They cannot be the types of values or variables, or components of other,
non-interface types.
非基本接口只能用作类型约束,或作为其他用作约束的接口的组成部分。它们不能是值或变量的类型,也不能成为其他非接口类型的组成部分。
var x Float // illegal: Float is not a basic interface
var x interface{} = Float(nil) // illegal
type Floatish struct {
f Float // illegal
}
An interface type T may not embed a type element
that is, contains, or embeds T, directly or indirectly.
接口类型 T 不可直接或间接嵌入一个本身是、包含或嵌入 T 的类型元素。
// illegal: Bad may not embed itself
type Bad interface {
Bad
}
// illegal: Bad1 may not embed itself using Bad2
type Bad1 interface {
Bad2
}
type Bad2 interface {
Bad1
}
// illegal: Bad3 may not embed a union containing Bad3
type Bad3 interface {
~int | ~string | Bad3
}
// illegal: Bad4 may not embed an array containing Bad4 as element type
type Bad4 interface {
[10]Bad4
}
Implementing an interface¶
实现接口¶
A type T implements an interface I if
类型 T 实现接口 I 如果
-
Tis not an interface and is an element of the type set ofI; or
T不是接口,且是I类型集合的元素;或 -
Tis an interface and the type set ofTis a subset of the type set ofI.
T是一个接口,且T的类型集合是I类型集合的子集。
A value of type T implements an interface if T
implements the interface.
当 T 实现该接口时, T 类型的值即实现该接口。
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.
map 是一种无序集合,其元素为同一种类型(称为元素类型),由一组唯一键(称为键类型)索引。未初始化的 map 值为 nil 。
MapType = "map" "[" KeyType "]" ElementType . KeyType = Type .
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 and
clear built-in function.
映射元素的数量称为其长度。对于映射 m ,可通过内置函数 len 发现其长度,该值可能在执行期间改变。执行期间可通过赋值添加元素,并使用索引表达式检索元素;也可通过内置函数 delete 和 clear 移除元素。
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 映射表等同于空映射表,只是不可添加任何元素。
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.
通道为并发执行的函数提供了一种机制,通过发送和接收特定元素类型的值进行通信。未初始化的通道值为 nil 。
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
The optional <- operator specifies the channel direction,
send or receive. If a direction is given, the channel is directional,
otherwise it is bidirectional.
A channel may be constrained only to send or only to receive by
assignment or
explicit conversion.
可选操作符 <- 用于指定通道方向:发送或接收。若指定方向,则通道为定向;否则为双向。通过赋值或显式转换,可约束通道仅发送或仅接收。
chan T // can be used to send and receive values of type T chan<- float64 // can only be used to send float64s <-chan int // can only be used to receive ints
The <- operator associates with the leftmost chan
possible:
<- 运算符与最左侧可能的 chan 关联:
chan<- chan int // same as chan<- (chan int) chan<- <-chan int // same as chan<- (<-chan int) <-chan <-chan int // same as <-chan (<-chan int) chan (<-chan int)
A new, initialized channel
value can be made using the built-in function
make,
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.
单个通道可在无需额外同步的情况下,被任意数量的 goroutine 用于发送语句、接收操作以及调用内置函数 cap 和 len 。通道以先进先出队列的形式运作。例如,若一个 goroutine 在通道上发送数据,另一个 goroutine 接收这些数据,则数据的接收顺序与发送顺序相同。
Properties of types and values¶
类型和值的属性 ¶
Representation of values¶
值的表示 ¶
Values of predeclared types (see below for the interfaces any
and error), arrays, and structs are self-contained:
Each such value contains a complete copy of all its data,
and variables of such types store the entire value.
For instance, an array variable provides the storage (the variables)
for all elements of the array.
The respective zero values are specific to the
value's types; they are never nil.
预声明类型(参见下文接口 any 和 error )、数组及结构体的值具有自包含性:每个此类值均包含其所有数据的完整副本,且对应类型的变量存储的是完整值。例如,数组变量为数组所有元素提供存储(即变量)。相应的零值由值的类型决定,它们绝不会是 nil 。
Non-nil pointer, function, slice, map, and channel values contain references
to underlying data which may be shared by multiple values:
非空指针、函数、切片、映射和通道值包含对可能被多个值共享的底层数据的引用
-
A pointer value is a reference to the variable holding
the pointer base type value.
指针值是对持有指针基类型值的变量的引用。 -
A function value contains references to the (possibly
anonymous) function
and enclosed variables.
函数值包含对(可能是匿名)函数及封闭变量的引用。 -
A slice value contains the slice length, capacity, and
a reference to its underlying array.
切片值包含切片长度、容量以及对其底层数组的引用。 -
A map or channel value is a reference to the implementation-specific
data structure of the map or channel.
映射或信道值是指向具体实现的映射或信道数据结构的引用。
An interface value may be self-contained or contain references to underlying data
depending on the interface's dynamic type.
The predeclared identifier nil is the zero value for types whose values
can contain references.
接口值可以是自包含的,也可以包含对底层数据的引用,具体取决于接口的动态类型。预声明标识符 nil 是其值可包含引用的类型的零值。
When multiple values share underlying data, changing one value may change another.
For instance, changing an element of a slice will change
that element in the underlying array for all slices that share the array.
当多个值共享底层数据时,修改其中一个值可能会影响另一个值。例如,修改切片的某个元素会改变底层数组中该元素的值,从而影响所有共享该数组的切片。
Underlying types¶ 基础类型 ¶
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 declaration.
For a type parameter that is the underlying type of its
type constraint, which is always an interface.
每种类型 T 都有一个底层类型:若 T 属于预声明的布尔、数值或字符串类型之一,或是类型字面量,则其对应的底层类型为 T 自身。否则, T 的底层类型即其声明所指类型的底层类型。对于类型参数而言,其底层类型是其类型约束(总是一个接口)的底层类型。
type (
A1 = string
A2 = A1
)
type (
B1 string
B2 B1
B3 []B1
B4 B3
)
func f[P any](x P) { … }
The underlying type of string, A1, A2, B1,
and B2 is string.
The underlying type of []B1, B3, and B4 is []B1.
The underlying type of P is interface{}.
string 、 A1 、 A2 、 B1 及 B2 的基础类型为 string 。 []B1 、 B3 和 B4 的基础类型为 []B1 。 P 的基础类型为 interface{} 。
Core types¶ 核心类型 ¶
Each non-interface type T has a core type, which is the same as the
underlying type of T.
每个非接口类型 T 都有一个核心类型,该核心类型与 T 的底层类型相同。
An interface T has a core type if one of the following
conditions is satisfied:
接口 T 在满足以下任一条件时具有核心类型:
-
There is a single type
Uwhich is the underlying type of all types in the type set ofT; or
存在单一类型U,它是T的类型集合中所有类型的基础类型;或者 -
the type set of
Tcontains only channel types with identical element typeE, and all directional channels have the same direction.
类型集合T仅包含元素类型E相同的通道类型,并且所有定向通道的方向均一致。
No other interfaces have a core type.
其他接口均不具备核心类型。
The core type of an interface is, depending on the condition that is satisfied, either:
接口的核心类型取决于所满足的条件,要么是:
-
the type
U; or
类型U; 或 -
the type
chan EifTcontains only bidirectional channels, or the typechan<- Eor<-chan Edepending on the direction of the directional channels present.
如果T仅包含双向通道,则为类型chan E;若存在定向通道,则根据其方向选择类型chan<- E或<-chan E。
By definition, a core type is never a defined type,
type parameter, or
interface type.
根据定义,核心类型永远不会是定义类型、类型参数或接口类型。
Examples of interfaces with core types:
核心类型接口示例:
type Celsius float32
type Kelvin float32
interface{ int } // int
interface{ Celsius|Kelvin } // float32
interface{ ~chan int } // chan int
interface{ ~chan int|~chan<- int } // chan<- int
interface{ ~[]*data; String() string } // []*data
Examples of interfaces without core types:
不包含核心类型的接口示例:
interface{} // no single underlying type
interface{ Celsius|float64 } // no single underlying type
interface{ chan int | chan<- string } // channels have different element types
interface{ <-chan int | chan<- int } // directional channels have different directions
Some operations (slice expressions,
append and copy)
rely on a slightly more loose form of core types which accept byte slices and strings.
Specifically, if there are exactly two types, []byte and string,
which are the underlying types of all types in the type set of interface T,
the core type of T is called bytestring.
某些操作(切片表达式、 append 和 copy )依赖于一种略宽松的核心类型形式,该形式接受字节切片和字符串。具体而言,若恰好存在两种类型 []byte 和 string ,它们作为接口 T 类型集中所有类型的底层类型,则称 T 的核心类型为 bytestring 。
Examples of interfaces with bytestring core types:
bytestring 核心类型的接口示例:
interface{ int } // int (same as ordinary core type)
interface{ []byte | string } // bytestring
interface{ ~[]byte | myString } // bytestring
Note that bytestring is not a real type; it cannot be used to declare
variables or compose other types. It exists solely to describe the behavior of some
operations that read from a sequence of bytes, which may be a byte slice or a string.
请注意 bytestring 并非真实类型;它不能用于声明变量或组合其他类型。其存在仅用于描述某些操作的行为,这些操作从字节序列中读取数据,该序列可能是一个字节切片或字符串。
Type identity¶ 类型同一性 ¶
Two types are either identical or different.
两种类型要么相同,要么不同。
A named type is always different from any other type.
Otherwise, two types are identical if their underlying type literals are
structurally equivalent; that is, they have the same literal structure and corresponding
components have identical types. In detail:
命名类型始终不同于其他任何类型。否则,若两个类型的基础类型字面量在结构上等价,则它们是相同的;即具有相同的字面结构且对应组件类型一致。具体而言:
- 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 pairs of fields have the same names, identical types,
and identical tags, and are either both embedded or both not embedded.
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 define the same type set.
如果两个接口类型定义了相同的类型集,那么它们是相同的。 - 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.
当两个通道类型具有相同的元素类型和方向时,它们被视为相同。 - Two instantiated types are identical if
their defined types and all type arguments are identical.
如果两个实例化类型的定义类型及其所有类型参数都相同,则它们是相同的。
Given the declarations 根据以下声明
type (
A0 = []string
A1 = A0
A2 = struct{ a, b int }
A3 = int
A4 = func(A3, float64) *A0
A5 = func(x int, _ float64) *[]string
B0 A0
B1 []string
B2 struct{ a, b int }
B3 struct{ a, c int }
B4 func(int, float64) *B0
B5 func(x int, y float64) *A1
C0 = B0
D0[P1, P2 any] struct{ x P1; y P2 }
E0 = D0[int, string]
)
these types are identical:
这些类型是相同的:
A0, A1, and []string
A2 and struct{ a, b int }
A3 and int
A4, func(int, float64) *[]string, and A5
B0 and C0
D0[int, string] and E0
[]int and []int
struct{ a, b *B5 } and struct{ a, b *B5 }
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5
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;
and P1 and P2 are different because they are different
type parameters.
D0[int, string] and struct{ x int; y string } are
different because the former is an instantiated
defined type while the latter is a type literal
(but they are still assignable).
B0 和 B1 不同,因为它们是由不同类型定义创建的新类型; func(int, float64) *B0 和 func(x int, y float64) *[]string 不同,因为 B0 与 []string 不同;而 P1 和 P2 不同,因为它们属于不同的类型参数。 D0[int, string] 和 struct{ x int; y string } 不同,因为前者是实例化的已定义类型,而后者是类型字面量(但两者仍可相互赋值)。
Assignability¶ 可转让性 ¶
A value x of type V is assignable to a variable of type T
("x is assignable to T") if one of the following conditions applies:
一个类型为 V 的值 x 可赋值给类型为 T 的变量(" x 可赋值给 T "),如果满足以下任一条件:
-
VandTare identical.
V和T相同 -
VandThave identical underlying types but are not type parameters and at least one ofVorTis not a named type.
V和T具有相同的底层类型,但它们并非类型参数,且V或T中至少有一个不是命名类型。 -
VandTare channel types with identical element types,Vis a bidirectional channel, and at least one ofVorTis not a named type.
V和T是元素类型相同的通道类型,V为双向通道,且V或T中至少有一个不是命名类型。 -
Tis an interface type, but not a type parameter, andximplementsT.
T是接口类型,但并非类型参数,而x实现了T。 -
xis the predeclared identifiernilandTis a pointer, function, slice, map, channel, or interface type, but not a type parameter.
x是预声明标识符nil,而T是指针、函数、切片、映射、通道或接口类型,而非类型参数。 -
xis an untyped constant representable by a value of typeT.
x是一个可由T类型的值表示的无类型常量。
Additionally, if x's type V or T are type parameters, x
is assignable to a variable of type T if one of the following conditions applies:
此外,若 x 的类型 V 或 T 为类型参数,则当满足以下任一条件时, x 可赋值给 T 类型的变量:
-
xis the predeclared identifiernil,Tis a type parameter, andxis assignable to each type inT's type set.
x是预声明的标识符nil,T是类型参数,且x可赋值给T类型集合中的每个类型。 -
Vis not a named type,Tis a type parameter, andxis assignable to each type inT's type set.
V不是命名类型,T是类型参数,而x可赋值给T类型集合中的每种类型。 -
Vis a type parameter andTis not a named type, and values of each type inV's type set are assignable toT.
V是类型参数,T不是命名类型,且V类型集合中每个类型的值均可赋值给T。
Representability¶ 可表示性 ¶
A constant x is representable
by a value of type T,
where T is not a type parameter,
if one of the following conditions applies:
若满足以下任一条件,则常量 x 可由类型 T 的值表示,其中 T 不是类型参数:
-
xis in the set of values determined byT.
x位于由T所确定的值集中。 -
Tis a floating-point type andxcan 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是浮点类型,x可舍入至T精度而不溢出。舍入遵循 IEEE 754 向偶数舍入规则,但 IEEE 负零会被简化为无符号零。需注意常量值永远不会产生 IEEE 负零、NaN 或无穷大。 -
Tis a complex type, andx's componentsreal(x)andimag(x)are representable by values ofT's component type (float32orfloat64).
T是一种复杂类型,其组件real(x)和imag(x)可通过T的组件类型(float32或float64)的值来表示。
If T is a type parameter,
x is representable by a value of type T if x is representable
by a value of each type in T's type set.
如果 T 是类型参数,当 T 的类型集中的每个类型均可由 x 的值表示时, x 可由 T 类型的值表示。
x T x is representable by a value of T because 'a' byte 97 is in the set of byte values 97 rune rune is an alias for int32, and 97 is in the set of 32-bit integers "foo" string "foo" is in the set of string values 1024 int16 1024 is in the set of 16-bit integers 42.0 byte 42 is in the set of unsigned 8-bit integers 1e10 uint64 10000000000 is in the set of unsigned 64-bit integers 2.718281828459045 float32 2.718281828459045 rounds to 2.7182817 which is in the set of float32 values -1e-1000 float64 -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0 0i int 0 is an integer value (42 + 0i) float32 42.0 (with zero imaginary part) is in the set of float32 values
x T x is not representable by a value of T because 0 bool 0 is not in the set of boolean values 'a' string 'a' is a rune, it is not in the set of string values 1024 byte 1024 is not in the set of unsigned 8-bit integers -1 uint16 -1 is not in the set of unsigned 16-bit integers 1.1 int 1.1 is not an integer value 42i float32 (0 + 42i) is not in the set of float32 values 1e1000 float64 1e1000 overflows to IEEE +Inf after rounding
Method sets¶ 方法集 ¶
The method set of a type determines the methods that can be
called on an operand of that type.
Every type has a (possibly empty) method set associated with it:
一个类型的方法集决定了可调用该类型操作数的方法。每个类型都有一个(可能为空的)与之关联的方法集:
- The method set of a defined type
Tconsists of all methods declared with receiver typeT.
定义类型T的方法集包含所有声明其接收者类型为T的方法。 -
The method set of a pointer to a defined type
T(whereTis neither a pointer nor an interface) is the set of all methods declared with receiver*TorT.
指向定义类型T的指针的方法集(其中T既非指针也非接口)是所有声明时接收者为*T或T的方法的集合。 - The method set of an interface type is the intersection
of the method sets of each type in the interface's type set
(the resulting method set is usually just the set of declared methods in the interface).
接口类型的方法集是该接口的类型集合中每个类型的方法集的交集(其结果方法集通常就是该接口中声明的方法集)。
Further rules apply to structs (and pointer to structs) containing embedded fields,
as described in the section on struct types.
Any other type has an empty method set.
对于包含嵌入字段的结构体(及结构体指针),适用进一步规则,详见结构体类型章节。其他任何类型均拥有空方法集。
In a method set, each method must have a
unique
non-blank method name.
在方法集中,每个方法必须拥有唯一且非空的方法名。
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.
全局块包含所有 Go 源代码。 - Each package has a package block containing all
Go source text for that package.
每个包都有一个包块,其中包含该包的所有 Go 源代码文本。 - Each file has a file block containing all Go source text
in that file.
每个文件都有一个文件块,其中包含该文件中的所有 Go 源代码文本。 - Each "if",
"for", and
"switch"
statement is considered to be in its own implicit block.
每个"if"、"for"和"switch"语句都被视为位于其自身的隐式块中。 - Each clause in a "switch"
or "select" statement
acts as an implicit block.
在“switch”或“select”语句中,每个子句都相当于一个隐式代码块。
Blocks nest and influence scoping.
块会嵌套并影响作用域。
Declarations and scope¶ 声明和作用域 ¶
A declaration binds a non-blank identifier to a
constant,
type,
type parameter,
variable,
function,
label, or
package.
Every identifier in a program must be declared.
No identifier may be declared twice in the same block, and
no identifier may be declared in both the file and package block.
声明将非空标识符绑定至常量、类型、类型参数、变量、函数、标签或包。程序中每个标识符都必须声明。同一代码块内不得重复声明标识符,且文件块与包块中不可同时声明相同标识符。
The blank identifier may be used like any other identifier
in a declaration, but it does not introduce a binding and thus is not declared.
In the package block, the identifier init may only be used for
init function declarations,
and like the blank identifier it does not introduce a new binding.
空白标识符在声明中可像其他标识符一样使用,但它不会引入绑定关系,因此无需显式声明。在包块中,标识符 init 仅可用于 init 函数声明,且与空白标识符类似,它不会引入新的绑定关系。
Declaration = ConstDecl | TypeDecl | VarDecl . TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
The scope of a declared identifier is the extent of source text in which
the identifier denotes the specified constant, type, variable, function, label, or package.
声明的标识符其作用域是指该标识符在源代码中表示指定常量、类型、变量、函数、标签或包的范围。
Go is lexically scoped using blocks:
Go 通过代码块实现词法作用域
- 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 an identifier denoting a type parameter of a function
or declared by a method receiver begins after the name of the function
and ends at the end of the function body.
表示函数类型参数或由方法接收者声明的标识符的作用域起始于函数名之后,结束于函数体末尾。 - The scope of an identifier denoting a type parameter of a type
begins after the name of the type and ends at the end
of the TypeSpec.
类型参数标识符的作用域始于类型名称之后,终于 TypeSpec 结尾。 - 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.
函数内声明的常量或变量标识符的作用域始于 ConstSpec 或 VarSpec(短变量声明为 ShortVarDecl)的末尾,止于最内层包含块的结尾。 - 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.
函数内部声明的类型标识符的作用域始于 TypeSpec 中的标识符,止于最内层包含块的末端。
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 assignment statements.
空白标识符由下划线字符 _ 表示,它作为无名占位符替代常规(非空白)标识符,在声明、作为操作数及赋值语句中具有特殊含义。
Predeclared identifiers¶
预声明标识符 ¶
The following identifiers are implicitly declared in the
universe block
[Go 1.18]
[Go 1.21]:
以下标识符在全局块中隐式声明 [ Go 1.18] [ Go 1.21]:
Types: any bool byte comparable complex64 complex128 error float32 float64 int int8 int16 int32 int64 rune string uint uint8 uint16 uint32 uint64 uintptr Constants: true false iota Zero value: nil Functions: append cap clear close complex copy delete imag len make max min new panic print println real recover
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 uppercase
letter (Unicode character category Lu); and
标识符名称的首字符为 Unicode 大写字母(Unicode 字符类别 Lu);且 - 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.
常量声明将一组标识符(即常量名称)绑定到常量表达式列表的值上。标识符的数量必须与表达式的数量相等,且左侧的第 n 个标识符会绑定到右侧第 n 个表达式的值。
ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
IdentifierList = identifier { "," identifier } .
ExpressionList = Expression { "," Expression } .
If the type is present, all constants take the type specified, and
the expressions must be assignable to that type,
which must not be a type parameter.
If the type is omitted, the constants take the
individual types of the corresponding expressions.
If the expression values are untyped constants,
the declared constants remain untyped and the constant identifiers
denote the constant values. For instance, if the expression is a
floating-point literal, the constant identifier denotes a floating-point
constant, even if the literal's fractional part is zero.
若类型存在,所有常量均采用指定类型,且表达式必须可赋值于该类型,该类型不得为类型参数。若省略类型,常量则采用对应表达式的各自类型。若表达式值为无类型常量,声明的常量仍保持无类型状态,常量标识符表示常量值。例如,若表达式为浮点数字面值,即使其小数部分为零,常量标识符仍表示浮点常量。
const Pi float64 = 3.14159265358979323846 const zero = 0.0 // untyped floating-point constant const ( size int64 = 1024 eof = -1 // untyped integer constant ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Within a parenthesized const 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 声明列表中,除首个 ConstSpec 外,其余表达式列表均可省略。此类空列表等效于文本替换为前一个非空表达式列表及其类型(若存在)。因此省略表达式列表等同于重复使用前一个列表。标识符数量必须与前一个列表中的表达式数量相等。结合 iota 常量生成器,该机制能够实现序列值的轻量声明:
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Partyday numberOfDays // this constant is not exported )
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:
在常量声明中,预声明标识符 iota 代表连续的无类型整型常量。其值为该常量声明中对应 ConstSpec 的索引,从零开始计数。此标识符可用于构造一组关联常量:
const ( c0 = iota // c0 == 0 c1 = iota // c1 == 1 c2 = iota // c2 == 2 ) const ( a = 1 << iota // a == 1 (iota == 0) b = 1 << iota // b == 2 (iota == 1) c = 3 // c == 3 (iota == 2, unused) d = 1 << iota // d == 8 (iota == 3) ) const ( u = iota * 42 // u == 0 (untyped integer constant) v float64 = iota * 42 // v == 42.0 (float64 constant) w = iota * 42 // w == 84 (untyped integer constant) ) const x = iota // x == 0 const y = iota // y == 0
By definition, multiple uses of iota in the same ConstSpec all have the same value:
根据定义,同一 ConstSpec 中 iota 的多次使用都具有相同值:
const ( bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0) bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1) _, _ // (iota == 2, unused) bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3) )
This last example exploits the implicit repetition
of the last non-empty expression list.
最后一个例子运用了最后一个非空表达式列表的隐式重复。
Type 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
[Go 1.9].
别名声明将标识符绑定到指定类型 [Go 1.9]。
AliasDecl = identifier [ TypeParameters ] "=" Type .
Within the scope of
the identifier, it serves as an alias for the given type.
在标识符的作用域内,其作为给定类型的别名。
type ( nodeList = []*Node // nodeList and []*Node are identical types Polar = polar // Polar and polar denote identical types )
If the alias declaration specifies type parameters
[Go 1.24], the type name denotes a generic alias.
Generic aliases must be instantiated when they
are used.
若别名声明指定了类型参数[ Go 1.24],该类型名即指代泛型别名。使用泛型别名时必须被实例化。
type set[P comparable] = map[P]bool
In an alias declaration the given type cannot be a type parameter.
在别名声明中,给定的类型不能是类型参数。
type A[P any] = P // illegal: P is a type parameter
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, the type name, to it.
类型定义会创建一个新的独特类型,该类型与给定类型具有相同的底层类型和操作,并将一个标识符——即类型名称——绑定至此新类型。
TypeDef = identifier [ TypeParameters ] Type .
The new type is called a defined type.
It is different from any other type,
including the type it is created from.
这种新型类型称为定义类型,但它与其他所有类型都不同,包括其源类型。
type (
Point struct{ x, y float64 } // Point and struct{ x, y float64 } are different types
polar Point // polar and Point denote different types
)
type TreeNode struct {
left, right *TreeNode
value any
}
type Block interface {
BlockSize() int
Encrypt(src, dst []byte)
Decrypt(src, dst []byte)
}
A defined type may have methods associated with it.
It does not inherit any methods bound to the given type,
but the method set
of an interface type or of elements of a composite type remains unchanged:
已定义类型可能拥有与之关联的方法。它不会继承任何绑定到给定类型的方法,但接口类型的方法集或复合类型元素的方法集保持不变:
// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct { /* Mutex fields */ }
func (m *Mutex) Lock() { /* Lock implementation */ }
func (m *Mutex) Unlock() { /* Unlock implementation */ }
// NewMutex has the same composition as Mutex but its method set is empty.
type NewMutex Mutex
// The method set of PtrMutex's underlying type *Mutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex
// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its embedded field Mutex.
type PrintableMutex struct {
Mutex
}
// MyBlock is an interface type that has the same method set as Block.
type MyBlock Block
Type definitions may be used to define different boolean, numeric,
or string types and associate methods with them:
类型定义可用于定义不同的布尔值、数值或字符串类型,并为其关联方法:
type TimeZone int
const (
EST TimeZone = -(5 + iota)
CST
MST
PST
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}
If the type definition specifies type parameters,
the type name denotes a generic type.
Generic types must be instantiated when they
are used.
如果类型定义指定了类型参数,则该类型名称表示泛型类型。泛型类型在使用时必须实例化。
type List[T any] struct {
next *List[T]
value T
}
In a type definition the given type cannot be a type parameter.
在类型定义中,给定类型不能是类型参数。
type T[P any] P // illegal: P is a type parameter
func f[T any]() {
type L T // illegal: T is a type parameter declared by the enclosing function
}
A generic type may also have methods associated with it.
In this case, the method receivers must declare the same number of type parameters as
present in the generic type definition.
泛型类型也可以拥有与其关联的方法。这种情况下,方法接收器必须声明与泛型类型定义中相同数量的类型参数。
// The method Len returns the number of elements in the linked list l.
func (l *List[T]) Len() int { … }
Type parameter declarations¶
类型参数声明 ¶
A type parameter list declares the type parameters of a generic function or type declaration.
The type parameter list looks like an ordinary function parameter list
except that the type parameter names must all be present and the list is enclosed
in square brackets rather than parentheses
[Go 1.18].
类型形参列表声明了泛型函数或类型声明的类型参数。该列表形式类似于普通函数参数列表,但类型形参名必须全部显式声明,且列表需用方括号而非圆括号包裹[Go 1.18]。
TypeParameters = "[" TypeParamList [ "," ] "]" .
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
TypeParamDecl = IdentifierList TypeConstraint .
All non-blank names in the list must be unique.
Each name declares a type parameter, which is a new and different named type
that acts as a placeholder for an (as of yet) unknown type in the declaration.
The type parameter is replaced with a type argument upon
instantiation of the generic function or type.
列表中所有非空名称必须唯一。每个名称声明一个类型参数,该参数作为声明中(尚未确定的)未知类型的占位符,是一个新且不同的命名类型。在实例化泛型函数或类型时,类型参数会被类型实参所替代。
[P any]
[S interface{ ~[]byte|string }]
[S ~[]E, E any]
[P Constraint[int]]
[_ any]
Just as each ordinary function parameter has a parameter type, each type parameter
has a corresponding (meta-)type which is called its
type constraint.
正如每个普通函数参数都有参数类型一样,每个类型参数也有对应的(元)类型,称为其类型约束。
A parsing ambiguity arises when the type parameter list for a generic type
declares a single type parameter P with a constraint C
such that the text P C forms a valid expression:
当泛型类型的类型参数列表声明了一个带有约束 C 的单个类型参数 P ,导致文本 P C 形成有效表达式时,便会产生解析歧义:
type T[P *C] … type T[P (C)] … type T[P *C|Q] … …
In these rare cases, the type parameter list is indistinguishable from an
expression and the type declaration is parsed as an array type declaration.
To resolve the ambiguity, embed the constraint in an
interface or use a trailing comma:
在极少数情况下,类型参数列表与表达式难以区分,此时类型声明会被解析为数组类型声明。为解决歧义问题,可将约束嵌入接口或使用尾随逗号:
type T[P interface{*C}] …
type T[P *C,] …
Type parameters may also be declared by the receiver specification
of a method declaration associated
with a generic type.
类型参数也可以通过关联泛型类型的方法声明中的接收器规范来声明。
Within a type parameter list of a generic type T, a type constraint
may not (directly, or indirectly through the type parameter list of another
generic type) refer to T.
在泛型类型 T 的类型形参列表中,类型约束不得(直接或间接地通过另一泛型类型的类型形参列表)引用 T 。
type T1[P T1[P]] … // illegal: T1 refers to itself
type T2[P interface{ T2[int] }] … // illegal: T2 refers to itself
type T3[P interface{ m(T3[int])}] … // illegal: T3 refers to itself
type T4[P T5[P]] … // illegal: T4 refers to T5 and
type T5[P T4[P]] … // T5 refers to T4
type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type parameter list
Type constraints¶ 类型约束 ¶
A type constraint is an interface that defines the
set of permissible type arguments for the respective type parameter and controls the
operations supported by values of that type parameter
[Go 1.18].
类型约束是一种接口,它定义了相应类型形参所允许的类型实参集合,并控制该类型形参值所支持的操作[Go 1.18]。
TypeConstraint = TypeElem .
If the constraint is an interface literal of the form interface{E} where
E is an embedded type element (not a method), in a type parameter list
the enclosing interface{ … } may be omitted for convenience:
如果约束是形如 interface{E} 的接口字面量,其中 E 是嵌入式类型元素(而非方法),那么在类型参数列表中为方便起见可以省略包围的 interface{ … } :
[T []P] // = [T interface{[]P}]
[T ~int] // = [T interface{~int}]
[T int|string] // = [T interface{int|string}]
type Constraint ~int // illegal: ~int is not in a type parameter list
The predeclared
interface type comparable
denotes the set of all non-interface types that are
strictly comparable
[Go 1.18].
预声明的接口类型 comparable 表示所有严格可比较的非接口类型的集合[Go 1.18]。
Even though interfaces that are not type parameters are comparable,
they are not strictly comparable and therefore they do not implement comparable.
However, they satisfy comparable.
尽管非类型参数的接口是可比较的,但它们并非严格可比较,因此无法实现 comparable 。然而,它们满足 comparable 的要求。
int // implements comparable (int is strictly comparable)
[]byte // does not implement comparable (slices cannot be compared)
interface{} // does not implement comparable (see above)
interface{ ~int | ~string } // type parameter only: implements comparable (int, string types are strictly comparable)
interface{ comparable } // type parameter only: implements comparable (comparable implements itself)
interface{ ~int | ~[]byte } // type parameter only: does not implement comparable (slices are not comparable)
interface{ ~struct{ any } } // type parameter only: does not implement comparable (field any is not strictly comparable)
The comparable interface and interfaces that (directly or indirectly) embed
comparable may only be used as type constraints. They cannot be the types of
values or variables, or components of other, non-interface types.
comparable 接口以及(直接或间接地)嵌入了 comparable 的接口只能用作类型约束。它们不能作为值或变量的类型,也不能作为其他非接口型的组成部分。
Satisfying a type constraint¶
满足类型约束 ¶
A type argument T satisfies a type constraint C
if T is an element of the type set defined by C; in other words,
if T implements C.
As an exception, a strictly comparable
type constraint may also be satisfied by a comparable
(not necessarily strictly comparable) type argument
[Go 1.20].
More precisely:
类型实参 T 满足类型约束 C 的条件是:当 T 属于由 C 定义的类型集合元素;换言之,若 T 实现了 C 。特例情况下,严格可比较的类型约束也可由可比较(未必严格可比较)的类型实参满足[Go 1.20]。更精确地说:
A type T satisfies a constraint C if
类型 T 满足约束 C 如果
-
TimplementsC; or
T实现C;或 -
Ccan be written in the forminterface{ comparable; E }, whereEis a basic interface andTis comparable and implementsE.
C可写作interface{ comparable; E }的形式,其中E是基础接口,T可比较且实现了E。
type argument type constraint // constraint satisfaction
int interface{ ~int } // satisfied: int implements interface{ ~int }
string comparable // satisfied: string implements comparable (string is strictly comparable)
[]byte comparable // not satisfied: slices are not comparable
any interface{ comparable; int } // not satisfied: any does not implement interface{ int }
any comparable // satisfied: any is comparable and implements the basic interface any
struct{f any} comparable // satisfied: struct{f any} is comparable and implements the basic interface any
any interface{ comparable; m() } // not satisfied: any does not implement the basic interface interface{ m() }
interface{ m() } interface{ comparable; m() } // satisfied: interface{ m() } is comparable and implements the basic interface interface{ m() }
Because of the exception in the constraint satisfaction rule, comparing operands of type parameter type
may panic at run-time (even though comparable type parameters are always strictly comparable).
由于约束满足规则存在异常,比较类型参数类型的操作数可能在运行时引发恐慌(尽管可比较的类型参数始终严格可比较)。
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 i int var U, V, W float64 var k = 0 var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" ) var re, im = complexSqrt(-1) var _, found = entries[name] // map lookup; only interested in "found"
If a list of expressions is given, the variables are initialized
with the expressions following the rules for assignment statements.
Otherwise, each variable is initialized to its zero value.
若提供了表达式列表,则变量将使用这些表达式按照赋值语句的规则进行初始化。否则,每个变量会被初始化为其零值。
If a type is present, each variable is given that type.
Otherwise, each variable is given the type of the corresponding
initialization value in the assignment.
If that value is an untyped constant, it is first implicitly
converted to its default type;
if it is an untyped boolean value, it is first implicitly converted to type bool.
The predeclared identifier 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
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() // os.Pipe() returns a connected pair of Files and an error, if any
_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
Unlike regular variable declarations, a short variable declaration may redeclare
variables provided they were originally declared earlier in the same block
(or the parameter lists if the block is the function body) with the same type,
and at least one of the non-blank variables is new.
As a consequence, redeclaration can only appear in a multi-variable short declaration.
Redeclaration does not introduce a new variable; it just assigns a new value to the original.
The non-blank variable names on the left side of :=
must be unique.
与常规变量声明不同,短变量声明可重新声明变量,前提是这些变量已在同一代码块(若为函数体则包含参数列表)中声明过且类型相同,且至少有一个非空白变量是新的。因此,重新声明仅能出现在多变量短声明中。重新声明不会创建新变量,仅对原变量赋予新值。 := 左侧的非空白变量名必须唯一。
field1, offset := nextField(str, 0) field2, offset := nextField(str, offset) // redeclares offset x, y, x := 1, 2, 3 // illegal: x repeated on left side of :=
Short variable declarations may appear only inside functions.
In some contexts such as the initializers for
"if",
"for", or
"switch" statements,
they can be used to declare local temporary variables.
短变量声明仅能在函数内部使用。在某些上下文中,例如“if”、“for”或“switch”语句的初始值设定项内,它们可用于声明局部临时变量。
Function declarations¶ 函数声明 ¶
A function declaration binds an identifier, the function name,
to a function.
函数声明将一个标识符(即函数名)绑定到函数上。
FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] . FunctionName = identifier . FunctionBody = Block .
If the function's signature declares
result parameters, the function body's statement list must end in
a terminating statement.
如果函数的签名声明了结果参数,则函数体的语句列表必须以终止语句结束。
func IndexRune(s string, r rune) int {
for i, c := range s {
if c == r {
return i
}
}
// invalid: missing return statement
}
If the function declaration specifies type parameters,
the function name denotes a generic function.
A generic function must be instantiated before it can be
called or used as a value.
如果函数声明指定了类型参数,则该函数名指代一个泛型函数。泛型函数必须经过实例化后才能被调用或作为值使用。
func min[T ~int|~float64](x, y T) T {
if x < y {
return x
}
return y
}
A function declaration without type parameters may omit the body.
Such a declaration provides the signature for a function implemented outside Go,
such as an assembly routine.
函数声明若无泛型类型参数,可以省略函数体。此类声明为在 Go 之外实现的函数提供了签名,例如汇编例程。
func flushICache(begin, end uintptr) // implemented externally
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 .
The receiver is specified via an extra parameter section preceding the method
name. That parameter section must declare a single non-variadic parameter, the receiver.
Its type must be a defined type T or a
pointer to a defined type T, possibly followed by a list of type parameter
names [P1, P2, …] enclosed in square brackets.
T is called the receiver base type. A receiver base type cannot 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 its receiver base type and the method name
is visible only within selectors for type T
or *T.
接收者通过位于方法名之前的一个额外参数部分指定。该参数部分必须声明一个非可变参数,即接收者。其类型必须是一个已定义类型 T 或指向已定义类型的指针 T ,其后可跟随用方括号括起来的类型参数名称列表 [P1, P2, …] 。 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 defined 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.
将方法 Length 和 Scale 绑定到基类型 Point ,使用接收器类型 *Point 。
If the receiver base type is a generic type, the
receiver specification must declare corresponding type parameters for the method
to use. This makes the receiver type parameters available to the method.
Syntactically, this type parameter declaration looks like an
instantiation of the receiver base type: the type
arguments must be identifiers denoting the type parameters being declared, one
for each type parameter of the receiver base type.
The type parameter names do not need to match their corresponding parameter names in the
receiver base type definition, and all non-blank parameter names must be unique in the
receiver parameter section and the method signature.
The receiver type parameter constraints are implied by the receiver base type definition:
corresponding type parameters have corresponding constraints.
如果接收器基类型为泛型类型,则接收器规范必须声明供方法使用的对应类型参数。这使得接收器类型参数在方法中可用。语法上,该类型参数声明类似于接收器基类型的实例化:类型实参必须是表示所声明类型参数的标识符,每个标识符对应接收器基类型的一个类型参数。类型参数名称无需与接收器基类型定义中的对应参数名称匹配,且所有非空参数名在接收器参数段和方法签名中必须唯一。接收器类型参数约束由接收器基类型定义隐式确定:对应类型参数具有对应约束。
type Pair[A, B any] struct {
a A
b B
}
func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B
func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair
If the receiver type is denoted by (a pointer to) an alias,
the alias must not be generic and it must not denote an instantiated generic type, neither
directly nor indirectly via another alias, and irrespective of pointer indirections.
如果接收器类型通过别名(或指向该别名的指针)表示,则该别名不得为泛型类型,且无论是否存在指针间接寻址,该别名都不得直接或间接通过其他别名表示实例化的泛型类型。
type GPoint[P any] = Point
type HPoint = *GPoint[int]
type IPair = Pair[int, int]
func (*GPoint[P]) Draw(P) { … } // illegal: alias must not be generic
func (HPoint) Draw(P) { … } // illegal: alias must not denote instantiated type GPoint[int]
func (*IPair) Second() int { … } // illegal: alias must not denote instantiated type Pair[int, int]
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.
操作数代表表达式中的基本值。操作数可以是字面量、表示常量、变量或函数的(可能带限定的)非空标识符,或是括号表达式。
Operand = Literal | OperandName [ TypeArgs ] | "(" Expression ")" .
Literal = BasicLit | CompositeLit | FunctionLit .
BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
OperandName = identifier | QualifiedIdent .
An operand name denoting a generic function
may be followed by a list of type arguments; the
resulting operand is an instantiated function.
操作数名称表示泛型函数后可以跟一个类型参数列表;生成的操作数即为实例化函数。
The blank identifier may appear as an
operand only on the left-hand side of an assignment statement.
空白标识符仅能作为操作数出现在赋值语句的左侧。
Implementation restriction: A compiler need not report an error if an operand's
type is a type parameter with an empty
type set. Functions with such type parameters
cannot be instantiated; any attempt will lead
to an error at the instantiation site.
实现限制:若操作数的类型为具有空类型集的类型参数,编译器无需报告错误。带有此类类型参数的函数无法实例化;任何尝试都将在实例化位置引发错误。
Qualified 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
Composite literals¶ 复合字面量 ¶
Composite literals construct new composite values each time they are evaluated.
They consist of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
复合字面量每次求值都会构造新的复合值。其结构由字面量类型后接大括号括起来的元素列表组成,每个元素均可选择性地前置对应的键名。
CompositeLit = LiteralType LiteralValue .
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
SliceType | MapType | TypeName [ TypeArgs ] .
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
ElementList = KeyedElement { "," KeyedElement } .
KeyedElement = [ Key ":" ] Element .
Key = FieldName | Expression | LiteralValue .
FieldName = identifier .
Element = Expression | LiteralValue .
The LiteralType's core type T
must be a struct, array, slice, or map type
(the syntax 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 type T;
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.
LiteralType 的核心类型 T 必须是结构体、数组、切片或映射类型(当类型以 TypeName 形式给出时,语法会强制此约束)。元素和键的类型必须可赋值给类型 T 的相应字段、元素和键类型;不进行额外转换。键在结构体字面量中解释为字段名,在数组和切片字面量中解释为索引,在映射字面量中解释为键。对于映射字面量,所有元素必须包含键。指定多个具有相同字段名或常量键值的元素将引发错误。关于非常量映射键的说明,请参阅求值顺序章节。
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.
如果某个元素具有 key,则每个元素都必须具有 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
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.
具有键的元素以该键作为其索引。该键必须是可由类型int的值表示的非负常量;若指定其类型,则必须是整型。 - 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
generates a pointer to a unique variable initialized
with the literal's value.
对复合字面量取地址会生成指向该字面值初始化的唯一变量的指针。
var pointer *Point3D = &Point3D{y: 1000}
Note that the zero value for a slice or map
type is not the same as an initialized but empty value of the same type.
Consequently, taking the address of an empty slice or map composite literal
does not have the same effect as allocating a new slice or map value with
new.
请注意,切片或映射类型的零值不同于同类型已初始化但为空的值。因此,对空切片或映射复合字面量取地址的效果与使用 new 分配新切片或映射值的效果并不相同。
p1 := &[]int{} // p1 points to an initialized, empty slice with value []int{} and length 0
p2 := new([]int) // p2 points to an uninitialized slice with value nil and length 0
The length of an array literal is the length specified in the literal type.
If fewer elements than the length are provided in the literal, the missing
elements are set to the zero value for the array element type.
It is an error to provide elements with index values outside the index range
of the array. The notation ... 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.
在数组、切片或映射类型的复合字面量 T 中,若元素或映射键本身为复合字面量,且其类型与 T 的元素或键类型相同,则可省略对应的字面量类型。同理,当元素或键类型为 *T 时,作为复合字面量地址的元素或键可省略 &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{})}
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,
}
Function literals¶ 函数字面量 ¶
A function literal represents an anonymous function.
Function literals cannot declare type parameters.
函数字面量表示匿名函数。函数字面量不能声明类型形参。
FunctionLit = "func" Signature FunctionBody .
func(a, b int, z float64) bool { return a*b < int(z) }
A function literal can be assigned to a variable or invoked directly.
函数字面量可赋值给变量或直接调用。
f := func(x, y int) int { return x + y }
func(ch chan int) { ch <- ACK }(replyChan)
Function literals are closures: they may refer to variables
defined in a surrounding function. Those variables are then shared between
the surrounding function and the function literal, and they survive as long
as they are accessible.
函数字面量即闭包:它们可引用外层函数中定义的变量。这些变量在外层函数与函数字面量间共享,且只要变量仍可访问,其生命周期便持续存在。
Primary 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 ,其选择器表达式
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 。为访问 f 所遍历的嵌入字段数量称为其在 T 中的深度。在 T 中声明的字段或方法 f 深度为零。在 T 的嵌入字段 A 中声明的字段或方法 f 的深度,等于 f 在 A 中的深度加一。
The following rules apply to selectors:
以下规则适用于选择器:
-
For a value
xof typeTor*TwhereTis not a pointer or interface type,x.fdenotes the field or method at the shallowest depth inTwhere there is such anf. If there is not exactly onefwith shallowest depth, the selector expression is illegal.
对于类型为T或*T的值x(其中T非指针或接口类型),x.f表示T中具有该f的最浅深度字段或方法。若不存在唯一的最浅深度f,则该选择器表达式非法。 -
For a value
xof typeIwhereIis an interface type,x.fdenotes the actual method with namefof the dynamic value ofx. If there is no method with namefin the method set ofI, the selector expression is illegal.
对于类型为I的值x,其中I为接口类型,x.f表示x动态值中名为f的实际方法。若在I的方法集合中不存在名为f的方法,则该选择器表达式非法。 -
As an exception, if the type of
xis a defined pointer type and(*x).fis a valid selector expression denoting a field (but not a method),x.fis shorthand for(*x).f.
作为例外,若x的类型为已定义的指针类型且(*x).f是表示字段(而非方法)的有效选择器表达式,则x.f表示(*x).f的简写形式。 -
In all other cases,
x.fis illegal.
在所有其他情况下,x.f均属非法。 -
If
xis of pointer type and has the valuenilandx.fdenotes a struct field, assigning to or evaluatingx.fcauses a run-time panic.
如果x是指针类型且值为nil,且x.f表示结构体字段,则对x.f赋值或求值将引发运行时恐慌。 -
If
xis of interface type and has the valuenil, calling or evaluating the methodx.fcauses a run-time panic.
若x为接口类型且值为nil,调用或求值方法x.f将引发运行时恐慌。
For example, given the declarations:
例如,给定声明:
type T0 struct {
x int
}
func (*T0) M0()
type T1 struct {
y int
}
func (T1) M1()
type T2 struct {
z int
T1
*T0
}
func (*T2) M2()
type Q *T2
var t T2 // with t.T0 != nil
var p *T2 // with p != nil and (*p).T0 != nil
var q Q = p
one may write: 有人可以这样写:
t.z // t.z t.y // t.T1.y t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y p.x // (*(*p).T0).x q.x // (*(*q).T0).x (*q).x is a valid field selector p.M0() // ((*p).T0).M0() M0 expects *T0 receiver p.M1() // ((*p).T1).M1() M1 expects T1 receiver p.M2() // p.M2() M2 expects *T2 receiver t.M2() // (&t).M2() M2 expects *T2 receiver, see section on Calls
but the following is invalid:
但以下内容无效:
q.M0() // (*q).M0 is valid but not a field selector
Method expressions¶ 方法表达式 ¶
If 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.
若 M 属于类型 T 的方法集,则 T.M 是一个可作为常规函数调用的函数,其参数与 M 相同,但需额外以方法接收器作为前缀参数。
MethodExpr = ReceiverType "." MethodName . ReceiverType = Type .
Consider a struct type T with two methods,
Mv, whose receiver is of type T, and
Mp, whose receiver is of type *T.
考虑一个结构体类型 T ,它包含两个方法:接收者类型为 T 的 Mv 方法,以及接收者类型为 *T 的 Mp 方法。
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
The expression 该表达式
T.Mv
yields a function equivalent to Mv but
with an explicit receiver as its first argument; it has signature
yields a function equivalent to Mv but with an explicit receiver as its first argument; it has signature
生成一个等效于Mv的函数,但首个参数为显式接收者;其签名为
func(tv T, a int) int
That function may be called normally with an explicit receiver, so
these five invocations are equivalent:
该函数可通过显式接收者正常调用,因此以下五种调用实例等效:
t.Mv(7) T.Mv(t, 7) (T).Mv(t, 7) f1 := T.Mv; f1(t, 7) f2 := (T).Mv; f2(t, 7)
Similarly, the expression
同样地,该表达式
(*T).Mp
yields a function value representing Mp with signature
生成一个函数值,表示带有签名的 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
生成一个表示 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 会先被求值并保存;后续调用时,该保存副本将作为接收者使用。
type S struct { *T }
type T int
func (t T) M() { print(t) }
t := new(T)
s := S{T: t}
f := t.M // receiver *t is evaluated and stored in f
g := s.M // receiver *(s.T) is evaluated and stored in g
*t = 42 // does not affect stored receivers in f and g
The type 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 :其接收器类型为 T 的 Mv ,以及接收器类型为 *T 的 Mp 。
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
var pt *T
func makeT() T
The expression 表达式
t.Mv
yields a function value of type
返回一个类型为……的函数值
func(int) int
These two invocations are equivalent:
这两种调用是等效的:
t.Mv(7) f := t.Mv; f(7)
Similarly, the expression
类似地,表达式
pt.Mp
yields a function value of type
生成一个类型为函数值的值
func(float32) float32
As with selectors, a reference to a non-interface method with a value receiver
using a pointer will automatically dereference that pointer: 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
Although the examples above use non-interface types, it is also legal to create a method value
from a value of interface type.
尽管上述示例使用的是非接口类型,但从接口类型的值创建方法值也是合法的。
var i interface { M(int) } = myVal
f := i.M; f(7) // like i.M(7)
Index 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 neither a map nor a type parameter:
若 a 既非映射亦非类型参数:
- the index
xmust be an untyped constant or its core type must be an integer
索引x必须是无类型常量或其核心类型必须是整数类型 - a constant index must be non-negative and
representable by a value of type
int
常量索引必须为非负,且能用类型int的值表示 - a constant index that is untyped is given type
int
一个无类型的常量索引被赋予类型int - the index
xis in range if0 <= x < len(a), otherwise it is out of range
索引x在范围内,如果0 <= x < len(a),否则超出范围
For a of array type A:
对于数组类型 A 的 a :
- a constant index must be in range
常量索引必须位于范围内 - if
xis out of range at run time, a run-time panic occurs
如果x在运行时超出范围,则会发生运行时恐慌 a[x]is the array element at indexxand the type ofa[x]is the element type ofA
a[x]是位于索引x处的数组元素,而a[x]的类型是A的元素类型
For a of pointer to array type:
对于指向数组类型的指针 a :
a[x]is shorthand for(*a)[x]
a[x]是(*a)[x]的简写形式
For a of slice type S:
对于切片类型 S 的 a :
- if
xis out of range at run time, a run-time panic occurs
如果x在运行时超出范围,将发生运行时恐慌 a[x]is the slice element at indexxand the type ofa[x]is the element type ofS
a[x]是索引x处的切片元素,而a[x]的类型是S的元素类型
For a of string type:
对于 a 属于字符串类型:
- a constant index must be in range
if the string
ais also constant
如果字符串a也为常量,则常量索引必须处于范围内 - if
xis out of range at run time, a run-time panic occurs
若运行时x超出范围,将发生运行时恐慌 a[x]is the non-constant byte value at indexxand the type ofa[x]isbyte
索引x处的非常量字节值为a[x],而a[x]的类型是bytea[x]may not be assigned to
a[x]不可分配至
For a of map type M:
对于地图类型 M 的 a :
x's type must be assignable to the key type ofM
x的类型必须可分配给M的键类型- if the map contains an entry with key
x,a[x]is the map element with keyxand the type ofa[x]is the element type ofM
若映射中包含键为x的条目,则a[x]是具有键x的映射元素,且a[x]的类型是M的元素类型 - if the map is
nilor does not contain such an entry,a[x]is the zero value for the element type ofM
若映射为nil或不包含该条目,则a[x]为M元素类型的零值
For a of type parameter type P:
对于类型为参数类型 P 的 a :
- The index expression
a[x]must be valid for values of all types inP's type set.
索引表达式a[x]必须对所有P类型集合中的类型的值都有效。 - The element types of all types in
P's type set must be identical. In this context, the element type of a string type isbyte.
P类型集合中所有类型的元素类型必须相同。在此上下文中,字符串类型的元素类型为byte。 - If there is a map type in the type set of
P, all types in that type set must be map types, and the respective key types must be all identical.
若类型集合P中存在映射类型,则该集合中的所有类型必须均为映射类型,且各自的键类型必须全部相同。 a[x]is the array, slice, or string element at indexx, or the map element with keyxof the type argument thatPis instantiated with, and the type ofa[x]is the type of the (identical) element types.
a[x]是数组、切片或字符串中索引为x的元素,或是P实例化时使用的类型参数中键为x的映射元素,而a[x]的类型即为这些(相同)元素类型的类型。a[x]may not be assigned to ifP's type set includes string types.
a[x]可能无法被赋值,如果P的类型集包含字符串类型。
Otherwise a[x] is illegal.
否则 a[x] 非法。
An index expression on a map a of type map[K]V
used in an assignment statement 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.
为 nil 映射的元素赋值将导致运行时恐慌。
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
简单切片表达式
The primary expression 主表达式
a[low : high]
constructs a substring or slice. The core type of
a must be a string, array, pointer to array, slice, or a
bytestring.
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
构造一个子字符串或切片。 a 的核心类型必须是字符串、数组、数组指针、切片或 bytestring 。索引 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:
为方便起见,可省略任何索引。缺失的 low 索引默认为零;缺失的 high 索引默认为切片操作对象的长度:
a[2:] // same as a[2 : len(a)] a[:3] // same as a[0 : 3] a[:] // same as a[0 : len(a)]
If a is a pointer to an array, a[low : high] is shorthand for
(*a)[low : high].
如果 a 是指向数组的指针,则 a[low : high] 是 (*a)[low : high] 的简写形式。
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 。若运行时索引越界,将触发运行时恐慌。
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 切片。否则,若结果为切片,则其底层数组与操作数共享。
var a [10]int s1 := a[3:7] // underlying array of s1 is array a; &s1[2] == &a[5] s2 := s1[1:4] // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5] s2[1] = 42 // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element var s []int s3 := s[:0] // s3 == nil
Full slice expressions 完整切片表达式
The primary expression 主表达式
a[low : high : max]
constructs a slice of the same type, and with the same length and elements as the simple slice
expression a[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.
The core type of a must be an array, pointer to array,
or slice (but not a string).
After slicing the array a
构建一个与简单切片表达式 a[low : high] 相同类型、长度及元素的切片。此外,它通过将容量设为 max - low 来控制结果切片的容量。仅首索引可省略,默认为 0。 a 的核心类型必须是数组、指向数组的指针或切片(不能是字符串)。在对数组 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,
but not a type parameter, 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.
若类型断言成立,则表达式的值为存储在 x 中的值,其类型为 T 。若类型断言不成立,将引发运行时恐慌。换言之,即使在运行时才知晓 x 的动态类型,但在正确的程序中, x.(T) 的类型可确认为 T 。
var x interface{} = 7 // x has dynamic type int and value 7
i := x.(int) // i has type int and value 7
type I interface { m() }
func f(y I) {
s := y.(string) // illegal: string does not implement I (missing method m)
r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
…
}
A type assertion used in an assignment statement or initialization of the special form
一种用于赋值语句或特殊形式初始化的类型断言
v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool
yields an additional untyped boolean value. The value of 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.
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 with a core type
F of function type,
给定一个表达式 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.
调用 f 时需传入 a1, a2, … an 参数。除特殊情形外,参数必须是可赋值给 F 参数类型的单值表达式,且在函数调用前完成求值。该表达式的结果类型即为 F 的结果类型。方法调用与此类似,但需在接收者类型的值上通过选择器指定具体方法。
math.Atan2(x, y) // function call var pt *Point pt.Scale(3.5) // method call with receiver pt
If f denotes a generic function, it must be
instantiated before it can be called
or used as a function value.
若 f 表示泛型函数,则必须实例化后方可调用或用作函数值。
In a function call, the function value and arguments are evaluated in
the usual order.
After they are evaluated, new storage is allocated for the function's
variables, which includes its parameters
and results.
Then, the arguments of the call are passed to the function,
which means that they are assigned
to their corresponding function parameters,
and the called function begins execution.
The return parameters of the function are passed
back to the caller 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 passing 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(parameters_of_g)) 时,会先将 g 的返回值按顺序传递给 f 的参数,再调用 f 。对 f 的调用不得包含除 g 调用之外的任何参数,且 g 必须至少有一个返回值。若 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() 方法调用有效时,需满足以下条件: x (类型)的方法集中包含 m ,且实参列表可赋值给 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 and
is followed by ..., it is passed unchanged as the value
for a ...T parameter. 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 相同的值,前提是它们共享相同的底层数组。
Instantiations¶ 实例化集合 ¶
A generic function or type is instantiated by substituting type arguments
for the type parameters [Go 1.18].
Instantiation proceeds in two steps:
泛型函数或类型通过将类型参数替换为类型实参进行实例化[Go 1.18]。实例化过程分两步进行:
-
Each type argument is substituted for its corresponding type parameter in the generic
declaration.
This substitution happens across the entire function or type declaration,
including the type parameter list itself and any types in that list.
每个类型实参都会替换泛型声明中对应的类型参数。这一替换过程发生在整个函数或类型声明范围内,包括类型形参列表本身及其包含的所有类型。 -
After substitution, each type argument must satisfy
the constraint (instantiated, if necessary)
of the corresponding type parameter. Otherwise instantiation fails.
在替换之后,每个类型实参必须满足对应类型形参的约束(必要时需实例化)。否则实例化将失败。
Instantiating a type results in a new non-generic named type;
instantiating a function produces a new non-generic function.
实例化一个类型会产生一个新的非泛型命名类型;实例化一个函数则生成一个新的非泛型函数。
type parameter list type arguments after substitution [P any] int int satisfies any [S ~[]E, E any] []int, int []int satisfies ~[]int, int satisfies any [P io.Writer] string illegal: string doesn't satisfy io.Writer [P comparable] any any satisfies (but does not implement) comparable
When using a generic function, type arguments may be provided explicitly,
or they may be partially or completely inferred
from the context in which the function is used.
Provided that they can be inferred, type argument lists may be omitted entirely if the function is:
使用泛型函数时,类型参数可显式提供,也可部分或全部从函数调用上下文中推断得出。若能推断出类型参数,则在以下情况下可完全省略类型参数列表:
-
called with ordinary arguments,
使用常规参数调用 -
assigned to a variable with a known type
赋值给已知类型的变量 -
passed as an argument to another function, or
作为参数传递给另一个函数,或 -
returned as a result.
作为结果返回
In all other cases, a (possibly partial) type argument list must be present.
If a type argument list is absent or partial, all missing type arguments
must be inferrable from the context in which the function is used.
在所有其他情况下,必须提供(可能是部分的)类型实参列表。若类型实参列表缺失或不完整,则所有缺失的类型实参必须能从使用该函数的上下文中推断出来。
// sum returns the sum (concatenation, for strings) of its arguments.
func sum[T ~int | ~float64 | ~string](x... T) T { … }
x := sum // illegal: the type of x is unknown
intSum := sum[int] // intSum has type func(x... int) int
a := intSum(2, 3) // a has value 5 of type int
b := sum[float64](2.0, 3) // b has value 5.0 of type float64
c := sum(b, -1) // c has value 4.0 of type float64
type sumFunc func(x... string) string
var f sumFunc = sum // same as var f sumFunc = sum[string]
f = sum // same as f = sum[string]
A partial type argument list cannot be empty; at least the first argument must be present.
The list is a prefix of the full list of type arguments, leaving the remaining arguments
to be inferred. Loosely speaking, type arguments may be omitted from "right to left".
部分类型实参列表不可为空;至少必须提供第一个实参。该列表是完整类型实参列表的前缀,剩余实参将由系统推断得出。通俗地说,类型实参可以"从右向左"省略。
func apply[S ~[]E, E any](s S, f func(E) E) S { … }
f0 := apply[] // illegal: type argument list cannot be empty
f1 := apply[[]int] // type argument for S explicitly provided, type argument for E inferred
f2 := apply[[]string, string] // both type arguments explicitly provided
var bytes []byte
r := apply(bytes, func(byte) byte { … }) // both type arguments inferred from the function arguments
For a generic type, all type arguments must always be provided explicitly.
对于泛型类型,所有类型参数都必须始终显式提供。
Type inference¶ 类型推断 ¶
A use of a generic function may omit some or all type arguments if they can be
inferred from the context within which the function is used, including
the constraints of the function's type parameters.
Type inference succeeds if it can infer the missing type arguments
and instantiation succeeds with the
inferred type arguments.
Otherwise, type inference fails and the program is invalid.
在泛型函数的使用中,若类型实参可通过函数使用上下文(包括函数类型参数的约束)推断得出,则可省略部分或全部类型实参。若类型推断能推导出缺失的类型实参,且使用推断出的类型实参能成功实现实例化,则类型推断成功;否则类型推断失败,程序无效。
Type inference uses the type relationships between pairs of types for inference:
For instance, a function argument must be assignable
to its respective function parameter; this establishes a relationship between the
type of the argument and the type of the parameter.
If either of these two types contains type parameters, type inference looks for the
type arguments to substitute the type parameters with such that the assignability
relationship is satisfied.
Similarly, type inference uses the fact that a type argument must
satisfy the constraint of its respective
type parameter.
类型推断利用类型对之间的类型关系进行推理:例如,函数实参必须可赋值给其对应的形参,这就在实参类型与形参类型之间建立了关联。若其中任一类型包含类型参数,类型推断会寻找能替代这些类型参数的类型实参,从而满足可赋值关系。类似地,类型推断还依据类型实参必须满足其对应类型参数约束这一事实进行推导。
Each such pair of matched types corresponds to a type equation containing
one or multiple type parameters, from one or possibly multiple generic functions.
Inferring the missing type arguments means solving the resulting set of type
equations for the respective type parameters.
每一对匹配的类型对应一个包含一个或多个类型参数的方程,这些参数来自一个或多个泛型函数。推断缺失的类型实参意味着求解这组类型方程的结果集以确定各自的类型参数。
For example, given 例如,给定
// dedup returns a copy of the argument slice with any duplicate entries removed.
func dedup[S ~[]E, E comparable](S) S { … }
type Slice []int
var s Slice
s = dedup(s) // same as s = dedup[Slice, int](s)
the variable s of type Slice must be assignable to
the function parameter type S for the program to be valid.
To reduce complexity, type inference ignores the directionality of assignments,
so the type relationship between Slice and S can be
expressed via the (symmetric) type equation Slice ≡A S
(or S ≡A Slice for that matter),
where the A in ≡A
indicates that the LHS and RHS types must match per assignability rules
(see the section on type unification for
details).
Similarly, the type parameter S must satisfy its constraint
~[]E. This can be expressed as S ≡C ~[]E
where X ≡C Y stands for
"X satisfies constraint Y".
These observations lead to a set of two equations
类型为 Slice 的变量 s 必须可赋值给函数参数类型 S ,程序才能有效。为降低复杂度,类型推断忽略赋值的指向性,因此 Slice 与 S 的类型关系可通过(对称的)类型方程 Slice ≡A S (或同样适用的 S ≡A Slice )表示,其中 ≡A 中的 A 表示左侧与右侧类型必须符合可赋值规则(详见类型统一章节)。类似地,类型参数 S 必须满足其约束 ~[]E ,这可表述为 S ≡C ~[]E ,其中 X ≡C Y 表示“ X 满足约束 Y ”。上述观察结果推导出包含两个方程的方程组。
Slice ≡A S (1) S ≡C ~[]E (2)
which now can be solved for the type parameters S and E.
From (1) a compiler can infer that the type argument for S is Slice.
Similarly, because the underlying type of Slice is []int
and []int must match []E of the constraint,
a compiler can infer that E must be int.
Thus, for these two equations, type inference infers
现在可以求解类型参数 S 和 E 。根据(1),编译器可推断出 S 的类型实参为 Slice 。同理,由于 Slice 的底层类型是 []int ,且 []int 必须匹配约束中的 []E ,编译器可推断 E 必须为 int 。因此对于这两个等式,类型推断得出
S ➞ Slice E ➞ int
Given a set of type equations, the type parameters to solve for are
the type parameters of the functions that need to be instantiated
and for which no explicit type arguments is provided.
These type parameters are called bound type parameters.
For instance, in the dedup example above, the type parameters
S and E are bound to dedup.
An argument to a generic function call may be a generic function itself.
The type parameters of that function are included in the set of bound
type parameters.
The types of function arguments may contain type parameters from other
functions (such as a generic function enclosing a function call).
Those type parameters may also appear in type equations but they are
not bound in that context.
Type equations are always solved for the bound type parameters only.
给定一组类型方程,待求解的类型参数是指那些需要实例化但未提供显式类型实参的函数类型参数。这些类型参数称为绑定类型参数。例如,在上文的 dedup 示例中,类型参数 S 和 E 被绑定到 dedup 。泛型函数调用的实参本身可能是泛型函数,该函数的类型参数会被纳入绑定类型参数集合。函数实参的类型可能包含来自其他函数(如包含函数调用的泛型函数)的类型参数,这些类型参数虽可能出现在类型方程中,但在该上下文中并不被绑定。类型方程始终仅针对绑定类型参数求解。
Type inference supports calls of generic functions and assignments
of generic functions to (explicitly function-typed) variables.
This includes passing generic functions as arguments to other
(possibly also generic) functions, and returning generic functions
as results.
Type inference operates on a set of equations specific to each of
these cases.
The equations are as follows (type argument lists are omitted for clarity):
类型推断支持泛型函数的调用以及将泛型函数赋值给(显式函数类型的)变量。这包括将泛型函数作为实参传递给其他函数(这些函数本身也可能是泛型函数),以及将泛型函数作为结果返回。类型推断基于针对每种情况特制的等式集合进行操作,具体等式如下(为清晰起见,类型实参列表被省略):
-
For a function call
f(a0, a1, …)wherefor a function argumentaiis a generic function:
对于函数调用f(a0, a1, …),其中f或函数参数ai是泛型函数:
Each pair(ai, pi)of corresponding function arguments and parameters whereaiis not an untyped constant yields an equationtypeof(pi) ≡A typeof(ai).
每对(ai, pi)对应的函数实参与形参,当ai不是无类型常量时,将推导出一个等式typeof(pi) ≡A typeof(ai)。
Ifaiis an untyped constantcj, andtypeof(pi)is a bound type parameterPk, the pair(cj, Pk)is collected separately from the type equations.
如果ai是一个未定型常量cj,且typeof(pi)是一个绑定的类型参数Pk,那么这对(cj, Pk)将从类型方程中单独收集。 -
For an assignment
v = fof a generic functionfto a (non-generic) variablevof function type:
对于将泛型函数f赋值给函数类型的(非泛型)变量v的情况:
typeof(v) ≡A typeof(f). -
For a return statement
return …, f, …wherefis a generic function returned as a result to a (non-generic) result variablerof function type:
对于返回语句return …, f, …,其中f是一个泛型函数,作为结果返回给(非泛型)结果变量r(函数类型):
typeof(r) ≡A typeof(f).
Additionally, each type parameter Pk and corresponding type constraint
Ck yields the type equation
Pk ≡C Ck.
此外,每个类型参数 Pk 及其对应的类型约束 Ck 都会产生类型方程 Pk ≡C Ck 。
Type inference gives precedence to type information obtained from typed operands
before considering untyped constants.
Therefore, inference proceeds in two phases:
类型推断在考虑无类型常量之前,会优先采用从类型化操作数获得的类型信息。因此推断过程分为两个阶段:
-
The type equations are solved for the bound type parameters using type unification. If unification fails, type inference fails.
类型方程通过类型统一求解绑定类型参数。若统一失败,则类型推断失败。 -
For each bound type parameter
Pkfor which no type argument has been inferred yet and for which one or more pairs(cj, Pk)with that same type parameter were collected, determine the constant kind of the constantscjin all those pairs the same way as for constant expressions. The type argument forPkis the default type for the determined constant kind. If a constant kind cannot be determined due to conflicting constant kinds, type inference fails.
对于尚未推断出类型实参的每个绑定类型形参Pk,若已收集到一个或多个包含该相同类型形参的(cj, Pk)对,则需按照常量表达式的处理方式,确定所有此类对中常量cj的常量种类。此时Pk的类型实参即为所确定常量种类对应的默认类型。若因常量种类冲突导致无法确定常量种类,则类型推断失败。
If not all type arguments have been found after these two phases, type inference fails.
如果这两个阶段之后仍未找到所有类型参数,则类型推断失败。
If the two phases are successful, type inference determined a type argument for each
bound type parameter:
如果这两个阶段都成功,类型推断就已为每个绑定类型参数确定了类型实参
Pk ➞ Ak
A type argument Ak may be a composite type,
containing other bound type parameters Pk as element types
(or even be just another bound type parameter).
In a process of repeated simplification, the bound type parameters in each type
argument are substituted with the respective type arguments for those type
parameters until each type argument is free of bound type parameters.
类型参数 Ak 可以是复合类型,包含其他绑定类型参数 Pk 作为元素类型(甚至可能本身就是一个绑定类型参数)。在反复简化的过程中,每个类型参数中的绑定类型参数会被替换为对应类型参数的具体类型实参,直至所有类型参数均不含绑定类型参数。
If type arguments contain cyclic references to themselves
through bound type parameters, simplification and thus type
inference fails.
Otherwise, type inference succeeds.
若类型实参通过绑定类型参数形成自循环引用,则无法进行简化,因而类型推断失败。否则,类型推断成功。
Type unification¶ 类型统一 ¶
Type inference solves type equations through type unification.
Type unification recursively compares the LHS and RHS types of an
equation, where either or both types may be or contain bound type parameters,
and looks for type arguments for those type parameters such that the LHS
and RHS match (become identical or assignment-compatible, depending on
context).
To that effect, type inference maintains a map of bound type parameters
to inferred type arguments; this map is consulted and updated during type unification.
Initially, the bound type parameters are known but the map is empty.
During type unification, if a new type argument A is inferred,
the respective mapping P ➞ A from type parameter to argument
is added to the map.
Conversely, when comparing types, a known type argument
(a type argument for which a map entry already exists)
takes the place of its corresponding type parameter.
As type inference progresses, the map is populated more and more
until all equations have been considered, or until unification fails.
Type inference succeeds if no unification step fails and the map has
an entry for each type parameter.
类型推断通过类型统一求解类型方程。类型统一递归地比较方程的左侧类型(LHS)与右侧类型(RHS),其中任一或双方类型可能包含绑定类型参数,并寻找这些类型参数的类型实参,以使左右两侧类型匹配(具体取决于上下文,需完全相同或满足赋值兼容性)。为此,类型推断维护一个从绑定类型参数到推断类型实参的映射表;该映射表在类型统一过程中被查询和更新。初始状态下,绑定类型参数已知但映射表为空。在类型统一期间,若推断出新类型实参 A ,则会将类型参数到实参的对应映射 P ➞ A 加入表中。反之,当比较类型时,已知类型实参(即映射表中已有记录的实参)将替换其对应的类型参数。随着类型推断推进,映射表逐渐填充直至处理完所有方程或统一过程失败。若所有统一步骤均成功且映射表包含每个类型参数的条目,则类型推断成功。
For example, given the type equation with the bound type parameter
P
例如,给定带有绑定类型参数 P 的类型方程[
[10]struct{ elem P, list []P } ≡A [10]struct{ elem string; list []string }
type inference starts with an empty map.
Unification first compares the top-level structure of the LHS and RHS
types.
Both are arrays of the same length; they unify if the element types unify.
Both element types are structs; they unify if they have
the same number of fields with the same names and if the
field types unify.
The type argument for P is not known yet (there is no map entry),
so unifying P with string adds
the mapping P ➞ string to the map.
Unifying the types of the list field requires
unifying []P and []string and
thus P and string.
Since the type argument for P is known at this point
(there is a map entry for P), its type argument
string takes the place of P.
And since string is identical to string,
this unification step succeeds as well.
Unification of the LHS and RHS of the equation is now finished.
Type inference succeeds because there is only one type equation,
no unification step failed, and the map is fully populated.
类型推断从一个空映射开始。统一算法首先比较左右两侧类型的顶层结构。两者均为长度相同的数组;当元素类型统一时,它们即达成统一。两个元素类型皆为结构体;当它们拥有相同数量的同名字段且字段类型统一时,则达成统一。 P 的类型参数尚未得知(映射表中无对应条目),因此统一 P 与 string 会将映射关系 P ➞ string 加入映射表。统一 list 字段的类型需要统一 []P 与 []string ,进而统一 P 与 string 。由于此时 P 的类型参数已知(映射表中存在 P 的条目),其类型参数 string 将替代 P 的位置。鉴于 string 与 string 完全相同,此统一步骤亦成功完成。至此,等式左右两侧的统一过程全部结束。类型推断成功,因仅存在单一类型等式、所有统一步骤均成功执行且映射表已完全填充。
Unification uses a combination of exact and loose
unification depending on whether two types have to be
identical,
assignment-compatible, or
only structurally equal.
The respective type unification rules
are spelled out in detail in the Appendix.
统一操作根据两种类型是否需要完全相同、赋值兼容或仅结构相等,采用精确统一和宽松统一的组合方式。相应的类型统一规则在附录中有详细说明。
For an equation of the form X ≡A Y,
where X and Y are types involved
in an assignment (including parameter passing and return statements),
the top-level type structures may unify loosely but element types
must unify exactly, matching the rules for assignments.
对于形如 X ≡A Y 的方程,其中 X 和 Y 是赋值操作(包括参数传递和返回语句)涉及的类型,其顶层类型结构可松散统一,但元素类型必须精确统一,以匹配赋值规则。
For an equation of the form P ≡C C,
where P is a type parameter and C
its corresponding constraint, the unification rules are bit
more complicated:
对于形式为 P ≡C C 的方程,其中 P 表示类型参数, C 是其对应的约束条件,统一规则稍显复杂:
-
If
Chas a core typecore(C)andPhas a known type argumentA,core(C)andAmust unify loosely. IfPdoes not have a known type argument andCcontains exactly one type termTthat is not an underlying (tilde) type, unification adds the mappingP ➞ Tto the map.
若C具有核心类型core(C)且P含有已知类型参数A,则core(C)与A必须进行宽松统一。若P不存在已知类型参数且C仅包含一个非底层(波浪号)类型的类型项T,统一过程将添加映射P ➞ T至映射表中。 -
If
Cdoes not have a core type andPhas a known type argumentA,Amust have all methods ofC, if any, and corresponding method types must unify exactly.
如果C没有核心类型,且P具有已知类型参数A,则A必须包含C的所有方法(如有),且对应方法类型必须完全统一。
When solving type equations from type constraints,
solving one equation may infer additional type arguments,
which in turn may enable solving other equations that depend
on those type arguments.
Type inference repeats type unification as long as new type
arguments are inferred.
在解决类型约束中的类型方程时,求解一个方程可能会推断出额外的类型参数,进而使依赖于这些类型参数的其他方程得以求解。只要推断出新的类型参数,类型推导就会持续进行类型统一。
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 implicitly converted
to the type of the other operand.
除移位操作外,若一个操作数为无类型常量而另一个操作数不是,则该常量会隐式转换为另一操作数的类型。
The right operand in a shift expression must have integer type
[Go 1.13]
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 implicitly converted to the type it would assume if the shift expression were
replaced by its left operand alone.
移位表达式中的右操作数必须是整数类型[Go 1.13]或是可由 uint 类型值表示的无类型常量。当非常量移位表达式的左操作数为无类型常量时,会首先将其隐式转换为假设移位表达式仅保留左操作数时所应具有的类型。
var a [1024]byte var s uint = 33 // The results of the following examples are given for 64-bit ints. var i = 1<<s // 1 has type int var j int32 = 1<<s // 1 has type int32; j == 0 var k = uint64(1<<s) // 1 has type uint64; k == 1<<33 var m int = 1.0<<s // 1.0 has type int; m == 1<<33 var n = 1.0<<s == j // 1.0 has type int32; n == true var o = 1<<s == 2<<s // 1 and 2 have type int; o == false var p = 1<<s == 1<<33 // 1 has type int; p == true var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift var v1 float32 = 1<<s // illegal: 1 has type float32, cannot shift var v2 = string(1<<s) // illegal: 1 is converted to a string, cannot shift var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression; w == 1<<33 var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33 // The results of the following examples are given for 32-bit ints, // which means the shifts will overflow. var mm int = 1.0<<s // 1.0 has type int; mm == 0 var oo = 1<<s == 2<<s // 1 and 2 have type int; oo == true var pp = 1<<s == 1<<33 // illegal: 1 has type int, but 1<<33 overflows int var xx = a[1.0<<s] // 1.0 has type int; xx == a[0] var bb = make([]byte, 1.0<<s) // 1.0 has type int; len(bb) == 0
Operator precedence¶ 运算符优先级 ¶
Unary operators have the highest precedence.
As the ++ 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 ||
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 // x 42 + a - b // (42 + a) - b 23 + 3*x[i] // 23 + (3 * x[i]) x <= f() // x <= f() ^a >> b // (^a) >> b f() || g() // f() || g() x == y+1 && <-chanInt > 0 // (x == (y+1)) && ((<-chanInt) > 0)
Arithmetic operators¶ 算术运算符 ¶
Arithmetic operators apply to numeric values and yield a result of the same
type as the first operand. The four standard arithmetic operators (+,
-, *, /) 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 << integer >= 0 >> right shift integer >> integer >= 0
If the operand type is a type parameter,
the operator must apply to each type in that type set.
The operands are represented as values of the type argument that the type parameter
is instantiated with, and the operation is computed
with the precision of that type argument. For example, given the function:
如果操作数类型为类型参数,则该运算符必须适用于该类型集合中的每种类型。操作数以类型参数实例化时所用的类型实参值表示,运算过程则采用该类型实参的精度进行计算。例如,给定函数:
func dotProduct[F ~float32|~float64](v1, v2 []F) F {
var s F
for i, x := range v1 {
y := v2[i]
s += x * y
}
return s
}
the product x * y and the addition s += x * y
are computed with float32 or float64 precision,
respectively, depending on the type argument for F.
乘积 x * y 和加法 s += x * y 的计算分别采用 float32 或 float64 精度,具体取决于 F 的类型参数。
Integer operators¶
For two integer values x and y, the integer quotient
q = x / y and remainder r = x % y satisfy the following
relationships:
对于两个整数值 x 和 y ,其整数商 q = x / y 与余数 r = x % y 满足如下关系:
x = q*y + r and |r| < |y|
with x / y truncated towards zero
("truncated division").
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 整型的最小负值,由于二进制补码整数溢出,商 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, which must be non-negative. If the shift count is negative at run time,
a run-time panic occurs.
The shift operators implement arithmetic shifts if the left operand is a signed
integer and logical shifts if it is an unsigned integer.
There is no upper limit on the shift count. Shifts behave
as if the left operand is shifted 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
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".
对于无符号整数值,运算 + 、 - 、 * 和 << 均按模 2 n 计算(其中 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.
Overflow does not cause a run-time panic.
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.
An explicit floating-point type conversion rounds to
the precision of the target type, preventing fusion that would discard that rounding.
实现可将多个浮点运算合并为单个融合操作,甚至跨越多个语句,并产生与单独执行和舍入指令所得结果不同的值。显式浮点类型转换会舍入至目标类型的精度,从而阻止了可能舍弃该舍入的融合操作。
For instance, some architectures provide a "fused multiply and add" (FMA) instruction
that computes x*y + z without rounding the intermediate result x*y.
These examples show when a Go implementation can use that instruction:
例如,某些架构提供"融合乘加"(FMA)指令,可在不进行中间结果 x*y 舍入的情况下计算 x*y + z 。这些示例展示了 Go 实现何时可使用该指令:
// 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 of comparable types.
The ordering operators <, <=, >, and >=
apply to operands of ordered types.
These terms and the result of the comparisons are defined as follows:
相等运算符 == 和 != 适用于可比较类型的操作数。排序运算符 < , <= , > , 及 >= 适用于有序类型的操作数。相关术语及比较结果定义如下:
-
Boolean types are comparable.
Two boolean values are equal if they are either both
trueor bothfalse.
布尔类型是可比较的。两个布尔值相等的前提是它们要么同为true,要么同为false。 -
Integer types are comparable and ordered.
Two integer values are compared in the usual way.
整数类型可比较且有序。两个整数值按常规方式进行比较。 -
Floating-point types are comparable and ordered.
Two floating-point values are compared as defined by the IEEE 754 standard.
浮点类型是可比较且有序的。两个浮点数值按照 IEEE 754 标准所定义的方式进行比较。 -
Complex types are comparable.
Two complex values
uandvare equal if bothreal(u) == real(v)andimag(u) == imag(v).
复数类型是可比较的。当real(u) == real(v)与imag(u) == imag(v)同时成立时,两个复数u和v被视为相等。 -
String types are comparable and ordered.
Two string values are compared lexically byte-wise.
字符串类型可比较且有序。两个字符串值按字节顺序进行字典序比较。 -
Pointer types 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.
指针类型是可比较的。若两个指针指向同一变量或两者值均为nil,则它们相等。指向不同零大小变量的指针可能相等也可能不相等。 -
Channel types are comparable.
Two channel values are equal if they were created by the same call to
makeor if both have valuenil.
通道类型是可比较的。两个通道值在以下情况下相等:它们由相同的make调用创建,或者两者均具有值nil。 -
Interface types that are not type parameters are comparable.
Two interface values are equal if they have identical dynamic types
and equal dynamic values or if both have value
nil.
非类型参数的接口类型是可比较的。两个接口值在它们具有相同的动态类型和相等的动态值,或如果两者都具有值nil时相等。 -
A value
xof non-interface typeXand a valuetof interface typeTcan be compared if typeXis comparable andXimplementsT. They are equal ift's dynamic type is identical toXandt's dynamic value is equal tox.
当类型X可比较且X实现了T时,非接口类型X的值x与接口类型T的值t可以进行比较。若t的动态类型与X完全相同,且t的动态值等于x,则二者相等。 -
Struct types are comparable if all their field types are comparable.
Two struct values are equal if their corresponding
non-blank field values are equal.
The fields are compared in source order, and comparison stops as
soon as two field values differ (or all fields have been compared).
结构体类型在其所有字段类型均可比较时是可比较的。若两个结构体值对应的非空白字段值均相等,则它们相等。字段按源代码顺序进行比较,一旦两个字段值不相等(或所有字段均已比较完毕),比较即会停止。 -
Array types are comparable if their array element types are comparable.
Two array values are equal if their corresponding element values are equal.
The elements are compared in ascending index order, and comparison stops
as soon as two element values differ (or all elements have been compared).
若数组元素类型可比较,则数组类型也可比较。两个数组值相等的前提是其对应元素值均相等。元素按索引升序逐一比较,一旦出现不同值即停止比较(或所有元素比较完毕)。 -
Type parameters are comparable if they are strictly comparable (see below).
类型参数在严格可比较(见下文)时具有可比性。
A comparison of two interface values with identical dynamic types
causes a run-time panic if that type
is 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 types 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 )
A type is strictly comparable if it is comparable and not an interface
type nor composed of interface types.
Specifically:
当某类型是可比较的,且既不是接口类型,也不是由接口类型组成时,该类型就是严格可比较的。具体来说:
-
Boolean, numeric, string, pointer, and channel types are strictly comparable.
布尔、数值、字符串、指针和通道类型是严格可比较的。 -
Struct types are strictly comparable if all their field types are strictly comparable.
如果结构体类型的所有字段类型都是严格可比较的,则该结构体类型也是严格可比较的。 -
Array types are strictly comparable if their array element types are strictly comparable.
数组类型在其数组元素类型严格可比较的前提下是严格可比较的。 -
Type parameters are strictly comparable if all types in their type set are strictly comparable.
类型参数在其类型集合中的所有类型均为严格可比较时,该类型参数才是严格可比较的。
Logical operators¶ 逻辑运算符 ¶
Logical operators apply to boolean values
and yield a result of the same type as the operands.
The left operand is evaluated, and then the right if the condition requires it.
逻辑运算符作用于布尔值,并产生与操作数相同类型的结果。首先对左操作数进行求值,若条件需要则接着对右操作数求值。
&& conditional AND p && q is "if p then q else false" || conditional OR p || q is "if p then true else q" ! NOT !p is "not p"
Address operators¶ 取址运算符 ¶
For an operand 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 会生成一个指向 x 的 *T 类型指针。该操作数必须是可寻址的,即必须是变量、指针解引用或切片索引操作;或是可寻址结构体操作数的字段选择器;或是可寻址数组的数组索引操作。作为可寻址性要求的例外情况, 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 表示由 x 所指向的 T 类型变量。若 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
Receive operator¶ 接收操作符 ¶
For an operand ch whose core type is a
channel,
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.
对于核心类型为通道的操作数 ch ,其接收操作 <-ch 的值即为从通道 ch 接收到的值。通道方向必须允许接收操作,且接收操作的类型即为通道的元素类型。该表达式会阻塞直至有值可接收。从 nil 通道接收将永久阻塞。对已关闭通道的接收操作可立即进行,在接收完所有先前发送的值后,将返回元素类型的零值。
v1 := <-ch v2 = <-ch f(<-ch) <-strobe // wait until clock pulse and discard received value
A receive expression used in an assignment statement or initialization of the special form
赋值语句或特殊形式初始化中使用的接收表达式
x, ok = <-ch x, ok := <-ch var x, ok = <-ch var x, ok T = <-ch
yields an additional untyped boolean result reporting whether the
communication succeeded. The value of 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¶ 转化 ¶
A conversion changes the type of an expression
to the type specified by the conversion.
A conversion may appear literally in the source, or it may be implied
by the context in which an expression appears.
转换将表达式的类型更改为转换所指定的类型。转换可能在源代码中字面显示,也可能由表达式出现的上下文暗示。
An explicit conversion is an expression of the form T(x)
where T is a type and x is an expression
that can be converted to type T.
显式转换是形式为 T(x) 的表达式,其中 T 为类型, x 是可转换为 T 类型的表达式。
Conversion = Type "(" Expression [ "," ] ")" .
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:
若类型以操作符 * 或 <- 开头,或类型以关键字 func 开头且无结果列表,则必要时必须加括号以避免歧义:
*Point(p) // same as *(Point(p)) (*Point)(p) // p is converted to *Point <-chan int(c) // same as <-(chan int(c)) (<-chan int)(c) // c is converted to <-chan int func()(x) // function signature func() x (func())(x) // x is converted to func() (func() int)(x) // x is converted to func() int func() int(x) // x is converted to func() int (unambiguous)
A constant value 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 explicitly converted to a
string type using the
same rule
as for non-constant x.
若 x 可由 T 的值表示,则常量值 x 可转换为类型 T 。作为特例,整型常量 x 可按照与非常量 x 相同的规则显式转换为字符串类型。
Converting a constant to a type that is not a type parameter
yields a typed constant.
将常量转换为非类型参数类型会产生类型化常量。
uint(iota) // iota value of type uint
float32(2.718281828) // 2.718281828 of type float32
complex128(1) // 1.0 + 0.0i of type complex128
float32(0.49999999) // 0.5 of type float32
float64(-1e-1000) // 0.0 of type float64
string('x') // "x" of type string
string(0x266c) // "♬" of type string
myString("foo" + "bar") // "foobar" of type myString
string([]byte{'a'}) // not a constant: []byte{'a'} is not a constant
(*int)(nil) // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
int(1.2) // illegal: 1.2 cannot be represented as an int
string(65.0) // illegal: 65.0 is not an integer constant
Converting a constant to a type parameter yields a non-constant value of that type,
with the value represented as a value of the type argument that the type parameter
is instantiated with.
For example, given the function:
将常量转换为类型参数会生成该类型的非常量值,其值表现为类型参数实例化时所使用的类型实参的值。例如,给定函数:
func f[P ~float32|~float64]() {
… P(1.1) …
}
the conversion P(1.1) results in a non-constant value of type P
and the value 1.1 is represented as a float32 or a float64
depending on the type argument for f.
Accordingly, if f is instantiated with a float32 type,
the numeric value of the expression P(1.1) + 1.2 will be computed
with the same precision as the corresponding non-constant float32
addition.
转换 P(1.1) 会导致类型 P 的非常量值,而值 1.1 会根据 f 的类型参数表示为 float32 或 float64 。因此,若 f 以 float32 类型实例化,表达式 P(1.1) + 1.2 的数值将以与对应非常量 float32 加法相同的精度计算。
A non-constant value x can be converted to type T
in any of these cases:
在以下任一情况下,非常量值 x 均可转换为类型 T :
-
xis assignable toT.
x可分配给T -
ignoring struct tags (see below),
x's type andTare not type parameters but have identical underlying types.
忽略结构体标签(详见下文),x的类型和T并非类型参数,但具有相同的底层类型。 -
ignoring struct tags (see below),
x's type andTare pointer types that are not named types, and their pointer base types are not type parameters but have identical underlying types.
忽略结构体标签(见下文),x的类型与T均为未命名类型的指针类型,其指针基类型虽非类型参数,却具有完全相同的底层类型。 -
x's type andTare both integer or floating point types.
x's type andT均为整数或浮点类型。 -
x's type andTare both complex types.
x的类型和T均为复杂类型。 -
xis an integer or a slice of bytes or runes andTis a string type.
x为整数、字节切片或符文切片,T为字符串类型。 -
xis a string andTis a slice of bytes or runes.
x是字符串,T是字节切片或符文切片。 -
xis a slice,Tis an array [Go 1.20] or a pointer to an array [Go 1.17], and the slice and array types have identical element types.
x是切片,T是数组 [Go 1.20] 或数组指针 [Go 1.17],且切片与数组类型具有相同的元素类型。
Additionally, if T or x's type V are type
parameters, x
can also be converted to type T if one of the following conditions applies:
此外,如果 T 或 x 的类型 V 是类型参数,在满足以下任一条件时, x 也可转换为 T 类型:
-
Both
VandTare type parameters and a value of each type inV's type set can be converted to each type inT's type set.
V和T均为类型参数,且V类型集中的每个类型值均可转换为T类型集中的每个类型。 -
Only
Vis a type parameter and a value of each type inV's type set can be converted toT.
仅当V是类型参数,并且V类型集中的每个类型的值都可以转换为T。 -
Only
Tis a type parameter andxcan be converted to each type inT's type set.
仅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.
当整数类型间转换时,若值为有符号整数,则进行符号扩展至隐式无限精度;若为无符号整数,则进行零扩展。随后该值会被截断以适配目标类型的大小。例如,若v := uint16(0x10F0),则uint32(int8(v)) == 0xFFFFFFF0。此类转换始终产生有效值,且不会提示溢出情况。 -
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
xof typefloat32may 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.1may use more than 32 bits of precision, butfloat32(x + 0.1)does not.
当将整数或浮点数转换为浮点类型,或将复数转换为另一种复数类型时,结果值会四舍五入到目标类型指定的精度。例如,类型为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 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 bytes []byte string(bytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'}) // "hellø" type myByte byte string([]myByte{'w', 'o', 'r', 'l', 'd', '!'}) // "world!" myString([]myByte{'\xf0', '\x9f', '\x8c', '\x8d'}) // "🌍" -
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 runes []rune string(runes{0x767d, 0x9d6c, 0x7fd4}) // "\u767d\u9d6c\u7fd4" == "白鵬翔" type myRune rune string([]myRune{0x266b, 0x266c}) // "\u266b\u266c" == "♫♬" myString([]myRune{0x1f30e}) // "\U0001f30e" == "🌎" -
Converting a value of a string type to a slice of bytes type
yields a non-nil slice whose successive elements are the bytes of the string.
The capacity of the resulting slice is
implementation-specific and may be larger than the slice length.
将字符串类型的值转换为字节切片类型会得到一个非空切片,其连续元素即为字符串的字节序列。生成切片的容量由具体实现决定,可能大于切片长度。[]byte("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []byte("") // []byte{} bytes("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} []myByte("world!") // []myByte{'w', 'o', 'r', 'l', 'd', '!'} []myByte(myString("🌏")) // []myByte{'\xf0', '\x9f', '\x8c', '\x8f'} -
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.
The capacity of the resulting slice is
implementation-specific and may be larger than the slice length.
将字符串类型的值转换为 rune 切片类型会生成包含该字符串各独立 Unicode 码点的切片。生成切片的容量取决于具体实现,可能大于切片长度。[]rune(myString("白鵬翔")) // []rune{0x767d, 0x9d6c, 0x7fd4} []rune("") // []rune{} runes("白鵬翔") // []rune{0x767d, 0x9d6c, 0x7fd4} []myRune("♫♬") // []myRune{0x266b, 0x266c} []myRune(myString("🌐")) // []myRune{0x1f310} -
Finally, for historical reasons, an integer value may be converted to a string type.
This form of conversion yields a string containing the (possibly multi-byte) UTF-8
representation of the Unicode code point with the given integer value.
Values outside the range of valid Unicode code points are converted to
"\uFFFD".string('a') // "a" string(65) // "A" string('\xf8') // "\u00f8" == "ø" == "\xc3\xb8" string(-1) // "\ufffd" == "\xef\xbf\xbd" type myString string myString('\u65e5') // "\u65e5" == "日" == "\xe6\x97\xa5"Note: This form of conversion may eventually be removed from the language. Thego vettool flags certain integer-to-string conversions as potential errors. Library functions such asutf8.AppendRuneorutf8.EncodeRuneshould be used instead.
最后,出于历史原因,整数值可被转换为字符串类型。这种转换形式会生成一个字符串,其中包含给定整数值对应的 Unicode 码点的(可能是多字节的)UTF-8 表示形式。超出有效 Unicode 码点范围的值将被转换为"\uFFFD"。注意:该转换形式最终可能会从语言中移除。go vet工具会将某些整型到字符串的转换标记为潜在错误,应改用utf8.AppendRune或utf8.EncodeRune等库函数。
Conversions from slice to array or array pointer¶
从切片到数组或数组指针的转换 ¶
Converting a slice to an array yields an array containing the elements of the underlying array of the slice.
Similarly, converting a slice to an array pointer yields a pointer to the underlying array of the slice.
In both cases, if the length of the slice is less than the length of the array,
a run-time panic occurs.
将切片转换为数组会得到一个包含该切片底层数组元素的数组。同样地,将切片转换为数组指针会得到指向该切片底层数组的指针。这两种情况下,若切片长度小于数组长度,均会引发运行时 panic。
s := make([]byte, 2, 4) a0 := [0]byte(s) a1 := [1]byte(s[1:]) // a1[0] == s[1] a2 := [2]byte(s) // a2[0] == s[0] a4 := [4]byte(s) // panics: len([4]byte) > len(s) s0 := (*[0]byte)(s) // s0 != nil s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1] s2 := (*[2]byte)(s) // &s2[0] == &s[0] s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := [0]string(t) // ok for nil slice t t1 := (*[0]string)(t) // t1 == nil t2 := (*[1]string)(t) // panics: len([1]string) > len(t) u := make([]byte, 0) u0 := (*[0]byte)(u) // u0 != nil
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.
只要在布尔值、数值或字符串类型操作数合法的场合,无类型的布尔值、数值及字符串常量都可以作为操作数使用。
A constant comparison always yields
an untyped boolean constant. If the left operand of a constant
shift expression is an untyped constant, the
result is an integer constant; otherwise it is a constant of the same
type as the left operand, which must be of
integer type.
常量比较总是产生一个无类型的布尔常量。如果常量位移表达式的左操作数是一个无类型常量,则结果是一个整数常量;否则,结果是与左操作数类型相同的常量,该左操作数必须是整数类型。
Any other operation on untyped constants results in an untyped constant of the
same kind; that is, a boolean, integer, floating-point, complex, or string
constant.
If the untyped operands of a binary operation (other than a shift) are of
different kinds, the result is of the operand's kind that appears later in this
list: integer, rune, floating-point, complex.
For example, an untyped integer constant divided by an
untyped complex constant yields an untyped complex constant.
对无类型常量的任何其他操作都会产生同一种类的无类型常量,即布尔型、整型、浮点型、复数型或字符串常量。若二元运算(位移运算除外)中的无类型操作数种类不同,结果将采用操作数列表中靠后的种类:整型、符文型、浮点型、复数型。例如,无类型整型常量除以无类型复数常量将产生无类型复数常量。
const a = 2 + 3.0 // a == 5.0 (untyped floating-point constant) const b = 15 / 4 // b == 3 (untyped integer constant) const c = 15 / 4.0 // c == 3.75 (untyped floating-point constant) const Θ float64 = 3/2 // Θ == 1.0 (type float64, 3/2 is integer division) const Π float64 = 3/2. // Π == 1.5 (type float64, 3/2. is float division) const d = 1 << 3.0 // d == 8 (untyped integer constant) const e = 1.0 << 3 // e == 8 (untyped integer constant) const f = int32(1) << 33 // illegal (constant 8589934592 overflows int32) const g = float64(2) >> 1 // illegal (float64(2) is a typed floating-point constant) const h = "foo" > "bar" // h == true (untyped boolean constant) const j = true // j == true (untyped boolean constant) const k = 'w' + 1 // k == 'x' (untyped rune constant) const l = "hi" // l == "hi" (untyped string constant) const m = string(k) // m == "x" (type string) const Σ = 1 - 0.707i // (untyped complex constant) const Δ = Σ + 2.0e-4 // (untyped complex constant) const Φ = iota*1i - 1/1i // (untyped complex constant)
Applying the built-in function complex to untyped
integer, rune, or floating-point constants yields
an untyped complex constant.
对无类型整数、rune 或浮点常量应用内置函数 complex 会产生无类型复数常量。
const ic = complex(0, c) // ic == 3.75i (untyped complex constant) const iΘ = complex(0, Θ) // iΘ == 1i (type complex128)
Constant expressions are always evaluated exactly; intermediate values and the
constants themselves may require precision significantly larger than supported
by any predeclared type in the language. The following are legal declarations:
常量表达式总是被精确计算;中间值及常量本身所需的精度可能远超语言中任何预声明类型的支持范围。以下为合法声明:
const Huge = 1 << 100 // Huge == 1267650600228229401496703205376 (untyped integer constant) const Four int8 = Huge >> 98 // Four == 4 (type int8)
The divisor of a constant division or remainder operation must not be zero:
常量除法或取余运算的除数不得为零:
3.14 / 0.0 // illegal: division by zero
The values of typed constants must always be accurately
representable by values
of the constant type. The following constant expressions are illegal:
类型化常量的值必须始终能被常量类型的值准确表示。以下常量表达式是非法的:
uint(-1) // -1 cannot be represented as a uint int(3.14) // 3.14 cannot be represented as an int int64(Huge) // 1267650600228229401496703205376 cannot be represented as an int64 Four * 300 // operand 300 cannot be represented as an int8 (type of Four) Four * 100 // product 400 cannot be represented as an int8 (type of Four)
The mask used by the unary bitwise complement operator ^ matches
the rule for non-constants: the mask is all 1s for unsigned constants
and -1 for signed and untyped constants.
一元按位补码运算符 ^ 使用的掩码遵循非常量规则:无符号常量掩码为全 1,有符号及无类型常量掩码为-1。
^1 // untyped integer constant, equal to -2 uint8(^1) // illegal: same as uint8(-2), -2 cannot be represented as a uint8 ^uint8(1) // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE) int8(^1) // same as int8(-2) ^int8(1) // same as -1 ^ int8(1) = -2
Implementation restriction: A compiler may use rounding while
computing untyped floating-point or complex constant expressions; see
the implementation restriction in the section
on constants. This rounding may cause a
floating-point constant expression to be invalid in an integer
context, even if it would be integral when calculated using infinite
precision, and vice versa.
实现限制:编译器在计算无类型浮点数或复数常量表达式时可能采用舍入处理,详见常量章节中的实现限制条款。该舍入可能导致浮点数常量表达式在整数上下文中失效——即便使用无限精度计算本应得到整数结果,反之亦然。
Order of 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,
receive operations,
and binary logical operations
are evaluated in lexical left-to-right order.
在包级别,初始化依赖关系决定了变量声明中各个初始化表达式的求值顺序。否则,当计算表达式、赋值或返回语句的操作数时,所有函数调用、方法调用、接收操作以及二元逻辑运算均按词法从左到右的顺序进行求值。
For example, in the (function-local) assignment
例如,在(函数局部)赋值中
y[f()], ok = g(z || h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order
f(), h() (if z
evaluates to false), 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 and z is not specified,
except as required lexically. For instance, g
cannot be called before its arguments are evaluated.
函数调用和通信按顺序 f() 、 h() (若 z 求值为假)、 i() 、 j() 、 <-c 、 g() 和 k() 发生。然而,这些事件相对于 x 的求值与索引,以及 y 和 z 的求值顺序均未明确规定,除词法要求外。例如, g 在其参数被求值前不可调用。
a := 1
f := func() int { a++; return a }
x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
At package level, initialization dependencies override the left-to-right rule
for individual initialization expressions, but not for operands within each
expression:
在包级别,初始化依赖项会覆盖单个初始化表达式的从左到右规则,但不会覆盖每个表达式内部的操作数:
var a, b, c = f() + v(), g(), sqr(u()) + v()
func f() int { return c }
func g() int { return a }
func sqr(x int) int { return x*x }
// functions u and v are independent of all other variables and functions
The function calls happen in the order
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 .
Terminating statements¶ 终止语句 ¶
A terminating statement interrupts the regular flow of control in
a block. The following statements are terminating:
终止语句会中断块中的常规控制流。以下语句属于终止语句:
-
A "return" or
"goto" statement.
-
A call to the built-in function
panic.
对内置函数panic的调用。 -
A block in which the statement list ends in a terminating statement.
语句列表以终止语句结尾的块。 -
An "if" statement in which:
"if"语句,其中:- the "else" branch is present, and
存在"else"分支,且 - both branches are terminating statements.
两个分支都是终止语句。
- the "else" branch is present, and
-
A "for" statement in which:
一个“for”语句,其中:- there are no "break" statements referring to the "for" statement, and
没有针对 for 语句的 break 语句, - the loop condition is absent, and
循环条件缺失,且 - the "for" statement does not use a range clause.
"for"语句不使用范围子句。
- there are no "break" statements referring to the "for" statement, and
-
A "switch" statement in which:
一个"switch"语句,其中:- there are no "break" statements referring to the "switch" statement,
没有针对"switch"语句的"break"语句 - 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.
每种情况下的语句列表,包括默认情况,都以终止语句或可能带标签的“fallthrough”语句结束。
- there are no "break" statements referring to the "switch" statement,
-
A "select" statement in which:
"select"语句,其中:- there are no "break" statements referring to the "select" statement, and
select 语句没有对应的"break"语句,并且 - the statement lists in each case, including the default if present,
end in a terminating statement.
每种情况下的语句列表,包括默认情况(如果存在),均以终止语句结束。
- there are no "break" statements referring to the "select" statement, and
-
A labeled statement labeling
a terminating statement.
用于标记终止语句的带标签语句。
All other statements are not terminating.
所有其他语句均不会终止。
A statement list ends in a terminating statement if the list
is not empty and its final non-empty statement is terminating.
语句列表以终止语句结束,前提是该列表非空且其最后一个非空语句为终止语句。
Empty statements¶ 空语句 ¶
The empty statement does nothing.
空语句不执行任何操作。
EmptyStmt = .
Labeled statements¶ 标记语句 ¶
A labeled statement may be the target of a goto,
break or continue statement.
带标签的语句可能成为 goto 、 break 或 continue 语句的跳转目标。
LabeledStmt = Label ":" Statement . Label = identifier .
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.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice unsafe.SliceData unsafe.String unsafe.StringData
h(x+y)
f.Close()
<-ch
(<-ch)
len("foo") // illegal if len is the built-in function
Send statements¶ 发送报表 ¶
A send statement sends a value on a channel.
The channel expression's core type
must be a channel,
the channel direction must permit send operations,
and the type of the value to be sent must be assignable
to the channel's element type.
发送语句通过通道传递一个值。通道表达式的核心类型必须是通道类型,通道方向需允许发送操作,且待发送值的类型必须可分配给通道的元素类型。
SendStmt = Channel "<-" Expression . Channel = Expression .
Both the channel and the value expression are evaluated before communication
begins. Communication blocks until the send can proceed.
A send on an unbuffered channel can proceed if a receiver is ready.
A send on a buffered channel can proceed if there is room in the buffer.
A send on a closed channel proceeds by causing a run-time panic.
A send on a nil channel blocks forever.
通道和值表达式在通信开始前均会被求值。通信会阻塞直至发送操作得以执行。无缓冲通道上的发送操作在接收方就绪时可执行。缓冲通道上的发送操作在缓冲区有空位时可执行。向已关闭通道发送数据会导致运行时恐慌。向 nil 通道发送数据将永久阻塞。
ch <- 3 // send value 3 to channel 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.
"++"和"--"语句将其操作数递增或递减一个无类型常量 1 。与赋值操作类似,操作数必须是可寻址的或为映射索引表达式。
IncDecStmt = Expression ( "++" | "--" ) .
The following assignment statements are semantically
equivalent:
以下赋值语句在语义上是等价的:
IncDec statement Assignment x++ x += 1 x-- x -= 1
Assignment statements¶ 赋值语句 ¶
An assignment replaces the current value stored in a variable
with a new value specified by an expression.
An assignment statement may assign a single value to a single variable, or multiple values to a
matching number of variables.
赋值操作将变量中存储的当前值替换为由表达式指定的新值。赋值语句可将单个值赋给单个变量,或将多个值赋给匹配数量的多个变量。
Assignment = ExpressionList assign_op ExpressionList . assign_op = [ add_op | mul_op ] "=" .
Each left-hand side operand must be addressable,
a map index expression, or (for = assignments only) the
blank identifier.
Operands may be parenthesized.
左侧操作数必须是可寻址的、映射索引表达式,或(仅适用于 = 赋值操作)空标识符。操作数可以带括号。
x = 1 *p = f() a[i] = 23 (k) = <-ch // same as: 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,
元组赋值将多值操作的各个元素分配给一组变量,分为两种形式。第一种形式中,右操作数为单个多值表达式,如函数调用、通道或映射操作,或类型断言。左侧操作数数量必须与值数量匹配。例如,若 f 是返回两个值的函数,
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:
将第一个值赋给 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
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 is []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 implicitly 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 implicitly converted to type
bool.
如果将一个无类型布尔值赋值给接口类型变量或空白标识符,它会首先被隐式转换为bool类型。
When a value is assigned to a variable, only the data that is stored in the variable
is replaced. If the value contains a reference,
the assignment copies the reference but does not make a copy of the referenced data
(such as the underlying array of a slice).
当变量被赋予新值时,仅会替换变量中存储的数据。若该值包含引用,赋值操作将复制该引用,但不会复制被引用的数据(例如切片的底层数组)。
var s1 = []int{1, 2, 3}
var s2 = s1 // s2 stores the slice descriptor of s1
s1 = s1[:1] // s1's length is 1 but it still shares its underlying array with s2
s2[0] = 42 // setting s2[0] changes s1[0] as well
fmt.Println(s1, s2) // prints [42] [42 2 3]
var m1 = make(map[string]int)
var m2 = m1 // m2 stores the map descriptor of m1
m1["foo"] = 42 // setting m1["foo"] changes m2["foo"] as well
fmt.Println(m2["foo"]) // prints 42
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.
"If"语句根据布尔表达式的值指定两个分支的条件执行。若表达式计算结果为 true,则执行"if"分支;否则,如果存在"else"分支,则执行该分支。
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
if x > max {
x = max
}
The expression may be preceded by a simple statement, which
executes before the expression is evaluated.
表达式前面可以加上一个简单语句,该语句会在表达式求值之前执行。
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
Switch statements¶
"Switch" statements provide multi-way execution.
An expression or type is compared to the "cases"
inside the "switch" to determine which branch
to execute.
"switch"语句提供多路执行功能。通过将表达式或类型与"switch"内部的"case"进行比较,决定执行哪个分支。
SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
There are two forms: expression switches and type switches.
In an expression switch, the cases contain expressions that are compared
against the value of the switch expression.
In a type switch, the cases contain types that are compared against the
type of a specially annotated switch expression.
The switch expression is evaluated exactly once in a switch statement.
有两种形式:表达式开关和类型开关。在表达式开关中,分支包含与开关表达式值进行比较的表达式;在类型开关中,分支包含与特殊注解的开关表达式类型进行比较的类型。在开关语句中,开关表达式只评估一次。
Expression switches¶
In an expression switch,
the switch expression is evaluated and
the case expressions, which need not be constants,
are evaluated left-to-right and top-to-bottom; the first one that equals the
switch expression
triggers execution of the statements of the associated case;
the other cases are skipped.
If no case matches and there is a "default" case,
its statements are executed.
There can be at most one default case and it may appear anywhere in the
"switch" statement.
A missing switch expression is equivalent to the boolean value
true.
在表达式 switch 中,首先求值 switch 表达式;case 表达式(无需为常量)则按从左到右、从上到下的顺序求值,首个与 switch 表达式匹配的 case 将触发执行其关联语句,其余 case 将被跳过。若所有 case 均不匹配且存在"default"分支,则执行其语句。最多只能有一个 default 分支,且可出现在"switch"语句的任意位置。缺失 switch 表达式时,其值默认为布尔值 true 。
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .
If the switch expression evaluates to an untyped constant, it is first implicitly
converted to its default type.
The predeclared untyped value nil cannot be used as a switch expression.
The switch expression type must be comparable.
如果 switch 表达式求值为无类型常量,则首先会隐式转换为默认类型。预声明的无类型值 nil 不能用作 switch 表达式。switch 表达式类型必须可比较。
If a case expression is untyped, it is first implicitly 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 ;每个 case 表达式 x 都将与该变量 t 的值进行相等性测试。
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"语句结尾。在表达式 switch 中,"fallthrough"语句可作为除最后一个子句之外所有子句的最终语句出现。
The switch expression may be preceded by a simple statement, which
executes before the expression is evaluated.
switch 表达式前可放置一条简单语句,该语句执行于表达式求值之前。
switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}
switch x := f(); { // missing switch expression means "true"
case x < 0: return -x
default: return x
}
switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}
Implementation restriction: A compiler may disallow multiple case
expressions evaluating to the same constant.
For instance, the current compilers disallow duplicate integer,
floating point, or string constants in case expressions.
实现限制:编译器可能禁止多个 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 keyword type rather than an actual type:
类型切换比较的是类型而非值,其结构类似于表达式切换。它通过一种特殊的切换表达式来标识——该表达式采用类型断言的形式,但使用关键词 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, but not a
type parameter, and each non-interface type
T listed in a case must implement the type of x.
The types listed in the cases of a type switch must all be
different.
然后,各分支会将实际类型 T 与表达式 x 的动态类型进行匹配。如同类型断言一样, x 必须是接口类型,而非类型参数,且每个分支中列出的非接口类型 T 都必须实现 x 的接口类型。类型选择中各分支列出的类型必须互不相同。
TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
TypeCaseClause = TypeSwitchCase ":" StatementList .
TypeSwitchCase = "case" TypeList | "default" .
The TypeSwitchGuard may include a
short variable declaration.
When that form is used, the variable is declared at the end of the
TypeSwitchCase in the implicit block of each clause.
In clauses with a case listing exactly one type, the variable
has that type; otherwise, the variable has the type of the expression
in the TypeSwitchGuard.
TypeSwitchGuard 可能包含一个短变量声明。采用这种形式时,变量会声明在每个子句隐式代码块末尾的 TypeSwitchCase 中。在 case 仅列出一个类型的子句里,变量具有该类型;否则,变量类型与 TypeSwitchGuard 中的表达式类型一致。
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.
在类型分支中,一个分支可选用预声明标识符 nil 而非具体类型;当 TypeSwitchGuard 中的表达式为 nil 接口值时,将选择该分支。 nil 分支最多只能存在一个。
Given an expression x of type interface{},
the following type switch:
给定一个类型为 interface{} 的 x 表达式,以下类型转换:
switch i := x.(type) {
case nil:
printString("x is nil") // type of i is type of x (interface{})
case int:
printInt(i) // type of i is int
case float64:
printFloat64(i) // type of i is float64
case func(int) float64:
printFunction(i) // type of i is func(int) float64
case bool, string:
printString("type is bool or string") // type of i is type of x (interface{})
default:
printString("don't know the type") // type of i is type of x (interface{})
}
could be rewritten: 可改写为:
v := x // x is evaluated exactly once
if v == nil {
i := v // type of i is type of x (interface{})
printString("x is nil")
} else if i, isInt := v.(int); isInt {
printInt(i) // type of i is int
} else if i, isFloat64 := v.(float64); isFloat64 {
printFloat64(i) // type of i is float64
} else if i, isFunc := v.(func(int) float64); isFunc {
printFunction(i) // type of i is func(int) float64
} else {
_, isBool := v.(bool)
_, isString := v.(string)
if isBool || isString {
i := v // type of i is type of x (interface{})
printString("type is bool or string")
} else {
i := v // type of i is type of x (interface{})
printString("don't know the type")
}
}
A type parameter or a generic type
may be used as a type in a case. If upon instantiation that type turns
out to duplicate another entry in the switch, the first matching case is chosen.
类型参数或泛型类型可用作 case 中的类型。若在实例化时该类型与 switch 中的另一条目重复,则选择第一个匹配的 case。
func f[P any](x any) int {
switch x.(type) {
case P:
return 0
case string:
return 1
case []P:
return 2
case []byte:
return 3
default:
return 4
}
}
var v1 = f[string]("foo") // v1 == 0
var v2 = f[byte]([]byte{}) // v2 == 2
The type switch guard may be preceded by a simple statement, which
executes before the guard is evaluated.
类型开关保护前可能带有一个简单语句,该语句在保护求值之前执行。
The "fallthrough" statement is not permitted in a type switch.
"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.
for 语句用于指定重复执行某个代码块。它有三种形式:迭代可由单一条件控制、for 子句控制或 range 子句控制。
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . Condition = Expression .
For statements with single condition¶
对于单条件语句 ¶
In its simplest form, a "for" statement specifies the repeated execution of
a block as long as a boolean condition evaluates to true.
The condition is evaluated before each iteration.
If the condition is absent, it is equivalent to the boolean value
true.
在最基本的形式中,“for”语句指定只要布尔条件评估为真,就重复执行代码块。该条件在每次迭代前进行评估。若条件缺失,则等同于布尔值 true 。
for a < b {
a *= 2
}
For statements with for clause¶
对于带有 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.
带有 ForClause 的"for"语句同样受其条件控制,但此外它还可指定初始语句和后置语句,例如赋值语句、递增或递减语句。初始语句可以是短变量声明,但后置语句不得使用短变量声明。
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . InitStmt = SimpleStmt . PostStmt = SimpleStmt .
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 子句中的任何元素均可为空,但除非仅存在条件语句,否则分号必不可少。若条件缺省,则相当于布尔值 true 。
for cond { S() } is the same as for ; cond ; { S() }
for { S() } is the same as for true { S() }
Each iteration has its own separate declared variable (or variables)
[Go 1.22].
The variable used by the first iteration is declared by the init statement.
The variable used by each subsequent iteration is declared implicitly before
executing the post statement and initialized to the value of the previous
iteration's variable at that moment.
每次迭代都拥有各自独立的声明变量(或多个变量)[Go 1.22]。首次迭代使用的变量由初始化语句声明。后续每次迭代使用的变量会在执行后续语句前隐式声明,并初始化为前次迭代变量此时的值。
var prints []func()
for i := 0; i < 5; i++ {
prints = append(prints, func() { println(i) })
i++
}
for _, p := range prints {
p()
}
prints 打印
1 3 5
Prior to [Go 1.22], iterations share one set of variables
instead of having their own separate variables.
In that case, the example above prints
在[ Go 1.22]之前,循环共享一组变量,而非各自拥有独立变量。此时上述示例输出
6 6 6
For statements with range clause¶
对于带有 range 子句的语句¶
A "for" statement with a "range" clause
iterates through all entries of an array, slice, string or map, values received on
a channel, integer values from zero to an upper limit [Go 1.22],
or values passed to an iterator function's yield function [Go 1.23].
For each entry it assigns iteration values
to corresponding iteration variables if present and then executes the block.
带有"range"子句的"for"语句可遍历数组、切片、字符串或映射的所有条目,接收通道中的值,从零到上限的整数值[Go 1.22],或传递给迭代器函数 yield 函数的值[Go 1.23]。对于每个条目,若存在迭代变量则为其分配对应的迭代值,随后执行代码块。
RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
The expression on the right in the "range" clause is called the range expression,
its core type must be
an array, pointer to an array, slice, string, map, channel permitting
receive operations, an integer, or
a function with specific signature (see below).
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 function, the maximum number of iteration variables depends on
the function signature.
If the range expression is a channel or integer, 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 子句等同于去除该标识符的同构子句。
The range expression x is evaluated before beginning the loop,
with one exception: if at most one iteration variable is present and x or
len(x) is constant,
the range expression is not evaluated.
范围表达式 x 在循环开始前被求值,仅有一个例外:若至多存在一个迭代变量,且 x 或 len(x) 为常量,则该范围表达式不会被求值。
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 integer value n integer type, or untyped int value i see below function, 0 values f func(func() bool) function, 1 value f func(func(V) bool) value v V function, 2 values f func(func(K, V) bool) key k K v V
-
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)-1and does not index into the array or slice itself. For anilslice, the number of iterations is 0.
对于数组、数组指针或切片值a,索引迭代值按递增顺序产生,从元素索引 0 开始。若最多存在一个迭代变量,range 循环将生成从 0 到len(a)-1的迭代值,且不会索引数组或切片本身。对于nil切片,迭代次数为 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.
对于字符串值,"range"子句从字节索引 0 开始遍历字符串中的 Unicode 码点。在连续迭代中,索引值将是字符串中连续 UTF-8 编码码点的首字节索引,而第二个值(类型为rune)则是对应码点的数值。若迭代遇到无效的 UTF-8 序列,第二个值将变为0xFFFD(Unicode 替换字符),且下次迭代将在字符串中前进一个字节。 -
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.
映射的迭代顺序未指定且无法保证不同迭代间一致。若迭代过程中删除了尚未遍历到的映射条目,则不会生成对应的迭代值。若在迭代期间创建了映射条目,该条目可能在本次迭代中生成,也可能被跳过。对于每个新增条目及不同迭代过程,该选择可能不同。若映射为nil,则迭代次数为 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.
对于通道,生成的迭代值是在通道上发送的连续值,直到通道关闭为止。若通道为nil,范围表达式将永久阻塞。 -
For an integer value
n, wherenis of integer type or an untyped integer constant, the iteration values 0 throughn-1are produced in increasing order. Ifnis of integer type, the iteration values have that same type. Otherwise, the type ofnis determined as if it were assigned to the iteration variable. Specifically: if the iteration variable is preexisting, the type of the iteration values is the type of the iteration variable, which must be of integer type. Otherwise, if the iteration variable is declared by the "range" clause or is absent, the type of the iteration values is the default type forn. Ifn<= 0, the loop does not run any iterations.
对于一个整数值n(其中n为整数类型或无类型整数常量),将按升序生成从 0 到n-1的迭代值。若n为整数类型,则迭代值具有相同类型;否则,n的类型将如同被赋值给迭代变量般确定。具体而言:若迭代变量已预先存在,则迭代值类型即为该迭代变量的类型(必须为整数类型);若迭代变量由"range"子句声明或不存在,则迭代值类型为n的默认类型。当n<= 0 时,循环不执行任何迭代。 -
For a function
f, the iteration proceeds by callingfwith a new, synthesizedyieldfunction as its argument. Ifyieldis called beforefreturns, the arguments toyieldbecome the iteration values for executing the loop body once. After each successive loop iteration,yieldreturns true and may be called again to continue the loop. As long as the loop body does not terminate, the "range" clause will continue to generate iteration values this way for eachyieldcall untilfreturns. If the loop body terminates (such as by abreakstatement),yieldreturns false and must not be called again.
对于函数f,其迭代过程通过调用f并传入一个新合成的yield函数作为参数来实现。若在f返回前调用了yield,则传入yield的参数将成为执行单次循环体的迭代值。每次连续循环迭代后,yield返回 true 并可再次调用以继续循环。只要循环体未终止,"range"子句将持续为每个yield调用生成迭代值,直至f返回。若循环体终止(如通过break语句),则yield返回 false 且不得再次调用。
The iteration variables may be declared by the "range" clause using a form of
short variable declaration
(:=).
In this case their scope is the block of the "for" statement
and each iteration has its own new variables [Go 1.22]
(see also "for" statements with a ForClause).
The variables have the types of their respective iteration values.
迭代变量可通过“range”子句采用短变量声明形式( := )来声明。此时,其作用域为“for”语句的代码块,且每次迭代都会创建新变量[Go 1.22](另见带 ForClause 的“for”语句)。这些变量的类型与其对应的迭代值类型一致。
If the iteration variables are not explicitly declared by the "range" clause,
they must be preexisting.
In this case, the iteration values are assigned to the respective variables
as in an assignment statement.
如果迭代变量未通过“range”子句显式声明,则它们必须预先存在。此时,迭代值会像赋值语句一样被赋予相应的变量。
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 {}
// call f(0), f(1), ... f(9)
for i := range 10 {
// type of i is int (default type for untyped constant 10)
f(i)
}
// invalid: 256 cannot be assigned to uint8
var u uint8
for u = range 256 {
}
// invalid: 1e3 is a floating-point constant
for range 1e3 {
}
// fibo generates the Fibonacci sequence
fibo := func(yield func(x int) bool) {
f0, f1 := 0, 1
for yield(f0) {
f0, f1 = f1, f0+f1
}
}
// print the Fibonacci numbers below 1000:
for x := range fibo {
if x >= 1000 {
break
}
fmt.Printf("%d ", x)
}
// output: 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
// iteration support for a recursive tree data structure
type Tree[K cmp.Ordered, V any] struct {
left, right *Tree[K, V]
key K
value V
}
func (t *Tree[K, V]) walk(yield func(key K, val V) bool) bool {
return t == nil || t.left.walk(yield) && yield(t.key, t.value) && t.right.walk(yield)
}
func (t *Tree[K, V]) Walk(yield func(key K, val V) bool) {
t.walk(yield)
}
// walk tree t in-order
var t Tree[string, int]
for k, v := range t.Walk {
// process k, v
}
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.
一条"go"语句会启动一个函数调用作为独立的并发控制线程(或称 goroutine),在同一个地址空间内执行。
GoStmt = "go" Expression .
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.
函数值及其参数会在调用者的 goroutine 中照常计算,但与常规调用不同的是,程序执行不会等待被调函数完成。相反,该函数会在新的 goroutine 中独立开始执行。当函数终止时,其所在的 goroutine 也随之终止。若函数存在返回值,这些值将在函数完成时被丢弃。
go Server()
go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
Select statements¶ 选择语句 ¶
A "select" statement chooses which of a set of possible
send or
receive
operations will proceed.
It looks similar to a
"switch" statement but with the
cases all referring to communication operations.
select 语句用于从一组可能的发送或接收操作中选择将要执行的操作。其形式类似 switch 语句,但所有分支条件均为通信操作。
SelectStmt = "select" "{" { CommClause } "}" .
CommClause = CommCase ":" StatementList .
CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
RecvExpr = Expression .
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.
带有 RecvStmt 的 case 子句可将 RecvExpr 的结果分配给一个或两个变量(这些变量可通过短变量声明定义)。该 RecvExpr 必须是(可能带括号的)接收操作。最多只能存在一个 default 分支,且可出现在 case 列表中的任意位置。
Execution of a "select" statement proceeds in several steps:
执行“选择”语句的操作分几个步骤进行:
-
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.
在语句的所有情况中,接收操作的通道操作数以及发送语句的通道和右侧表达式,在进入"select"语句时严格按源码顺序求值一次。结果形成一组待接收或发送的通道及其对应发送值。该求值过程中的任何副作用都会发生,无论最终选择执行哪个(或是否执行)通信操作。带有短变量声明或赋值的 RecvStmt 左侧表达式此时尚未求值。 -
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.
如果有一个或多个通信可进行,则通过均匀伪随机选择选定一个可进行的通信。否则,若有默认情况,则选择该情况。若无默认情况,"select"语句将阻塞,直到至少一个通信可进行。 -
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.
若选中的 case 是一个带有短变量声明或赋值的 RecvStmt,则左侧表达式被求值,接收到的值(或多个值)被赋值。 -
The statement list of the selected case is executed.
选定用例的语句列表被执行。
Since communication on nil channels can never proceed,
a select with only nil channels and no default case blocks forever.
由于在 nil 通道上的通信永远无法进行,仅包含 nil 通道且无默认情况的 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): // 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
Return statements¶ 返回语句 ¶
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.
函数中的"return"语句 F 会终止 F 的执行,并可选择提供一个或多个结果值。由 F 延迟执行的任何函数将在 F 返回其调用方之前执行。
ReturnStmt = "return" [ ExpressionList ] .
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.
返回值可以在"return"语句中显式列出。每个表达式必须是单值的,并且可赋值给函数结果类型的对应元素。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.
"return"语句中的表达式列表可以是对多值函数的单一调用。其效果等同于:该函数返回的每个值均被赋予一个与各值类型匹配的临时变量,随后执行列出这些变量的"return"语句,此时前述规则同样适用。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.
如果函数的结果类型为其结果参数指定了名称,则表达式列表可为空。结果参数的作用如同普通局部变量,函数可按需对其进行赋值。"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.
实现限制:若在返回位置的作用域内存在与结果参数同名的其他实体(常量、类型或变量),编译器可禁止在"return"语句中使用空表达式列表。
func f(n int) (res int, err error) {
if _, err := f(n-1); err != nil {
return // invalid return statement: err is shadowed
}
return
}
Break statements¶ 中断语句 ¶
A "break" statement terminates execution of the innermost
"for",
"switch", or
"select" statement
within the same function.
break"语句会终止同一函数内最内层的"for"、"switch"或"select"语句的执行。
BreakStmt = "break" [ Label ] .
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¶ 继续语句 ¶
A "continue" statement begins the next iteration of the
innermost enclosing "for" loop
by advancing control to the end of the loop block.
The "for" loop must be within the same function.
"continue"语句通过将控制推进到循环块的末尾,开始最内层封闭"for"循环的下一次迭代。该"for"循环必须位于同一函数内。
ContinueStmt = "continue" [ Label ] .
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.
"goto"语句将控制权转移至同一函数内具有相应标签的语句。
GotoStmt = "goto" Label .
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"语句时,不得导致任何在 goto 语句所在位置尚未进入作用域的变量进入作用域。例如:
goto L // BAD 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¶ 贯穿语句 ¶
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.
"贯穿"语句将控制权转移到表达式"switch"语句中下一个 case 子句的第一条语句。该语句只能作为此类子句中的最后一条非空语句使用。
FallthroughStmt = "fallthrough" .
Defer statements¶
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.
"defer"语句会调用一个函数,其执行过程被推迟到外层函数返回的那一刻——无论是因外层函数执行了 return 语句、执行到函数体末尾,还是由于对应的协程正在发生恐慌。
DeferStmt = "defer" Expression .
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. That is, if the surrounding function
returns through an explicit return statement,
deferred functions are executed after any result parameters are set
by that return statement but before the function returns to its caller.
If a deferred function value evaluates
to nil, execution panics
when the function is invoked, not when the "defer" statement is executed.
每次执行"defer"语句时,函数值及其调用参数会照常进行求值并重新保存,但实际函数不会被立即调用。被延迟的函数会在外围函数返回之前,以被延迟顺序的逆序立即调用。具体而言,若外围函数通过显式返回语句结束,被延迟函数会在该返回语句设置完所有结果参数之后、函数返回给调用方之前执行。若被延迟的函数值求值为 nil ,则会在函数被调用时引发 panic,而非执行"defer"语句时。
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 42
func f() (result int) {
defer func() {
// result is accessed after it was set to 6 by the return statement
result *= 7
}()
return 6
}
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.
内置函数不具备标准的 Go 类型,因此它们仅能出现在调用表达式中;无法作为函数值使用。
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 a slice s
and returns the resulting slice of the same type as s.
The core type of s must be a slice
of type []E.
The values x are passed to a parameter of type ...E
and the respective parameter
passing rules apply.
As a special case, if the core type of s is []byte,
append also accepts a second argument with core type
bytestring followed by ....
This form appends the bytes of the byte slice or string.
可变参数函数 append 将零个或多个值 x 追加到切片 s 中,并返回与 s 类型相同的结果切片。 s 的核心类型必须是 []E 类型的切片。值 x 会传递给 ...E 类型的参数,并遵循相应的参数传递规则。特殊情况下,若 s 的核心类型为 []byte ,则 append 还可接受第二个参数——该参数需具有 bytestring 核心类型且后接 ... 。此形式将追加字节切片或字符串的字节数据。
append(s S, x ...E) S // core type of S is []E
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.
若 s 的容量不足以容纳新增值, append 将分配一个全新且足够大的底层数组,用于存放现有切片元素及新增值。否则, append 将直接复用原有底层数组。
s0 := []int{0, 0}
s1 := append(s0, 2) // append a single element s1 is []int{0, 0, 2}
s2 := append(s1, 3, 5, 7) // append multiple elements s2 is []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...) // append a slice s3 is []int{0, 0, 2, 3, 5, 7, 0, 0}
s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 is []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
var t []interface{}
t = append(t, 42, 3.1415, "foo") // t is []interface{}{42, 3.1415, "foo"}
var b []byte
b = append(b, "bar"...) // append string contents b is []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.
The core types of both arguments must be slices
with identical element type.
The number of elements copied is the minimum of
len(src) and len(dst).
As a special case, if the destination's core type is []byte,
copy also accepts a source argument with core type
bytestring.
This form copies the bytes from the byte slice or string into the byte slice.
函数 copy 将切片元素从源 src 复制到目标 dst ,并返回复制的元素数量。两个参数的核心类型必须是具有相同元素类型的切片。复制的元素数量是 len(src) 和 len(dst) 中的最小值。特殊情况下,若目标的核心类型为 []byte ,则 copy 也接受核心类型为 bytestring 的源参数。此形式将字节切片或字符串中的字节复制到字节切片中。
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 is []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:]) // n2 == 4, s is []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!") // n3 == 5, b is []byte("Hello")
Clear¶ 清除¶
The built-in function clear takes an argument of map,
slice, or type parameter type,
and deletes or zeroes out all elements
[Go 1.21].
内置函数 clear 接受映射、切片或类型参数类型的参数,并删除或归零所有元素 [Go 1.21]。
Call Argument type Result
clear(m) map[K]T deletes all entries, resulting in an
empty map (len(m) == 0)
clear(s) []T sets all elements up to the length of
s to the zero value of T
clear(t) type parameter see below
If the type of the argument to clear is a
type parameter,
all types in its type set must be maps or slices, and clear
performs the operation corresponding to the actual type argument.
若 clear 参数的类型是类型参数,则其类型集合中的所有类型必须是映射或切片, clear 将根据实际类型实参执行相应操作。
If the map or slice is nil, clear is a no-op.
如果映射或切片是 nil , clear 即为 no-op。
Close¶ 关闭 ¶
For an argument ch with a core type
that is a channel, the built-in function close
records that no more values will be sent on the channel.
It is an error if ch 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.
对于核心类型为通道的参数 ch ,内置函数 close 表示该通道将不再发送任何值。若 ch 为只接收通道则属错误。向已关闭通道发送数据或关闭该通道将导致运行时恐慌。关闭 nil 通道同样会引发运行时恐慌。调用 close 后,待所有先前发送的值被接收完毕,接收操作将返回通道类型的零值且不会阻塞。多值接收操作会返回接收到的值及通道是否已关闭的指示。
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 implicitly
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.
参数类型与返回值类型需对应。对于 complex ,两个参数必须为相同浮点类型,返回值则为包含相应浮点成分的复数类型: complex64 对应 float32 参数, complex128 对应 float64 参数。若其中一个参数为无类型常量,它首先会被隐式转换为另一参数的类型。若两参数均为无类型常量,则必须是非复数或虚部为零,此时函数返回值为无类型复数常量。
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.
对于 real 和 imag ,实参必须是复数类型,返回类型为对应的浮点类型: complex64 实参对应 float32 , complex128 实参对应 float64 。若实参的值为无类型常量,则其必须是数字,此时函数返回值为无类型浮点数常量。
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 int = complex(1, 0) // untyped complex constant 1 + 0i can be converted to int _ = 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
Arguments of type parameter type are not permitted.
不允许类型参数类型的参数。
Deletion of map elements¶
删除地图元素 ¶
The built-in function delete removes the element with key
k from a map m. The
value k must be assignable
to the key type of m.
内置函数 delete 从映射 m 中移除键为 k 的元素。值 k 必须可赋值给 m 的键类型。
delete(m, k) // remove element m[k] from map m
If the type of m is a type parameter,
all types in that type set must be maps, and they must all have identical key types.
如果 m 的类型是类型参数,则该类型集合中的所有类型都必须是映射,并且它们都必须具有完全相同的键类型。
If the map m is nil or the element m[k]
does not exist, delete is a no-op.
若地图 m 为 nil 或元素 m[k] 不存在,则 delete 为无操作。
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.
内置函数 len 和 cap 可接受多种类型的参数,并返回 int 类型的结果。其实现确保结果始终可容纳于 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
type parameter see below
cap(s) [n]T, *[n]T array length (== n)
[]T slice capacity
chan T channel buffer capacity
type parameter see below
If the argument type is a type parameter P,
the call len(e) (or cap(e) respectively) must be valid for
each type in P's type set.
The result is the length (or capacity, respectively) of the argument whose type
corresponds to the type argument with which P was
instantiated.
若参数类型为类型参数 P ,则调用 len(e) (或分别调用 cap(e) )必须对 P 类型集中的每种类型有效。结果为实参的长度(或容量),该实参类型对应于 P 实例化时所用的类型实参。
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.
切片、映射或通道的长度为 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
Making slices, maps and channels¶
创建切片、映射和通道
The built-in function make takes a type T,
optionally followed by a type-specific list of expressions.
The core type of T must
be a slice, map or channel.
It returns a value of type T (not *T).
The memory is initialized as described in the section on
initial values.
内置函数 make 接受类型 T ,可选后接一个类型特定的表达式列表。 T 的核心类型必须是切片、映射或通道。该函数返回类型为 T 的值(而非 *T )。内存初始化方式如初始值章节所述。
Call Core type 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
Each of the size arguments n and m must be of integer type,
have a type set containing only integer types,
or be 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.
For slices and channels, if n is negative or larger than m at run time,
a run-time panic occurs.
每个尺寸参数 n 和 m 必须为整型、仅包含整型的类型集合,或是无类型常量。常量尺寸参数必须非负,且可由 int 类型的值表示;若为无类型常量,则赋予 int 类型。若同时提供常量 n 和 m ,则 n 不得大于 m 。对于切片和通道,若运行时 n 为负值或大于 m ,将触发运行时恐慌。
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
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.
调用 make 时若指定映射类型和大小提示 n ,将创建一个拥有 n 个映射元素初始空间的映射。具体行为视实现而定。
Min and max¶ 最小和最大 ¶
The built-in functions min and max compute the
smallest—or largest, respectively—value of a fixed number of
arguments of ordered types.
There must be at least one argument
[Go 1.21].
内置函数 min 和 max 分别计算有序类型固定参数的最小值——或最大值。参数数量至少需一个[Go 1.21]。
The same type rules as for operators apply:
for ordered arguments x and
y, min(x, y) is valid if x + y is valid,
and the type of min(x, y) is the type of x + y
(and similarly for max).
If all arguments are constant, the result is constant.
与运算符相同的类型规则同样适用:对于有序参数 x 和 y ,若 x + y 有效则 min(x, y) 有效,且 min(x, y) 的类型即为 x + y 的类型(同样适用于 max )。若所有参数均为常量,则结果也为常量。
var x, y int
m := min(x) // m == x
m := min(x, y) // m is the smaller of x and y
m := max(x, y, 10) // m is the larger of x and y but at least 10
c := max(1, 2.0, 10) // c == 10.0 (floating-point kind)
f := max(0, float32(x)) // type of f is float32
var s []string
_ = min(s...) // invalid: slice arguments are not permitted
t := max("", "foo", "bar") // t == "foo" (string kind)
For numeric arguments, assuming all NaNs are equal, min and max are
commutative and associative:
对于数值参数,假设所有 NaN 相等时, min 和 max 具有可交换和可结合性:
min(x, y) == min(y, x) min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))
For floating-point arguments negative zero, NaN, and infinity the following rules apply:
对于浮点数参数中的负零、NaN 及无穷大,适用以下规则:
x y min(x, y) max(x, y) -0.0 0.0 -0.0 0.0 // negative zero is smaller than (non-negative) zero -Inf y -Inf y // negative infinity is smaller than any other number +Inf y y +Inf // positive infinity is larger than any other number NaN y NaN NaN // if any argument is a NaN, the result is a NaN
For string arguments the result for min is the first argument
with the smallest (or for max, largest) value,
compared lexically byte-wise:
对于字符串参数, min 的结果是字节字典序比较值最小(或 max 表示最大)的首个参数:
min(x, y) == if x <= y then x else y min(x, y, z) == min(min(x, y), z)
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 的值,其中包含该位置的地址。
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 调用方延迟的函数,依此类推直至执行协程中顶层函数延迟的函数。此时程序终止并报告错误状态(包含 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 函数允许程序管理恐慌协程的行为。假设函数 G 延迟了一个调用 recover 的函数 D ,且在 G 执行的同一协程中发生恐慌。当延迟函数执行到 D 时, D 调用 recover 的返回值将成为传递给 panic 调用的值。若 D 正常返回且未触发新的 panic ,恐慌序列即终止。此时,在 G 和 panic 之间调用的函数状态会被丢弃,正常执行恢复。接着运行 G 在 D 前延迟的所有函数, G 通过返回到其调用者来终止执行。
The return value of recover is nil when the
goroutine is not panicking or recover was not called directly by a deferred function.
Conversely, if a goroutine is panicking and recover was called directly by a deferred function,
the return value of recover is guaranteed not to be nil.
To ensure this, calling panic with a nil interface value (or an untyped nil)
causes a run-time panic.
当 goroutine 未发生 panic 或 recover 未被延迟函数直接调用时, recover 的返回值为 nil 。反之,若 goroutine 正在 panic 且 recover 由延迟函数直接调用,则 recover 的返回值必定不为 nil 。为确保此机制,使用 nil 接口值(或无类型的 nil )调用 panic 将引发运行时 panic。
The protect function in the example below invokes
the function argument g and protects callers from
run-time panics raised by g.
下例中的 protect 函数会调用函数参数 g ,并保护调用者免受 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()
}
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
Implementation restriction: print and println need not
accept arbitrary argument types, but printing of boolean, numeric, and string
types must be supported.
实现限制: print 和 println 无需接受任意参数类型,但必须支持布尔值、数值和字符串类型的打印输出。
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 .
The PackageName must not be the blank identifier.
PackageName 不得为空白标识符。
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.
导入声明表明,含有该声明的源文件依赖于所导入包的功能(§程序初始化与执行),并允许访问该包的导出标识符。导入语句需指定一个用于访问的标识符(包名 PackageName)以及指明待导入包的导入路径(ImportPath)。
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
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.
PackageName 用于限定标识符,在导入源文件中访问包的导出标识符。该名称在文件块中声明。若省略 PackageName,则默认使用被导入包中 package 子句指定的标识符。若出现显式句点( . )替代名称,则该包 package 块中声明的所有导出标识符都将被声明在导入源文件的文件块中,且必须不加限定符进行访问。
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.
ImportPath 的解释依赖于具体实现,但通常是编译后包完整文件名的子串,并且可能相对于已安装包的存储库。
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.
实现限制:编译器可以将 ImportPaths 限制为仅包含属于 Unicode L、M、N、P 和 S 通用类别(即不含空格的图形字符)的非空字符串,同时也可排除字符 !"#$%&'()*,:;<=>?[\]^`{|} 以及 Unicode 替换字符 U+FFFD。
Consider a 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.
考虑一个包含包声明 package math 的已编译包,该声明导出函数 Sin ,并将此编译包安装在由 "lib/math" 标识的文件中。下表展示了在不同类型的导入声明后,导入该包的文件如何访问 Sin 。
Import declaration Local name of 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.
这是一个完整的 Go 包,实现了并发素数筛。
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()
}
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 ,字符串为 "" ,指针、函数、接口、切片、通道和映射则为 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 variable initialization proceeds stepwise,
with each step selecting the variable earliest in declaration order
which has no dependencies on uninitialized variables.
在包内部,包级变量初始化逐步进行,每一步选择声明顺序最早且不依赖于未初始化变量的变量。
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.
当此过程结束时,若有变量仍未初始化,则这些变量属于一个或多个初始化循环的一部分,该程序无效。
Multiple variables on the left-hand side of a variable declaration initialized
by single (multi-valued) expression on the right-hand side are initialized
together: If any of the variables on the left-hand side is initialized, all
those variables are initialized in the same step.
在变量声明中,当左侧多个变量由右侧单个(多值)表达式初始化时,这些变量将同时完成初始化:若左侧任一变量被初始化,则所有变量均在同一阶段完成初始化。
var x = a var a, b = f() // a and b are initialized together, before x is initialized
For the purpose of package initialization, blank
variables are treated like any other variables in declarations.
在包初始化过程中,空白变量在声明中被视为与其他变量无异。
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.
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.
多文件中变量声明的顺序由文件提交给编译器的次序决定:首个文件中声明的变量优先于第二个文件中的任何变量声明,依此类推。为确保可重现的初始化行为,建议构建系统以词法文件名顺序将属于同一包的多个文件提供给编译器。
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
mis a method value or method expression of the formt.m, where the (static) type oftis not an interface type, and the methodmis in the method set oft. It is immaterial whether the resulting function valuet.mis invoked.
对方法m的引用是指形式为t.m的方法值或方法表达式,其中t的(静态)类型并非接口类型,且方法m属于t的方法集。无论最终函数值t.m是否被调用均无关紧要。 -
A variable, function, or method
xdepends on a variableyifx's initialization expression or body (for functions and methods) contains a reference toyor to a function or method that depends ony.
变量、函数或方法x依赖于变量y,若x的初始化表达式或其主体(针对函数和方法)包含对y的引用,或包含依赖于y的函数或方法的引用。
For example, given the declarations
例如,给定以下声明
var (
a = c + b // == 9
b = f() // == 4
c = f() // == 5
d = 3 // == 5 after initialization has finished
)
func f() int {
d++
return d
}
the initialization order is d, b, c, a.
Note that the order of subexpressions in initialization expressions is irrelevant:
a = c + b and a = b + c result in the same initialization
order in this example.
初始化顺序为 d 、 b 、 c 、 a 。请注意初始化表达式中子表达式的顺序无关紧要:在此示例中, a = c + b 和 a = b + c 会产生相同的初始化顺序。
Dependency analysis is performed per package; only references referring
to variables, functions, and (non-interface) methods declared in the current
package are considered. If other, hidden, data dependencies exists between
variables, the initialization order between those variables is unspecified.
依赖分析按包进行;仅考虑引用当前包中声明的变量、函数及(非接口)方法的依赖关系。若变量间存在其他隐藏的数据依赖,则这些变量间的初始化顺序未作指定。
For instance, given the declarations
例如,给定声明
var x = I(T{}).ab() // x has an undetected, hidden dependency on a and b
var _ = sideEffect() // unrelated to x, a, or b
var a = b
var b = 42
type I interface { ab() []int }
type T struct{}
func (T) ab() []int { return []int{a, b} }
the variable a will be initialized after b but
whether x is initialized before b, between
b and a, or after a, and
thus also the moment at which sideEffect() is called (before
or after x is initialized) is not specified.
变量 a 将在 b 之后进行初始化,但 x 是否在 b 之前、在 b 与 a 之间,或在 a 之后初始化,以及因此 sideEffect() 被调用的时刻(在 x 初始化之前或之后)均未作规定。
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 函数无法在程序中的任何位置被引用。
The entire package 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.
整个包的初始化过程包括首先为所有包级变量赋予初始值,随后按照源代码中呈现给编译器的顺序(可能涉及多个文件),依次调用所有 init 函数。
Program initialization¶ 程序初始化 ¶
The packages of a complete program are initialized stepwise, one package at a time.
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.
More precisely:
完整程序的包初始化是逐步进行的,每次仅初始化一个包。若某包存在导入项,则需先初始化被导入的包,再初始化该包本身。当多个包导入同一包时,被导入包仅初始化一次。在构造时导入包能确保不会出现循环初始化依赖。更准确地说:
Given the list of all packages, sorted by import path, in each step the first
uninitialized package in the list for which all imported packages (if any) are
already initialized is initialized.
This step is repeated until all packages are initialized.
给定按导入路径排序的所有包列表,在每一步中,列表中首个所有导入包(若存在)均已初始化的未初始化包将被初始化。重复此步骤直至所有包完成初始化。
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 函数的调用——在单个协程中顺序执行,每次仅处理一个包。 init 函数可启动其他协程,这些协程可与初始化代码并发运行。但初始化过程始终对 init 函数进行序列化处理:前一个函数返回前不会调用下一个函数。
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 program
and then invoking the function main in package main.
When that function invocation returns, the program exits.
It does not wait for other (non-main) goroutines to complete.
程序执行始于初始化程序,随后调用包 main 中的函数 main 。当该函数调用返回时,程序即退出,不会等待其他(非 main )goroutine 完成。
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.
执行错误(如尝试索引数组越界)会触发运行时恐慌,其效果等同于调用内置函数 panic 并传入实现定义的接口类型 runtime.Error 的值。该类型满足预声明接口类型 error 的要求。代表不同运行时错误状态的具体错误值尚未指定。
package runtime
type Error interface {
error
// and perhaps other methods
}
System considerations¶ 系统考量¶
Package 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:
编译器已知且可通过导入路径 "unsafe" 访问的内置包 unsafe ,为低级编程提供了设施,包括违反类型系统的操作。使用 unsafe 的包必须手动进行类型安全检查,且可能不具备可移植性。该包提供以下接口:
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 type IntegerType int // shorthand for an integer type; it is not a real type func Add(ptr Pointer, len IntegerType) Pointer func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType func SliceData(slice []ArbitraryType) *ArbitraryType func String(ptr *byte, len IntegerType) string func StringData(str string) *byte
A Pointer is a pointer type but a Pointer
value may not be dereferenced.
Any pointer or value of core type uintptr can be
converted to a type of core 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))
func f[P ~*B, B any](p P) uintptr {
return uintptr(unsafe.Pointer(p))
}
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 were declared via var v = x.
Alignof 和 Sizeof 函数接受任意类型的表达式 x ,分别返回假想变量 v 的对齐或大小,如同通过 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
A (variable of) type T has variable size if T
is a type parameter, or if it is an
array or struct type containing elements
or fields of variable size. Otherwise the size is constant.
Calls to Alignof, Offsetof, and Sizeof
are compile-time constant expressions of
type uintptr if their arguments (or the struct s in
the selector expression s.f for Offsetof) are types
of constant size.
若 T 是类型参数,或为包含可变大小元素或字段的数组或结构体类型,则 T 类型的(变量)具有可变大小,否则其大小为常量。当实参(或 Offsetof 的选择器表达式 s.f 中的结构体 s )属于常量大小的类型时,对 Alignof 、 Offsetof 和 Sizeof 的调用即为 uintptr 类型的编译时常量表达式。
The function Add adds len to ptr
and returns the updated pointer unsafe.Pointer(uintptr(ptr) + uintptr(len))
[Go 1.17].
The len argument must be of integer type or an untyped constant.
A constant len argument must be representable by a value of type int;
if it is an untyped constant it is given type int.
The rules for valid uses of Pointer still apply.
函数 Add 将 len 添加到 ptr 并返回更新后的指针 unsafe.Pointer(uintptr(ptr) + uintptr(len)) [Go 1.17]。 len 参数必须是整数类型或无类型常量。常量 len 参数必须能用 int 类型的值表示;若为无类型常量,则赋予其 int 类型。 Pointer 的有效使用规则仍然适用。
The function Slice returns a slice whose underlying array starts at ptr
and whose length and capacity are len.
Slice(ptr, len) is equivalent to
函数 Slice 返回一个切片,其底层数组起始于 ptr ,长度与容量均为 len 。 Slice(ptr, len) 等效于
(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
except that, as a special case, if ptr
is nil and len is zero,
Slice returns nil
[Go 1.17].
除非在特殊情况下,如果 ptr 为 nil 且 len 为零,则 Slice 返回 nil [Go 1.17]。
The len argument must be of integer type or an untyped constant.
A constant len argument must be non-negative and representable by a value of type int;
if it is an untyped constant it is given type int.
At run time, if len is negative,
or if ptr is nil and len is not zero,
a run-time panic occurs
[Go 1.17].
参数 len 必须为整数类型或无类型常量。常量参数 len 必须非负且能用类型 int 的值表示;若为无类型常量,则赋予其类型 int 。运行时若 len 为负值,或 ptr 为 nil 且 len 非零,将触发运行时恐慌[Go 1.17]。
The function SliceData returns a pointer to the underlying array of the slice argument.
If the slice's capacity cap(slice) is not zero, that pointer is &slice[:1][0].
If slice is nil, the result is nil.
Otherwise it is a non-nil pointer to an unspecified memory address
[Go 1.20].
函数 SliceData 返回 slice 参数底层数组的指针。若切片的容量 cap(slice) 非零,则该指针为 &slice[:1][0] 。若 slice 为 nil ,则结果为 nil ;否则将返回指向未指定内存地址的非 nil 指针[Go 1.20]。
The function String returns a string value whose underlying bytes start at
ptr and whose length is len.
The same requirements apply to the ptr and len argument as in the function
Slice. If len is zero, the result is the empty string "".
Since Go strings are immutable, the bytes passed to String must not be modified afterwards.
[Go 1.20]
函数 String 返回一个 string 值,其底层字节起始于 ptr 且长度为 len 。对 ptr 和 len 参数的要求与函数 Slice 中的相同。若 len 为零,则结果为空字符串 "" 。由于 Go 字符串不可变,传递给 String 的字节后续不得修改。[Go 1.20]
The function StringData returns a pointer to the underlying bytes of the str argument.
For an empty string the return value is unspecified, and may be nil.
Since Go strings are immutable, the bytes returned by StringData must not be modified
[Go 1.20].
StringData 函数返回指向 str 参数底层字节的指针。对于空字符串,返回值未指定,可能为 nil 。由于 Go 字符串不可变, StringData 返回的字节绝不可被修改[Go 1.20]。
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
The following minimal alignment properties are guaranteed:
以下最小对齐属性得到保证:
- For a variable
xof any type:unsafe.Alignof(x)is at least 1.
对于任意类型的变量x:unsafe.Alignof(x)至少为 1。 - For a variable
xof struct type:unsafe.Alignof(x)is the largest of all the valuesunsafe.Alignof(x.f)for each fieldfofx, but at least 1.
对于一个结构类型的变量x:unsafe.Alignof(x)是对于x的每个字段f而言所有unsafe.Alignof(x.f)值中的最大值,但至少为 1。 - For a variable
xof array type:unsafe.Alignof(x)is the same as the alignment of a variable of the array's element type.
对于数组类型的变量x:其对齐要求与数组元素类型变量的对齐要求相同。
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.
若结构体或数组类型不包含大小大于零的字段(或分别对应元素),则其大小为零。两个不同的零大小变量可能在内存中具有相同地址。
Appendix¶ 附录 ¶
Language versions¶ 语言版本 ¶
The Go 1 compatibility guarantee ensures that
programs written to the Go 1 specification will continue to compile and run
correctly, unchanged, over the lifetime of that specification.
More generally, as adjustments are made and features added to the language,
the compatibility guarantee ensures that a Go program that works with a
specific Go language version will continue to work with any subsequent version.
Go 1 兼容性保证确保遵循 Go 1 规范编写的程序在该规范的生命周期内,无需修改即可持续正确编译和运行。更广泛地说,当语言做出调整并添加新功能时,兼容性保证确保了适用于特定 Go 语言版本的程序,在后续版本中仍能正常运行。
For instance, the ability to use the prefix 0b for binary
integer literals was introduced with Go 1.13, indicated
by [Go 1.13] in the section on
integer literals.
Source code containing an integer literal such as 0b1011
will be rejected if the implied or required language version used by
the compiler is older than Go 1.13.
例如,使用前缀 0b 表示二进制整数字面量的能力随 Go 1.13 版本引入,在整数字面量章节中标注为[Go 1.13]。若编译器使用的隐含或所需的语言版本低于 Go 1.13,含有 0b1011 等整数字面量的源代码将被拒绝编译。
The following table describes the minimum language version required for
features introduced after Go 1.
下表描述了 Go 1.之后引入功能所需的最低语言版本。
Go 1.9¶
-
An alias declaration may be used to declare an alias name for a type.
别名声明可用于为类型声明别名。
Go 1.13¶
-
Integer literals may use the prefixes
0b,0B,0o, and0Ofor binary, and octal literals, respectively.
整数字面值可使用前缀0b、0B、0o和0O分别表示二进制和八进制字面值。 -
Hexadecimal floating-point literals may be written using the prefixes
0xand0X.
十六进制浮点数字面量可通过前缀0x和0X书写。 -
The imaginary suffix
imay be used with any (binary, decimal, hexadecimal) integer or floating-point literal, not just decimal literals.
虚数后缀i可用于任意进制(二进制、十进制、十六进制)的整型或浮点数字面量,而不仅仅是十进制字面量。 -
The digits of any number literal may be separated (grouped)
using underscores
_.
任何数字字面量的数字可用下划线分隔(分组)_。 -
The shift count in a shift operation may be a signed integer type.
移位操作中的移位计数可为有符号整数类型。
Go 1.14¶
-
Emdedding a method more than once through different embedded interfaces
is not an error.
通过不同的嵌入式接口多次嵌入同一方法并不视为错误。
Go 1.17¶
-
A slice may be converted to an array pointer if the slice and array element
types match, and the array is not longer than the slice.
若切片与数组元素类型匹配,且数组长度不超过切片,则切片可转换为数组指针。 -
The built-in package
unsafeincludes the new functionsAddandSlice.
内置包unsafe包含新函数Add和Slice。
Go 1.18¶ Go 1.18 段落
The 1.18 release adds polymorphic functions and types ("generics") to the language.
Specifically:
1.18 版本向该语言添加了多态函数和类型("泛型")。具体包括:
-
The set of operators and punctuation includes the new token
~.
操作符和标点符号集合包含新标记~。 -
Function and type declarations may declare type parameters.
函数和类型声明可以声明类型参数。 -
Interface types may embed arbitrary types (not just type names of interfaces)
as well as union and
~Ttype elements.
接口类型可以嵌入任意类型(不仅限于接口类型名称),以及联合类型和~T类型元素。 -
The set of predeclared types includes the new types
anyandcomparable.
预声明的类型集包括新类型any和comparable。
Go 1.20¶
-
A slice may be converted to an array if the slice and array element
types match and the array is not longer than the slice.
如果切片和数组元素类型匹配,且数组长度不超过切片,则切片可转换为数组。 -
The built-in package
unsafeincludes the new functionsSliceData,String, andStringData.
unsafe内置包包含SliceData、String和StringData等新功能. -
Comparable types (such as ordinary interfaces) may satisfy
comparableconstraints, even if the type arguments are not strictly comparable.
可比较类型(如普通接口)可满足comparable约束,即使类型参数并非严格可比较。
Go 1.21¶ Go 1.21 节
-
The set of predeclared functions includes the new functions
min,max, andclear.
预声明的函数集合包括新函数min、max和clear。 -
Type inference uses the types of interface methods for inference.
It also infers type arguments for generic functions assigned to variables or
passed as arguments to other (possibly generic) functions.
类型推断利用接口方法的类型进行推断。它还会为分配给变量的泛型函数或作为参数传递给其他(可能是泛型的)函数的泛型函数推断类型参数。
Go 1.22¶
-
In a "for" statement, each iteration has its own set of iteration
variables rather than sharing the same variables in each iteration.
在“for”语句中,每次迭代都拥有各自的迭代变量集合,而非在每次迭代中共享相同的变量。 -
A "for" statement with "range" clause may iterate over
integer values from zero to an upper limit.
带有“range”子句的“for”语句可迭代从零到上限的整数值。
Go 1.23¶ Go 1.23 节
- A "for" statement with "range" clause accepts an iterator
function as range expression.
带有"range"子句的"for"语句接受迭代器函数作为范围表达式。
Go 1.24¶
-
An alias declaration may declare
type parameters.
别名声明可以声明类型参数。
Type unification rules¶ 类型统一规则 ¶
The type unification rules describe if and how two types unify.
The precise details are relevant for Go implementations,
affect the specifics of error messages (such as whether
a compiler reports a type inference or other error),
and may explain why type inference fails in unusual code situations.
But by and large these rules can be ignored when writing Go code:
type inference is designed to mostly "work as expected",
and the unification rules are fine-tuned accordingly.
类型统一规则描述两种类型是否能够统一以及如何统一。具体细节与 Go 实现相关,会影响错误信息的具体内容(例如编译器报告类型推断错误还是其他错误),并可能解释为何在特殊代码场景中类型推断会失败。但大体上,在编写 Go 代码时可以忽略这些规则:类型推断的设计目标是基本“按预期工作”,相应的统一规则也据此进行了微调。
Type unification is controlled by a matching mode, which may
be exact or loose.
As unification recursively descends a composite type structure,
the matching mode used for elements of the type, the element matching mode,
remains the same as the matching mode except when two types are unified for
assignability (≡A):
in this case, the matching mode is loose at the top level but
then changes to exact for element types, reflecting the fact
that types don't have to be identical to be assignable.
类型统一由一个匹配模式控制,该模式可为精确或宽松。当统一过程递归地下降遍历复合类型结构时,用于类型元素的匹配模式(即元素匹配模式)通常保持与当前匹配模式一致,除非在两种类型因可分配性而统一时( ≡A ):此时顶层采用宽松匹配模式,但随后对元素类型切换为精确模式,这反映出类型无需完全相同即可分配的事实。
Two types that are not bound type parameters unify exactly if any of
following conditions is true:
如果满足以下任一条件为真,则两种非绑定类型参数将精确统一:
-
Both types are identical.
两种类型是相同的。 -
Both types have identical structure and their element types
unify exactly.
两种类型具有相同的结构,且它们的元素类型完全统一。 -
Exactly one type is an unbound
type parameter with a core type,
and that core type unifies with the other type per the
unification rules for
≡A(loose unification at the top level and exact unification for element types).
确切存在一种未绑定具体类型的泛型参数,其核心类型将根据≡A的统一规则(顶层采用宽松统一,元素类型采用精确统一)与另一类型进行统一。
If both types are bound type parameters, they unify per the given
matching modes if:
若两种类型均为受限类型参数,则按照给定匹配模式进行统一的条件如下:
-
Both type parameters are identical.
两个类型参数是相同的。 -
At most one of the type parameters has a known type argument.
In this case, the type parameters are joined:
they both stand for the same type argument.
If neither type parameter has a known type argument yet,
a future type argument inferred for one the type parameters
is simultaneously inferred for both of them.
至多一个类型形参具有已知类型实参。在这种情况下,类型形参会合并:它们均代表相同的类型实参。若当前两个类型形参均无已知类型实参,则未来为其中一个类型形参推断的类型实参将同时被推断适用于两者。 -
Both type parameters have a known type argument
and the type arguments unify per the given matching modes.
两个类型参数均具有已知类型实参,且这些类型实参会根据给定的匹配模式统一。
A single bound type parameter P and another type T unify
per the given matching modes if:
单个绑定类型参数 P 与另一类型 T 根据给定匹配模式统一的条件为:
-
Pdoesn't have a known type argument. In this case,Tis inferred as the type argument forP.
P没有已知的类型实参。此时,T被推断为P的类型实参。 -
Pdoes have a known type argumentA,AandTunify per the given matching modes, and one of the following conditions is true:
P确实拥有已知类型参数A,A和T根据给定的匹配模式进行统一,且满足以下任一条件:-
Both
AandTare interface types: In this case, if bothAandTare also defined types, they must be identical. Otherwise, if neither of them is a defined type, they must have the same number of methods (unification ofAandTalready established that the methods match).
A和T均为接口类型:若A和T同为定义类型,则二者必须完全相同;若均非定义类型,则必须拥有相同数量的方法(A与T的统一性已确保方法匹配)。 -
Neither
AnorTare interface types: In this case, ifTis a defined type,TreplacesAas the inferred type argument forP.
A和T均非接口类型:在此情况下,若T是已定义类型,则T将替代A作为P推断出的类型参数。
-
Both
Finally, two types that are not bound type parameters unify loosely
(and per the element matching mode) if:
最终,在以下情况下,两种非绑定类型参数会松散地统一(且依据元素匹配模式):
-
Both types unify exactly.
两种类型完全统一 -
One type is a defined type,
the other type is a type literal, but not an interface,
and their underlying types unify per the element matching mode.
一种是已定义类型,另一种是类型字面量但并非接口,按照元素匹配模式,它们的底层类型能够统一。 -
Both types are interfaces (but not type parameters) with
identical type terms,
both or neither embed the predeclared type
comparable,
corresponding method types unify exactly,
and the method set of one of the interfaces is a subset of
the method set of the other interface.
两种类型均为接口(而非类型参数),且具有相同的类型项,二者均嵌入或不嵌入预声明的可比较类型,对应方法类型完全统一,并且其中一个接口的方法集是另一个接口方法集的子集。 -
Only one type is an interface (but not a type parameter),
corresponding methods of the two types unify per the element matching mode,
and the method set of the interface is a subset of
the method set of the other type.
仅有一种类型为接口(非类型参数),两种类型的对应方法按元素匹配模式统一,且该接口的方法集是另一类型方法集的子集。 -
Both types have the same structure and their element types
unify per the element matching mode.
两种类型具有相同的结构,其元素类型根据元素匹配模式统一。