这是用户在 2025-8-2 19:38 为 https://go.dev/ref/spec 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

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 表示从 ab 的字符集合作为可选项。水平省略号 在规范中还用于非正式表示未进一步指定的各种枚举或代码片段。字符 (而不是三个字符 ... )不是 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:
注释作为程序文档存在,有两种形式:

  1. Line comments start with the character sequence // and stop at the end of the line.
    行注释以字符序列 // 开始,并终止于行末。
  2. 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 程序可通过以下两条规则省略大部分分号:

  1. 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
    当输入被分解为词法单元时,若某行的最终词法单元是分号,则该分号会被自动插入到词法流中紧随其后
  2. 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.
整数字面量是由一串数字组成的整数常量。可选前缀用于设定非十进制基数: 0b0B 表示二进制, 00o0O 表示八进制, 0x0X 表示十六进制[Go 1.13]。单个 0 被视为十进制零。在十六进制字面量中,字母 af 以及 AF 分别代表数值 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.
十进制浮点数字面值由整数部分(十进制数字)、小数点、小数部分(十进制数字)及指数部分( eE 后接可选符号和十进制数字)组成。整数部分或小数部分可省略其一;小数点或指数部分可省略其一。指数值 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].
十六进制浮点数字面值由 0x0X 前缀、整数部分(十六进制数字)、小数点、小数部分(十六进制数字)及指数部分( pP 后接可选符号和十进制数字)组成。整数部分或小数部分可省略其一;小数点亦可省略,但指数部分必须保留。(该语法符合 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.
常量值可由符文、整数、浮点数、虚数或字符串字面量表示,也可由表示常量的标识符、常量表达式、结果为常量的类型转换、或某些内置函数作用于常量参数的结果值构成(例如作用于常量参数的 minmax ,作用于特定值的 unsafe.Sizeof ,作用于某些表达式的 caplen ,作用于复数常量的 realimag ,以及作用于数值常量的 complex )。布尔真值由预声明常量 truefalse 表示。预声明标识符 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.
常量可以是有类型的或无类型的。字面常量、 truefalseiota 以及仅包含无类型常量操作数的某些常量表达式均为无类型常量。

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 中未指定显式类型时),该常量会被隐式转换为此类型。无类型常量的默认类型分别为 boolruneintfloat64complex128string ,具体取决于它是布尔常量、符文常量、整数常量、浮点常量、复数常量还是字符串常量。

Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must:
实现限制:尽管语言中的数值常量具有任意精度,但编译器可以使用有限精度的内部表示来实现它们。但所有实现都必须:

These requirements apply both to literal constants and to the result of evaluating constant expressions.
这些要求既适用于字面常量,也适用于常量表达式求值的结果。

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.
布尔类型表示由预声明常量 truefalse 表示的布尔真值集合。预声明的布尔类型为 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 的别名)除外。当表达式中混合使用不同数值类型或进行赋值时,必须进行显式转换。例如, int32int 虽在特定架构上可能具有相同大小,但并非同一类型。

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 时,提升方法将按以下方式包含在结构体的方法集中:

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
多个类型可能实现同一个接口。例如,若两个类型 S1S2 拥有方法集

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 代表 S1S2 )则 File 接口将由 S1S2 共同实现,无论 S1S2 可能拥有或共享何种其他方法。

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
如果 S1S2 也实现

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 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 如果

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 发现其长度,该值可能在执行期间改变。执行期间可通过赋值添加元素,并使用索引表达式检索元素;也可通过内置函数 deleteclear 移除元素。

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 用于发送语句、接收操作以及调用内置函数 caplen 。通道以先进先出队列的形式运作。例如,若一个 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.
预声明类型(参见下文接口 anyerror )、数组及结构体的值具有自包含性:每个此类值均包含其所有数据的完整副本,且对应类型的变量存储的是完整值。例如,数组变量为数组所有元素提供存储(即变量)。相应的零值由值的类型决定,它们绝不会是 nil

