一 标记

Go有四种类型的标记:

  • 标识(shí)符
  • 关键字
  • 运算符和分隔符
  • 字面量

空白符包括空格(U+0020),横向制表符(U+0009),回车符(U+000D)和换行符(U+000A),除非用它们来分隔会结合成单个的标记,否则将被忽略。此外,换行符或EOF(文件结束符)会触发分号的插入。当把输入分解为标记时,可形成有效标记的最长字符序列将作为下一个标记。

二 分号

大多数语言的标准语法中使用;作为结束符,同样,Go的正式语法也使用分号来终止语句,但是,在实际的源代码中一般不需要使用分号来结束语句,因为Go的词法分析器会使用一个简单的规则在扫描时自动插入分号,所以源代码中就可以省略了(当然你写了也不会有问题)。
Go程序中可以省略大多数分号,满足以下两个规则即可:

  1. 行尾如果是以下标记之一:

    • 标识符(包括像int,float64等这样的词)
    • 基本的字面量,如整数字面量,浮点数字面量,虚数字面量,符文字面量或字符串字面量
    • 关键字break,continue,fallthrough, 或return之一
    • 运算符和分隔符++, --, ), ], 或 }之一
  2. 为了允许复杂语句占用一行,在结束“)”或“}”之前可以省略分号。如go func() { for { dst <- <-src } }()

Go程序只在像for循环语句之类的地方使用分号,以分隔初始化器、条件和接下来的元素;也可以用作一行中的多个语句分隔,但不推荐这种写法,这样不易于阅读。

这种规则导致的一个后果就是,不能将控制结构(ifforswitch,或select)的左大括号另起一行,否则会默认插入一个分号,导致莫名其妙的问题。
例如,你只能这么写:

if i < f() {
    g()
}

而不能这样写:

if i < f()  // 错误!
{           // 错误!
    g()
}

三 标识符

标识符命名程序实体,如变量和类型等,标识符是一个或多个字母或数字的序列,其中第一个字符必须是字母(包含下划线)

如:

a
_x9
ThisVariableIsExported
αβ

四 关键字

以下25个关键字是保留的,不能用作标识符:

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

五 运算符和分隔符

运算符(包括赋值运算符)和标点符号:

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
     &^          &^=

六 整数字面量

可选的前缀表示非十进制基数:0-八进制,0x0X-16进制。在十六进制中,字母a-f和A-F表示10到15

42
0600
0xBadFace
170141183460469231731687303715884105727

七 浮点数字面量

浮点数包括整数部分,小数点,小数部分,指数部分。整数部分和小数部分由十进制数字构成;指数部分是e或E,后跟可选的带符号十进制指数。整数部分和小数部分可以省略其一;小数点和指数可以省略其一。

0. // 省略小数部分,小数部分为0
72.40
072.40 // == 72.40
2.71828
1.e+0 // 省略小数部分,小数部分为0
6.67428e-11
1E6       // 省略小数点和小数部分
.25       // 省略整数部分,整数部分为0
.12345E+5 // 省略整数部分,整数部分为0

八 虚数字面量

虚数字面量是复数常量的虚部的十进制表示形式。它由浮点字面量或十进制整数后跟小写字母i组成

0i
011i  // == 11i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i

九 符文字面量

符文字面量表示符文常量,一个标识Unicode码点的整数值。符文字面量表示为用单引号括起来的一个或多个字符,如'x''\n'。在引号内,除换行符和未转义的单引号外,任何字符都可以出现。单引号扩起的字符表示字符本身的Unicode值,而以反斜杠开头的多字符序列以多种格式编码值。

最简单的方式就是用单引号扩起单个字符;由于Go源文件是以UTF-8编码的Unicode字符,因此多个UTF-8编码的字节可以表示单个整数值。比如,字面量'a'包含单个字节,表示文字a(Unicode U+0061),值为0x61;而'ä'包含两个字节(0xc3 0xa4),表示文字a-dieresis(U+00E4),值为0xe4

几个反斜杠转义允许将任意值编码为ASCII文本。有四种方法可以将整数值表示为数字常量:\x后跟2个十六进制数字;\u后跟4个十六进制数字;\U后跟8个十六进制数字和一个普通的反斜杠\后跟3个八进制数字。每一种情况下,字面量的值都是由相应基数的数字表示的值。

虽然这些表示都是整数,但他们具有不同的有效范围。八进制转义必须表示0-255之间的值。十六进制通过构造满足这种条件。\u\U转义表示Unicode码点,因此其中一些值是非法的,特别是高于0x10FFFF的值和半个代理项对(surrogate halves)。

关于代理项对(surrogate pairs)以及surrogate halves:

“Unicode 标准”将代理项对定义为由两个代码单元序列组成的单个抽象字符的编码字符表示形式。 代理项对的第一个值是高代理项,它是一个介于 U+D800 和 U+DBFF 之间的 16 位代码值。 代理项对的第二个值是低代理项,它是一个介于 U+DC00 和 U+DFFF 之间的值。

“Unicode 标准”将组合字符序列定义为一个基字符与一个或多个组合字符的组合。 代理项对可表示基字符或组合字符。 有关代理项对及组合字符序列的更多信息,请参见位于 Unicode home page(Unicode 主页)的“Unicode Standard”(Unicode 标准)。

关键是要记住,代理项对表示 32 位单字符。 不能假定一个 16 位 Unicode 编码值会精确地映射到一个字符。 通过使用代理项对,16 位 Unicode 编码系统可以表示另外一百万个码位,而 Unicode 标准将为它们分配字符。

还可以参考这些文章:
1.what-is-a-surrogate-pair-in-java
2.why_does_unicode_use_surrogate_pairs_2_code
3.UTF-16 on wiki

反斜杠后,某些单字符转义表示的特殊值:

\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)(只在符文字面量中有转义效果)
\"   U+0022 双引号(double quote)  (只在字符串字面量中有转义效果)

所有其他以反斜杠开头的序列在符文字面量中都是非法的。

'a'
'ä'
'本'
'\t'
'\000'
'\007'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'
'\''         // 包含单引号字符的符文字面量
'aa'         // 非法: 字符过多
'\xa'        // 非法: 十六进制数字过少
'\0'         // 非法: 八进制数字太少
'\uDFFF'     // 非法: 代理项的一半
'\U00110000' // 非法: 无效的Unicode码点

十 字符串字面量

有两种形式:原始字符串字面量和解释字符串字面量。

原始字符串字面量是反引号之间的字符序列,如`foo`,在引号内,除反引号外,任何字符都可能出现。原始字符串文字的值是由引号之间未解释的(隐式UTF-8编码)字符组成的字符串,另外,反斜杠无特殊含义,字符串可能包含换行符。原始字符串文字中的回车符('r')将从原始字符串值中丢弃。

解释字符串字面量是双引号之间的字符序列,如"bar"。在引号内,除了换行符和未转义的双引号外,任何字符都可能出现。反斜杠转义被解释为符文字面量(除了\'是非法的,\是合法的)并具有相同的限制。

参考:
https://golang.org/ref/spec#Lexical_elements
https://technet.microsoft.com/zh-cn/windowsserver/8k5611at(v=vs.98)

文章目录