Files
the-swift-programming-langu…/source/chapter3/02_Lexical_Structure.md
2015-08-02 22:12:05 +08:00

22 KiB
Executable File
Raw Blame History

1.0 翻译:superkam
校对:numbbbbb

2.0 翻译+校对:[buginux](KYawn

词法结构


本页包含内容:

Swift 的“词法结构(lexical structure)”描述了能构成该语言中合法标记(tokens)的字符序列。这些合法标记组成了语言中最底层的构建基块,并在之后的章节中用于描述语言的其他部分。

通常情况下,标记是在随后将介绍的语法约束下,由 Swift 源文件的输入文本中提取可能的最长子串生成。这种方法称为“最长匹配项(longest match)”,或者“最大适合”(maximal munch)。

空白与注释

空白(whitespace)有两个用途:分隔源文件中的标记和帮助区分运算符属于前缀还是后缀(参见 运算符),在其他情况下则会被忽略。以下的字符会被当作空白:空格(spaceU+0020、换行符line feedU+000A、回车符carriage returnU+000D、水平制表符horizontal tabU+0009、垂直制表符vertical tabU+000B、换页符form feedU+000C以及空nullU+0000

注释(comments)被编译器当作空白处理。单行注释由 // 开始直至遇到换行符(line feedU+000A或者回车符carriage returnU+000D。多行注释由 /* 开始,以 */ 结束。注释允许嵌套,但注释标记必须匹配。

标识符

标识符(identifiers)可以由以下的字符开始:大写或小写的字母 AZ、下划线 _、基本多文种平面(Basic Multilingual Plane)中的 Unicode 非组合字符以及基本多文种平面以外的非专用区(Private Use Area)字符。首字符之后,允许使用数字和 Unicode 字符组合。

使用保留字(reserved word)作为标识符,需要在其前后增加反引号 `` 。例如,class 不是合法的标识符,但可以使用 <code>\class`。反引号不属于标识符的一部分,`x`x 表示同一标识符。

闭包(closure)中如果没有明确指定参数名称,参数将被隐式命名为 $0$1$2等等。 这些命名在闭包作用域范围内是合法的标识符。

标识符语法
标识符头部标识符 标识符字符组可选
标识符 → `头部标识符 标识符字符组可选`
标识符隐式参数名
标识符列表标识符 | 标识符 , 标识符列表

头部标识符 → 大写或小写字母 A - Z
头部标识符 → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2U+00B5, or U+00B7U+00BA
头部标识符 → U+00BCU+00BE, U+00C0U+00D6, U+00D8U+00F6, or U+00F8U+00FF
头部标识符 → U+0100U+02FF, U+0370U+167F, U+1681U+180D, or U+180FU+1DBF
头部标识符 → U+1E00U+1FFF
头部标识符 → U+200BU+200D, U+202AU+202E, U+203FU+2040, U+2054, or U+2060U+206F
头部标识符 → U+2070U+20CF, U+2100U+218F, U+2460U+24FF, or U+2776U+2793
头部标识符 → U+2C00U+2DFF or U+2E80U+2FFF
头部标识符 → U+3004U+3007, U+3021U+302F, U+3031U+303F, or U+3040U+D7FF
头部标识符 → U+F900U+FD3D, U+FD40U+FDCF, U+FDF0U+FE1F, or U+FE30U+FE44
头部标识符 → U+FE47U+FFFD
头部标识符 → U+10000U+1FFFD, U+20000U+2FFFD, U+30000U+3FFFD, or U+40000U+4FFFD
头部标识符 → U+50000U+5FFFD, U+60000U+6FFFD, U+70000U+7FFFD, or U+80000U+8FFFD
头部标识符 → U+90000U+9FFFD, U+A0000U+AFFFD, U+B0000U+BFFFD, or U+C0000U+CFFFD
头部标识符 → U+D0000U+DFFFD or U+E0000U+EFFFD
标识符字符 → 数值 0 - 9
标识符字符 → U+0300U+036F, U+1DC0U+1DFF, U+20D0U+20FF, or U+FE20U+FE2F
标识符字符头部标识符
标识符字符组标识符字符 标识符字符列表可选

隐式参数名$ 十进制数字列表

关键字和符号

下面这些被保留的关键字(keywords)不允许用作标识符,除非被反引号转义,具体描述请参考 标识符

  • 用在声明中的关键字: classdeinitenumextensionfuncimportinitletprotocolstaticstructsubscripttypealiasvar
  • 用在语句中的关键字: breakcasecontinuedefaultdoelsefallthroughifinforreturnswitchwherewhile
  • 用在表达式和类型中的关键字: asdynamicTypeisnewsuperselfSelfType__COLUMN____FILE____FUNCTION____LINE__
  • 用在模式中的关键字: _
  • 特定上下文中被保留的关键字: associativitydidSetgetinfixinoutleftmutatingnonenonmutatingoperatoroverridepostfixprecedenceprefixrightsetunownedunowned(safe)unowned(unsafe)weakwillSet,这些关键字在特定上下文之外可以被用于标识符。

以下标记被当作保留符号,不能用于自定义操作符:(){}[].,:;=@#&(作为前缀操作符)->、`` ?!(作为后缀操作符)`。

字面量

字面量是用来表示源码中某种特定类型的值,比如一个数字或字符串。

下面是字面量的一些示例:

42                 // 整型字面量
3.14159            // 浮点型字面量
"Hello, world!"    // 字符串型字面量
true			   // 布尔型字面量

字面量本身并不包含类型信息。事实上,一个字面量会被解析为拥有无限的精度,然后 Swift 的类型推导会尝试去推导出这个字面量的类型。比如,在 let x: Int8 = 42 这个声明中Swift 使用了显式类型标注(: Int8)来推导出 42 这个整型字面量的类型是 Int8。如果没有可用的类型信息, Swift 则会从标准库中定义的字面量类型中推导出一个默认的类型。整型字面量的默认类型是 Int,浮点型字面量的默认类型是 Double,字符串型字面量的默认类型是 String,布尔型字面量的默认类型是 Bool。比如,在 let str = "Hello, world" 这个声明中,字符串 "Hello, world"的默认推导类型就是 String

当为一个字面量值指定了类型标注的时候,这个注解的类型必须能通过这个字面量值实例化后得到。也就是说,这个类型必须遵守这些 Swift 标准库协议中的一个:整型字面量的IntegerLiteralConvertible协议、符点型字面量的FloatingPointLiteralConvertible协议、字符串字面量的StringLiteralConvertible协议以及布尔型字面量的BooleanLiteralConvertible协议。比如,Int8 遵守了 IntegerLiteralConvertible协议,因此它能在 let x: Int8 = 42 这个声明中作为整型字面量 42 的类型标注。

字面量语法
字面量数字型字面量 | 字符串型字面量 | 布尔型字面量 | nil型字面量

数字型字面量 → -可选整型字面量 | -可选符点型字面量
布尔型字面量true | false
nil型字面量nil

整型字面量

整型字面量(integer literals)表示未指定精度整型数的值。整型字面量默认用十进制表示,可以加前缀来指定其他的进制,二进制字面量加 0b,八进制字面量加 0o,十六进制字面量加 0x

十进制字面量包含数字 09。二进制字面量只包含 01,八进制字面量包含数字 07,十六进制字面量包含数字 09 以及字母 AF (大小写均可)。

负整数的字面量在整型字面量前加减号 -,比如 -42

整型字面面可以使用下划线 _ 来增加数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 0,并不会影响字面量的值。

除非特别指定,整型字面量的默认推导类型为 Swift 标准库类型中的 Int。Swift 标准库还定义了其他不同长度以及是否带符号的整数类型,请参考 整数类型

整型字面量语法
整型字面量二进制字面量
整型字面量八进制字面量
整型字面量十进制字面量
整型字面量十六进制字面量
二进制字面量0b 二进制数字 二进制字面量字符组可选
二进制数字 → 数值 0 到 1
二进制字面量字符二进制数字 | _
二进制字面量字符组二进制字面量字符 二进制字面量字符组可选

八进制字面量0o 八进字数字 八进制字符列表可选
八进字数字 → 数值 0 到 7
八进制字符八进字数字 | _
八进制字符组八进制字符 八进制字符列表可选
十进制字面量十进制数字 十进制字符组可选
十进制数字 → 数值 0 到 9
十进制数字列表十进制数字 十进制数字列表可选
十进制字符十进制数字 | _
十进制字符列表十进制字符 十进制字符列表可选
十六进制字面量0x 十六进制数字 十六进制字面量字符列表可选
十六进制数字 → 数值 0 到 9, 字母 a 到 f, 或 A 到 F
十六进制字符十六进制数字 | _
十六进制字面量字符列表十六进制字符 十六进制字面量字符列表可选

浮点型字面量

浮点型字面量(floating-point literals)表示未指定精度浮点数的值。

浮点型字面量默认用十进制表示(无前缀),也可以用十六进制表示(加前缀 0x)。

十进制浮点型字面量(decimal floating-point literals)由十进制数字串后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 . 后跟十进制数字串组成。指数部分由大写或小写字母 e 为前缀后跟十进制数字串组成,这串数字表示 e 之前的数量乘以 10 的几次方。例如:1.25e2 表示 1.25 ⨉ 10^2,也就是 125.0;同样,1.25e2 表示 1.25 ⨉ 10^2,也就是 0.0125

十六进制浮点型字面量(hexadecimal floating-point literals)由前缀 0x 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字串组成。指数部分由大写或小写字母 p 为前缀后跟十进制数字串组成,这串数字表示 p 之前的数量乘以 2 的几次方。例如:0xFp2 表示 15 ⨉ 2^2,也就是 60;同样,0xFp-2 表示 15 ⨉ 2^-2,也就是 3.75

负的浮点型字面量由一元运算符减号 - 和浮点型字面量组成,例如 -42.5

浮点型字面量允许使用下划线 _ 来增强数字的可读性,下划线会被系统忽略,因此不会影响字面量的值。同样地,也可以在数字前加 0,并不会影响字面量的值。

除非特别指定,浮点型字面量的默认推导类型为 Swift 标准库类型中的 Double表示64位浮点数。Swift 标准库也定义了 Float 类型表示32位浮点数。

浮点型字面量语法
浮点数字面量十进制字面量 十进制分数可选 十进制指数可选
浮点数字面量十六进制字面量 十六进制分数可选 十六进制指数
十进制分数. 十进制字面量
十进制指数浮点数e 正负号可选 十进制字面量
十六进制分数. 十六进制数字 十六进制字面量字符列表可选
十六进制指数浮点数p 正负号可选 十进制字面量
浮点数ee | E
浮点数pp | P
正负号+ | -

字符串型字面量

字符串型字面量(string literal)由被包在双引号中的一串字符组成,形式如下:

"characters"

字符串型字面量中不能包含未转义的双引号 ")、未转义的反斜线(\)、回车符(carriage return)或换行符(line feed)。

可以在字符串字面量中使用的转义特殊符号如下:

  • 空字符Null Character\0
  • 反斜线Backslash\\
  • 水平制表符Horizontal Tab\t
  • 换行符Line Feed\n
  • 回车符Carriage Return\r
  • 双引号Double Quote\"
  • 单引号Single Quote\'
  • Unicode标量 \u{n}n为一到八位的十六进制数字

字符串字面量允许在反斜杠小括号 \() 中插入表达式的值。插入表达式(interpolated expression)不能包含未转义的双引号 "、未转义的反斜线 \、回车符或者换行符。表达式结果的类型必须在 String 类中有对应的初始化方法。

例如,以下所有字符串字面量的值都是相同的:

"1 2 3"
"1 2 \(3)"
"1 2 \(1 + 2)"
let x = 3; "1 2 \(x)"

字符串字面量的默认推导类型为 String。组成字符串的字符默认推导类型为 Character。更多有关 StringCharacter 的信息请参照 字符串和字符

字符型字面量语法
字符串字面量" 引用文本可选 "
引用文本引用文本条目 引用文本 可选
引用文本条目转义字符
引用文本条目( 表达式 )
引用文本条目除了"­, \­, U+000A, 或者 U+000D的所有Unicode的字符
转义字符\0 | \ | \t | \n | \r | " | '
转义字符\u { unicode标量数字 } unicode标量数字 → 一到八位的十六进制数字

运算符

Swift 标准库定义了许多可供使用的运算符,其中大部分在 基础运算符高级运算符 中进行了阐述。这一小节将描述哪些字符能用于自定义运算符。

自定义运算符可以由以下其中之一的 ASCII 字符 /=-+!*%<>&|^? 以及 ~, 或者后面语法中规定的任一个 Unicode 字符开始。在第一个字符之后,允许使用组合型 Unicode 字符。也可以使用两个或者多个的点号来自定义运算符(比如, ....)。虽然可以自定义包含问号?的运算符,但是这个运算符不能只包含单独的一个问号。

注意:
以下这些标记 =, ->, //, /*, */, ., <(前缀运算符), &, and ?, ?(中缀运算符), >(后缀运算符), ! 以及 ? 是被系统保留的。这些标记不能被重载,也不能用于自定义操作符。

运算符两侧的空白被用来区分该运算符是否为前缀运算符(prefix operator)、后缀运算符(postfix operator)或二元运算符(binary operator)。规则总结如下:

  • 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:a+ba + b 中的运算符 + 被看作二元运算符。
  • 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 a ++b 中的 ++ 被看作前缀一元运算符。
  • 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 a++ b 中的 ++ 被看作后缀一元运算符。
  • 如果运算符左侧没有空白并紧跟 .,将被看作后缀一元运算符。例如 a++.b 中的 ++ 被看作后缀一元运算符(即上式被视为 a++ .b 而非 a ++ .b)。

鉴于这些规则,运算符前的字符 ([{ ;运算符后的字符 )]} 以及字符 ,;: 都被视为空白。

以上规则需注意一点,如果预定义运算符 !? 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 ? 用作可选链(optional-chaining)操作符,左侧必须无空白。如果用于条件运算符 ? :,必须两侧都有空白。

在某些特定的构造中 ,以 <> 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 Dictionary<String, Array<Int>> 中没有必要添加空白来消除闭合字符 > 的歧义。在这个例子中, 闭合字符 > 不会被视为单独的标记,因而不会被误解析为 >> 运算符的一部分。

要学习如何自定义运算符,请参考 自定义操作符运算符声明。要学习如何重载运算符,请参考 运算符方法

运算符语法语法
运算符头部运算符 运算符字符组可选
运算符头部点运算符 点运算符字符组可选

头部运算符/ | = | + | ! |* | % |< | > |& | | |/ | ~ | ? | 头部运算符 → U+00A1U+00A7
头部运算符 → U+00A9 or U+00AB
头部运算符 → U+00AC or U+00AE
头部运算符 → U+00B0U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7
头部运算符 → U+2016U+2017 or U+2020U+2027
头部运算符 → U+2030U+203E
头部运算符 → U+2041U+2053
头部运算符 → U+2055U+205E
头部运算符 → U+2190U+23FF
头部运算符 → U+2500U+2775
头部运算符 → U+2794U+2BFF
头部运算符 → U+2E00U+2E7F
头部运算符 → U+3001U+3003
头部运算符 → U+3008U+3030
运算符字符头部运算符
运算符字符 → U+0300U+036F
运算符字符 → U+1DC0U+1DFF
运算符字符 → U+20D0U+20FF
运算符字符 → U+FE00U+FE0F
运算符字符 → U+FE20U+FE2F
运算符字符 → U+E0100U+E01EF

运算符字符组运算符字符 [运算符字符组] (#operator_characters)可选

头部点运算符..
头部点运算符字符 → . | 运算符字符
头部点运算符字符组点运算符字符 点运算符字符组可选

二元运算符运算符
前置运算符运算符
后置运算符运算符