Non-nil pointer, function, slice, map, and channel values contain references to underlying data which may be shared by multiple values:
非空指针、函数、切片、映射和通道值包含对可能被多个值共享的底层数据的引用

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{}.
stringA1A2B1B2 的基础类型为 string[]B1B3B4 的基础类型为 []B1P 的基础类型为 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 在满足以下任一条件时具有核心类型:

  1. There is a single type U which is the underlying type of all types in the type set of T; or
    存在单一类型 U ,它是 T 的类型集合中所有类型的基础类型;或者
  2. the type set of T contains only channel types with identical element type E, 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:
接口的核心类型取决于所满足的条件,要么是:

  1. the type U; or
    类型 U ; 或
  2. the type chan E if T contains only bidirectional channels, or the type chan<- E or <-chan E depending 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.
某些操作(切片表达式、 appendcopy )依赖于一种略宽松的核心类型形式,该形式接受字节切片和字符串。具体而言,若恰好存在两种类型 []bytestring ,它们作为接口 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:
命名类型始终不同于其他任何类型。否则,若两个类型的基础类型字面量在结构上等价,则它们是相同的;即具有相同的字面结构且对应组件类型一致。具体而言:

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).
B0B1 不同,因为它们是由不同类型定义创建的新类型; func(int, float64) *B0func(x int, y float64) *[]string 不同,因为 B0[]string 不同;而 P1P2 不同,因为它们属于不同的类型参数。 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 "),如果满足以下任一条件:

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 的类型 VT 为类型参数,则当满足以下任一条件时, x 可赋值给 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 不是类型参数:

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:
一个类型的方法集决定了可调用该类型操作数的方法。每个类型都有一个(可能为空的)与之关联的方法集:

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:
除了源代码中的显式块,还存在隐式块:

  1. The universe block encompasses all Go source text.
    全局块包含所有 Go 源代码。
  2. Each package has a package block containing all Go source text for that package.
    每个包都有一个包块,其中包含该包的所有 Go 源代码文本。
  3. Each file has a file block containing all Go source text in that file.
    每个文件都有一个文件块,其中包含该文件中的所有 Go 源代码文本。
  4. Each "if", "for", and "switch" statement is considered to be in its own implicit block.
    每个"if"、"for"和"switch"语句都被视为位于其自身的隐式块中。
  5. 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 通过代码块实现词法作用域

  1. The scope of a predeclared identifier is the universe block.
    预声明标识符的作用域是全局代码块。
  2. 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.
    表示在顶层(在任何函数之外)声明的常量、类型、变量或函数(而非方法)的标识符,其作用域为包块。
  3. The scope of the package name of an imported package is the file block of the file containing the import declaration.
    导入包中包名称的作用域为包含该导入声明的文件的文件块。
  4. The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
    表示方法接收器、函数参数或结果变量的标识符的作用域是函数体。
  5. 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.
    表示函数类型参数或由方法接收者声明的标识符的作用域起始于函数名之后,结束于函数体末尾。
  6. 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 结尾。
  7. 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)的末尾,止于最内层包含块的结尾。
  8. 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:
标识符可被导出以允许其他包访问。满足以下两个条件时,标识符即被导出:

  1. the first character of the identifier's name is a Unicode uppercase letter (Unicode character category Lu); and
    标识符名称的首字符为 Unicode 大写字母(Unicode 字符类别 Lu);且
  2. 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 如果

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.
将方法 LengthScale 绑定到基类型 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:
对于结构体字面量,适用以下规则:

Given the declarations   鉴于以下声明

type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }

one may write   可以写

origin := Point3D{}                            // zero value for Point3D
line := Line{origin, Point3D{y: -4, z: 12.3}}  // zero value for line.q.x

For array and slice literals the following rules apply:
对于数组和切片字面量,适用以下规则:

Taking the address of a composite literal generates a pointer to a unique variable initialized with the literal's value.
对复合字面量取地址会生成指向该字面值初始化的唯一变量的指针。

var pointer *Point3D = &Point3D{y: 1000}

Note that the zero value for a slice or map type is not the same as an initialized but empty value of the same type. Consequently, taking the address of an empty slice or map composite literal does not have the same effect as allocating a new slice or map value with new.
请注意,切片或映射类型的零值不同于同类型已初始化但为空的值。因此,对空切片或映射复合字面量取地址的效果与使用 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 的深度,等于 fA 中的深度加一。

The following rules apply to selectors:
以下规则适用于选择器:

  1. For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
    对于类型为 T*T 的值 x (其中 T 非指针或接口类型), x.f 表示 T 中具有该 f 的最浅深度字段或方法。若不存在唯一的最浅深度 f ,则该选择器表达式非法。
  2. For a value x of type I where I is an interface type, x.f denotes the actual method with name f of the dynamic value of x. If there is no method with name f in the method set of I, the selector expression is illegal.
    对于类型为 I 的值 x ,其中 I 为接口类型, x.f 表示 x 动态值中名为 f 的实际方法。若在 I 的方法集合中不存在名为 f 的方法,则该选择器表达式非法。
  3. As an exception, if the type of x is a defined pointer type and (*x).f is a valid selector expression denoting a field (but not a method), x.f is shorthand for (*x).f.
    作为例外,若 x 的类型为已定义的指针类型且 (*x).f 是表示字段(而非方法)的有效选择器表达式,则 x.f 表示 (*x).f 的简写形式。
  4. In all other cases, x.f is illegal.
    在所有其他情况下, x.f 均属非法。
  5. If x is of pointer type and has the value nil and x.f denotes a struct field, assigning to or evaluating x.f causes a run-time panic.
    如果 x 是指针类型且值为 nil ,且 x.f 表示结构体字段,则对 x.f 赋值或求值将引发运行时恐慌。
  6. If x is of interface type and has the value nil, calling or evaluating the method x.f causes 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 ,它包含两个方法:接收者类型为 TMv 方法,以及接收者类型为 *TMp 方法。

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 :其接收器类型为 TMv ,以及接收器类型为 *TMp

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 既非映射亦非类型参数:

For a of array type A:
对于数组类型 Aa

For a of pointer to array type:
对于指向数组类型的指针 a

For a of slice type S:
对于切片类型 Sa

For a of string type:
对于 a 属于字符串类型:

For a of map type M:
对于地图类型 Ma

For a of type parameter type P:
对于类型为参数类型 Pa

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 。索引 lowhigh 用于选择操作数 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]。实例化过程分两步进行:

  1. 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.
    每个类型实参都会替换泛型声明中对应的类型参数。这一替换过程发生在整个函数或类型声明范围内,包括类型形参列表本身及其包含的所有类型。
  2. 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:
使用泛型函数时,类型参数可显式提供,也可部分或全部从函数调用上下文中推断得出。若能推断出类型参数,则在以下情况下可完全省略类型参数列表:

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 ,程序才能有效。为降低复杂度,类型推断忽略赋值的指向性,因此 SliceS 的类型关系可通过(对称的)类型方程 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
现在可以求解类型参数 SE 。根据(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 示例中,类型参数 SE 被绑定到 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):
类型推断支持泛型函数的调用以及将泛型函数赋值给(显式函数类型的)变量。这包括将泛型函数作为实参传递给其他函数(这些函数本身也可能是泛型函数),以及将泛型函数作为结果返回。类型推断基于针对每种情况特制的等式集合进行操作,具体等式如下(为清晰起见,类型实参列表被省略):

Additionally, each type parameter Pk and corresponding type constraint Ck yields the type equation PkC Ck.
此外,每个类型参数 Pk 及其对应的类型约束 Ck 都会产生类型方程 PkC Ck

Type inference gives precedence to type information obtained from typed operands before considering untyped constants. Therefore, inference proceeds in two phases:
类型推断在考虑无类型常量之前,会优先采用从类型化操作数获得的类型信息。因此推断过程分为两个阶段:

  1. The type equations are solved for the bound type parameters using type unification. If unification fails, type inference fails.
    类型方程通过类型统一求解绑定类型参数。若统一失败,则类型推断失败。

  2. For each bound type parameter Pk for 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 constants cj in all those pairs the same way as for constant expressions. The type argument for Pk is 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 的类型参数尚未得知(映射表中无对应条目),因此统一 Pstring 会将映射关系 P ➞ string 加入映射表。统一 list 字段的类型需要统一 []P[]string ,进而统一 Pstring 。由于此时 P 的类型参数已知(映射表中存在 P 的条目),其类型参数 string 将替代 P 的位置。鉴于 stringstring 完全相同,此统一步骤亦成功完成。至此,等式左右两侧的统一过程全部结束。类型推断成功,因仅存在单一类型等式、所有统一步骤均成功执行且映射表已完全填充。

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 的方程,其中 XY 是赋值操作(包括参数传递和返回语句)涉及的类型,其顶层类型结构可松散统一,但元素类型必须精确统一,以匹配赋值规则。

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 是其对应的约束条件,统一规则稍显复杂:

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 的计算分别采用 float32float64 精度,具体取决于 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:
对于两个整数值 xy ,其整数商 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:
此规则的一个例外是,若被除数 xx 整型的最小负值,由于二进制补码整数溢出,商 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:
相等运算符 ==!= 适用于可比较类型的操作数。排序运算符 < , <= , > , 及 >= 适用于有序类型的操作数。相关术语及比较结果定义如下:

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:
当某类型是可比较的,且既不是接口类型,也不是由接口类型组成时,该类型就是严格可比较的。具体来说:

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 类型变量。若 xnil ,尝试对 *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 的类型参数表示为 float32float64 。因此,若 ffloat32 类型实例化,表达式 P(1.1) + 1.2 的数值将以与对应非常量 float32 加法相同的精度计算。

A non-constant value x can be converted to type T in any of these cases:
在以下任一情况下,非常量值 x 均可转换为类型 T

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:
此外,如果 Tx 的类型 V 是类型参数,在满足以下任一条件时, 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:
对于非常量数值的转换,适用以下规则:

  1. 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), then uint32(int8(v)) == 0xFFFFFFF0. The conversion always yields a valid value; there is no indication of overflow.
    当整数类型间转换时,若值为有符号整数,则进行符号扩展至隐式无限精度;若为无符号整数,则进行零扩展。随后该值会被截断以适配目标类型的大小。例如,若 v := uint16(0x10F0) ,则 uint32(int8(v)) == 0xFFFFFFF0 。此类转换始终产生有效值,且不会提示溢出情况。
  2. When converting a floating-point number to an integer, the fraction is discarded (truncation towards zero).
    将浮点数转换为整数时,小数部分被舍弃(向零截断)。
  3. When converting an integer or floating-point number to a floating-point type, or a complex number to another complex type, the result value is rounded to the precision specified by the destination type. For instance, the value of a variable x of type float32 may be stored using additional precision beyond that of an IEEE 754 32-bit number, but float32(x) represents the result of rounding x's value to 32-bit precision. Similarly, x + 0.1 may use more than 32 bits of precision, but float32(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
与字符串类型之间的转换¶

  1. 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'})   // "🌍"
    
  2. 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" == "🌎"
    
  3. 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'}
    
  4. 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}
    
  5. 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. The go vet tool flags certain integer-to-string conversions as potential errors. Library functions such as utf8.AppendRune or utf8.EncodeRune should be used instead.
    最后,出于历史原因,整数值可被转换为字符串类型。这种转换形式会生成一个字符串,其中包含给定整数值对应的 Unicode 码点的(可能是多字节的)UTF-8 表示形式。超出有效 Unicode 码点范围的值将被转换为 "\uFFFD" 。注意:该转换形式最终可能会从语言中移除。 go vet 工具会将某些整型到字符串的转换标记为潜在错误,应改用 utf8.AppendRuneutf8.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()<-cg()k() 发生。然而,这些事件相对于 x 的求值与索引,以及 yz 的求值顺序均未明确规定,除词法要求外。例如, 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:
终止语句会中断块中的常规控制流。以下语句属于终止语句:

  1. A "return" or "goto" statement.
  2. A call to the built-in function panic.
    对内置函数 panic 的调用。
  3. A block in which the statement list ends in a terminating statement.
    语句列表以终止语句结尾的块。
  4. An "if" statement in which:
    "if"语句,其中:
    • the "else" branch is present, and
      存在"else"分支,且
    • both branches are terminating statements.
      两个分支都是终止语句。
  5. 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"语句不使用范围子句。
  6. 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”语句结束。
  7. 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.
      每种情况下的语句列表,包括默认情况(如果存在),均以终止语句结束。
  8. 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.
带标签的语句可能成为 gotobreakcontinue 语句的跳转目标。

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:
在赋值操作中,每个值都必须可赋值给所赋值操作数的类型,存在以下特殊情况:

  1. Any typed value may be assigned to the blank identifier.
    任何类型的值都可以赋值给空白标识符。
  2. 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.
    当将无类型常量赋值给接口类型的变量或空白标识符时,该常量会先被隐式转换为其默认类型。
  3. 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 表达式的值 tx == 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 在循环开始前被求值,仅有一个例外:若至多存在一个迭代变量,且 xlen(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
  1. 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 to len(a)-1 and does not index into the array or slice itself. For a nil slice, the number of iterations is 0.
    对于数组、数组指针或切片值 a ,索引迭代值按递增顺序产生,从元素索引 0 开始。若最多存在一个迭代变量,range 循环将生成从 0 到 len(a)-1 的迭代值,且不会索引数组或切片本身。对于 nil 切片,迭代次数为 0。
  2. 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 be 0xFFFD, 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 替换字符),且下次迭代将在字符串中前进一个字节。
  3. 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。
  4. 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 ,范围表达式将永久阻塞。
  5. For an integer value n, where n is of integer type or an untyped integer constant, the iteration values 0 through n-1 are produced in increasing order. If n is of integer type, the iteration values have that same type. Otherwise, the type of n is 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 for n. If n <= 0, the loop does not run any iterations.
    对于一个整数值 n (其中 n 为整数类型或无类型整数常量),将按升序生成从 0 到 n-1 的迭代值。若 n 为整数类型,则迭代值具有相同类型;否则, n 的类型将如同被赋值给迭代变量般确定。具体而言:若迭代变量已预先存在,则迭代值类型即为该迭代变量的类型(必须为整数类型);若迭代变量由"range"子句声明或不存在,则迭代值类型为 n 的默认类型。当 n <= 0 时,循环不执行任何迭代。
  6. For a function f, the iteration proceeds by calling f with a new, synthesized yield function as its argument. If yield is called before f returns, the arguments to yield become the iteration values for executing the loop body once. After each successive loop iteration, yield returns 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 each yield call until f returns. If the loop body terminates (such as by a break statement), yield returns 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:
执行“选择”语句的操作分几个步骤进行:

  1. 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 左侧表达式此时尚未求值。
  2. 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"语句将阻塞,直到至少一个通信可进行。
  3. Unless the selected case is the default case, the respective communication operation is executed.
    除非所选情况为默认情况,否则将执行相应的通信操作。
  4. 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,则左侧表达式被求值,接收到的值(或多个值)被赋值。
  5. 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:
有三种方式可以从具有结果类型的函数中返回值:

  1. 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
    }
    
  2. 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()
    }
    
  3. 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.
内置函数 appendcopy 用于常见的切片操作。对于这两个函数,其结果不依赖于参数引用的内存是否重叠。

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.
如果映射或切片是 nilclear 即为 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 根据浮点数实部和虚部构造复数值,而 realimag 则用于提取复数值的实部与虚部。

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.
对于 realimag ,实参必须是复数类型,返回类型为对应的浮点类型: complex64 实参对应 float32complex128 实参对应 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))).
函数 realimag 共同构成 complex 的逆函数,因此对于复杂类型 Z 的值 zz == 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.
若地图 mnil 或元素 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.
内置函数 lencap 可接受多种类型的参数,并返回 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 不会被求值。否则, lencap 的调用不是常量,且 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.
每个尺寸参数 nm 必须为整型、仅包含整型的类型集合,或是无类型常量。常量尺寸参数必须非负,且可由 int 类型的值表示;若为无类型常量,则赋予 int 类型。若同时提供常量 nm ,则 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].
内置函数 minmax 分别计算有序类型固定参数的最小值——或最大值。参数数量至少需一个[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.
与运算符相同的类型规则同样适用:对于有序参数 xy ,若 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 相等时, minmax 具有可交换和可结合性:

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=0b=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.
两个内置函数 panicrecover 协助报告和处理运行时恐慌及程序定义的错误条件。

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 ,恐慌序列即终止。此时,在 Gpanic 之间调用的函数状态会被丢弃,正常执行恢复。接着运行 GD 前延迟的所有函数, 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.
实现限制: printprintln 无需接受任意参数类型,但必须支持布尔值、数值和字符串类型的打印输出。

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 。具体而言:

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.
初始化顺序为 dbca 。请注意初始化表达式中子表达式的顺序无关紧要:在此示例中, a = c + ba = 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 之前、在 ba 之间,或在 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 ,反之亦然。 Pointeruintptr 间的转换效果由实现定义。

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.
AlignofSizeof 函数接受任意类型的表达式 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 )属于常量大小的类型时,对 AlignofOffsetofSizeof 的调用即为 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.
函数 Addlen 添加到 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 ,长度与容量均为 lenSlice(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].
除非在特殊情况下,如果 ptrnillen 为零,则 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 为负值,或 ptrnillen 非零,将触发运行时恐慌[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] 。若 slicenil ,则结果为 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 。对 ptrlen 参数的要求与函数 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:
以下最小对齐属性得到保证:

  1. For a variable x of any type: unsafe.Alignof(x) is at least 1.
    对于任意类型的变量 xunsafe.Alignof(x) 至少为 1。
  2. For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least 1.
    对于一个结构类型的变量 xunsafe.Alignof(x) 是对于 x 的每个字段 f 而言所有 unsafe.Alignof(x.f) 值中的最大值,但至少为 1。
  3. For a variable x of array type: unsafe.Alignof(x) is the same as the alignment of a variable of the array's element type.
    对于数组类型的变量 x :其对齐要求与数组元素类型变量的对齐要求相同。

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

Go 1.13

Go 1.14

Go 1.17

Go 1.18  Go 1.18 段落

The 1.18 release adds polymorphic functions and types ("generics") to the language. Specifically:
1.18 版本向该语言添加了多态函数和类型("泛型")。具体包括:

Go 1.20

Go 1.21  Go 1.21 节

Go 1.22

Go 1.23  Go 1.23 节

Go 1.24

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:
如果满足以下任一条件为真,则两种非绑定类型参数将精确统一:

If both types are bound type parameters, they unify per the given matching modes if:
若两种类型均为受限类型参数,则按照给定匹配模式进行统一的条件如下:

A single bound type parameter P and another type T unify per the given matching modes if:
单个绑定类型参数 P 与另一类型 T 根据给定匹配模式统一的条件为:

Finally, two types that are not bound type parameters unify loosely (and per the element matching mode) if:
最终,在以下情况下,两种非绑定类型参数会松散地统一(且依据元素匹配模式):