Scala 词法语法完全指南:字符分类、标识符、字面量与换行规则

发布时间:2026/11/14 18:50:43

Scala 词法语法完全指南:字符分类、标识符、字面量与换行规则 编程语言编译器标准库语言运行时【免费下载链接】scalaScala 2 compiler and standard library. Scala 2 bugs at https://github.com/scala/bug; Scala 3 at https://github.com/scala/scala3项目地址https://gitcode.com/gh_mirrors/sc/scala点击查看免费下载本指南以 Scala 官方语言规范spec/01-lexical-syntax.md第一章「词法语法」为骨架系统讲解 Scala 源码如何从 Unicode 文本被切分为 token包括字符分类体系、三种标识符形态、保留字清单、语句结束的换行判定规则、各类字面量的完整语法以及注释、尾随逗号和 XML 模式的特殊处理。文中同时结合本仓库编译器与标准库实现Scanners.scala、Chars.scala、StringContext.scala给出源码级佐证。读完本文你将能够准确预判任意一段 Scala 代码会被如何切词、为何1.toString是三个 token、为何yield不能直接用作变量名以及多行字符串与插值字符串的边界行为。源文件与字符分类Scala 源码由 Unicode 文本构成。程序文本按照本章描述的方式被切分为 token词法单元。为构造 token字符被划分为以下几类括号内为 Unicode 通用类别类别包含字符Unicode 类别空白字符\u0020空格、\u0009水平制表符、\u000D回车、\u000A换行—字母小写字母Ll、大写字母Lu、标题字母Lt、其他字母Lo、修饰字母Lm、字母数字Nl外加\u0024$与\u005F_多类数字0至9Nd括号( ) [ ] { }—分隔符 . ; ,—运算符字符除上述集合外的全部可打印 ASCII 字符\u0020–\u007E、数学符号Sm、其他符号SoSm、So这份分类在编译器中有直接实现。Chars.scala 中的isIdentifierStart/isIdentifierPart基于Character.isUnicodeIdentifierStart/Part判定字母类字符isOperatorPart显式枚举~ ! # % ^ * - ? : | / \等 ASCII 运算符字符并叠加isSpecialUnicodeMATH_SYMBOL与OTHER_SYMBOLisScalaLetter则对应规范中的字母类。词法分析器 Scanners.scala 正是通过getIdentRest/getOperatorRest与这些谓词协同完成切词见下文。禁止出现的双向控制字符规范规定九个 Unicode 双向显式格式化字符被禁止出现在源码文件中\u202a–\u202e与\u2066–\u2069含端点。这些字符在字符串和字符字面量中可用 Unicode 转义\uXXXX表示。编译器在 Scanners.scala 中对应报错found unicode bidirectional character \uXXXX; in a string or character literal, use a unicode escape insteadChars.isBiDiCharacterChars.scala则精确匹配这九个码位。这一限制是为了防止利用双向文本特性制造「视觉与逻辑不一致」的恶意源码bidi attack。标识符Identifiers标识符的 EBNF 语法如下op :: opchar {opchar} varid :: lower idrest boundvarid :: varid | varid plainid :: upper idrest | varid | op id :: plainid | { charNoBackQuoteOrNewline | escapeSeq } idrest :: {letter | digit} [_ op] escapeSeq :: UnicodeEscape | charEscapeSeq UnicodeEscape :: \ u {u} hexDigit hexDigit hexDigit hexDigit hexDigit :: 0 | … | 9 | A | … | F | a | … | f三种构成形式字母开头的标识符以一个字母开头后接任意字母与数字序列其后可跟随一个或多个下划线_再接一段由字母数字或运算符字符组成的字符串。例如big_bob、p2p、empty_?、dot_product_*、_MAX_LEN_。运算符开头的标识符以一个运算符字符开头后接任意运算符字符序列如、。以上两种统称 plain普通标识符。反引号包裹的标识符任意字符串反引号除外置于反引号内如yield、://。宿主系统可能对合法标识符施加额外限制。规范特别指出虽然/是运算符字符但//与/*会开启注释因此要用作标识符时必须以反引号包裹例如def ://(s: String): URI def */*(d: Double): Double最长匹配规则与多数语言一致切词遵循最长匹配longest match规则。例如字符串big_bobdef被分解为三个标识符big_bob、、defdef虽为保留字但此处指反引号外的裸def不构成标识符的一部分。读者可以从扫描器实现观察到这一点getIdentRest 循环吞入字母、数字与$遇到_转入getIdentOrOperatorRest继续吞并随后的字母数字或运算符片段getOperatorRest 则连续吞入运算符字符直到遇到空白或不可作为运算符的字符为止。变量标识符与常量标识符模式匹配规则进一步区分变量标识符以小写字母或_开头与常量标识符其他情形。这里的「小写字母」不仅包含 a–z还包含 UnicodeLl类别以及具有Other_Lowercase贡献属性的字母但Nl字母数字类别的字符绝不视为小写。变量标识符示例x maxIndex p2p empty_? yield αρετη _y dot_product_* __system _MAX_LEN_ ªpple ʰelper常量标识符示例 Object $reserved Džul ǂnûm ⅰ_ⅲ Ⅰ_Ⅲ ↁelerious ǃqhàà ʹthatsaletter注意$字符被保留给编译器合成的标识符用户程序不应定义包含$的标识符。这一约定同样体现在 Chars.scalaisIdentifierStart与isIdentifierPart均允许$参与标识符。保留字Reserved Words以下名称是保留字不属于词法标识符id的成员abstract case catch class def do else extends false final finally for forSome if implicit import lazy macro match new null object override package private protected return sealed super this throw trait try true type val var while with yield _ : - : % : # 此外Unicode 运算符\u21D2⇒ASCII 等价与\u2190←ASCII 等价-同样被保留。访问 Java 保留字的方式当需要引用恰好是 Scala 保留字的 Java 标识符时使用反引号包裹。例如Thread.yield()非法yield是 Scala 保留字但Thread.yield()是合法写法。换行字符Newline Characters与语句结束Scala 是面向行的语言语句可由分号或换行终止。换行的判定规则如下semi :: ; | nl {nl}换行何时被当作 nl token源码文本中的换行只有在同时满足以下三个条件时才被当作特殊 tokennl换行之前紧邻的 token能够终止一条语句换行之后紧邻的 token能够开始一条语句该 token 位于启用换行的区域。能够终止语句的 token字面量、标识符以及下列分隔符与保留字this null true false return type xml-start _ ) ] }能够开始语句的 token除下列分隔符与保留字之外的所有 Scala tokencatch else extends finally forSome match with yield , . ; : - : % : # [ ) ] }casetoken 只有后接class或object时才可开始一条语句。换行启用与禁用的区域启用换行整个 Scala 源文件除嵌套的禁用区域外以及匹配的{与}之间的区间除嵌套的禁用区域外。禁用换行匹配的(与)之间、匹配的[与]之间均除外层嵌套的启用区域case与其匹配的之间以及所有 XML 模式区域。注意XML 与字符串字面量中{...}转义的括号字符不是 token因此不会构成启用换行的区域。连续换行与空行正常情况下两个不同行上的相邻非换行 token 之间只会插入一个nltoken即使中间隔了多行。但如果两个 token 之间隔着至少一个完全空白的行不含任何可打印字符的行则会插入两个nltoken。可选 nl 的位置不终止语句完整的 Scala 语法见 13-syntax-summary.md中某些产生式允许可选的nl但不允许分号这意味着这些位置的换行不会终止表达式或语句条件表达式或 while 循环的条件与下一个表达式之间for 推导式的枚举器与下一个表达式之间类型定义或声明中初始type关键字之后。允许单个换行 token 的位置在{之前若该{是当前语句或表达式的合法延续在 infix 运算符之后若下一行第一个 token 能开始一个表达式在参数列表之前在注解之后。规范给出了多组「有无额外换行导致语义迥异」的对照示例// 合法换行不终止语句 if (x 0) x x - 1 while (x 0) x x / 2 for (x - 1 to 10) println(x) type IntList List[Int]// 一个换行对象创建后紧跟一个块 new Iterator[Int] { private var x 0 def hasNext true def next { x 1; x } } // 空行分隔后对象创建 独立的局部块 new Iterator[Int] { private var x 0 def hasNext true def next { x 1; x } }// 一个换行单个表达式 x 0 || x 10 // 空行分隔后两个表达式 x 0 || x 10// 合法换行出现在参数列表前 def func(x: Int) (y: Int) x y // 空行分隔后抽象函数定义 非法语句 def func(x: Int) (y: Int) x y// 合法注解与定义之间换行 serializable protected class Data { ... } // 空行分隔后注解 独立语句语法非法 serializable protected class Data { ... }这些示例表明单换行在语法允许位置被吸收而空行产生的双nl则一定会终止语句。这也是 Scala 代码风格中「空行即分隔」的底层机制。字面量Literals字面量涵盖整数、浮点数、字符、布尔值、符号、字符串其语法与 Java 一致Literal :: [-] integerLiteral | [-] floatingPointLiteral | booleanLiteral | characterLiteral | stringLiteral | interpolatedString | symbolLiteral | null整数字面量integerLiteral :: (decimalNumeral | hexNumeral | binaryNumeral) [L | l] decimalNumeral :: digit {digit} hexNumeral :: 0 (x | X) hexDigit {hexDigit} binaryNumeral :: 0 (b | B) binaryDigit {binaryDigit}Int覆盖 $-2^{31}$ 到 $2^{31}-1$Long覆盖 $-2^{63}$ 到 $2^{63}-1$。超出范围的整数字面量是编译错误。整数字面量默认为Int带L/l后缀则为Long小写l因可读性原因被弃用。若字面量的期望类型pt为Byte、Short或Char且数值落在对应范围内则字面量自动转换并采用该类型。范围如下类型范围Byte$-2^7$ 到 $2^7-1$Short$-2^{15}$ 到 $2^{15}-1$Char$0$ 到 $2^{16}-1$数字字面量中可用任意多个下划线分隔数字以增强可读性0 21_000 0x7F -42L 0xFFFF_FFFF浮点字面量floatingPointLiteral :: digit {digit} . digit {digit} [exponentPart] [floatType] | . digit {digit} [exponentPart] [floatType] | digit {digit} exponentPart [floatType] | digit {digit} [exponentPart] floatType exponentPart :: (E | e) [ | -] digit {digit} floatType :: F | f | D | d带F/f后缀的浮点字面量为FloatIEEE 754 32 位单精度否则为DoubleIEEE 754 64 位双精度。若浮点字面量后紧跟一个以字母开头的 token两者之间必须有至少一个空白字符。注意1.toString会解析为三个 token整数1、.、标识符toString而1.不是合法浮点字面量.后缺少必需的数字。0.0 1e30f 3.14159f 1.0e-100 .1布尔字面量booleanLiteral :: true | falsetrue与false均为Boolean类型的成员。字符字面量characterLiteral :: (charNoQuoteOrNewline | escapeSeq) 字符字面量是单引号内的单个字符可以是除单引号定界符、\u000ALF、\u000DCR之外的任意 Unicode 字符或由转义序列表示的任意 Unicode 字符a \u0041 \n \t字符串字面量stringLiteral :: {stringElement} stringElement :: charNoDoubleQuoteOrNewline | escapeSeq字符串字面量是双引号内的字符序列可为除双引号定界符、LF、CR 之外的任意 Unicode 字符或由转义序列表示。字符串内含双引号必须转义为\。字符串字面量的值是一个String实例Hello, world!\n \Hello,\ replied the world.多行字符串字面量stringLiteral :: multiLineChars multiLineChars :: {[] [] charNoDoubleQuote} {}多行字符串以三引号 ... 包裹除结尾外不得出现三个及以上连续引号字符。字符不必可打印换行与控制字符均允许。转义序列不处理但 Unicode 转义仍被处理自 2.13.2 起这一行为被弃用。编译器侧 Scanners.scala 的replaceUnicodeEscapesInTriple会对三引号字符串中的 Unicode 转义发出弃用警告提示 Scala 3 或-Xsource-features:unicode-escapes-raw下将忽略这些转义。the present string spans three lines.结果为the present string spans three lines.标准库的stripMargin定义于scala.collection.StringOps可去除多行字符串的前导空白the present string |spans three |lines..stripMargin求值结果为the present string spans three lines.插值字符串Interpolated StringinterpolatedString :: alphaid {[\] interpolatedStringPart | \\ | \} | alphaid {[] [] char \ ( | $) | escape} {} interpolatedStringPart :: printableChar \ ( | $ | \) | escape escape :: $$ | $ | $ alphaid | $ BlockExpr alphaid :: upper idrest | varid插值字符串由「以字母开头的标识符 紧随其后的字符串字面量」组成两者之间不得有空白或注释。字符串字面量可为普通单引号形式或三引号多行形式。插值字符串内不解释通常的转义字符普通与多行形式皆然\不会关闭普通字符串字面量。$转义有三种形式最通用形式$后跟{与}包裹的表达式${expr}。其中的表达式属于BlockExpr语法类别可含多条语句换行有意义。单独的$不允许出现要得到字面$需写$$要得到字面需写\$。简单形式$后跟一个以字母开头、仅含字母数字与下划线的标识符$id等价于${id}。展开后的表达式正常做类型检查StringContext通常解析为 scala 包中的默认实现也可由用户自定义还可通过内置scala.StringContext的隐式转换添加新的插值器。例如implicit class StringInterpolation(s: StringContext) { def id(args: Any*) ??? }标准库中的 StringContext.scala 定义了内置的s、raw、f三个插值器在 2.13 中均通过宏 fast-track 到scala.tools.reflect.FastStringInterpolator实现其中InvalidUnicodeEscapeExceptionStringContext.scala用于校验字符串中 Unicode 转义的合法性。转义序列Escape Sequences字符与字符串字面量中识别下列字符转义序列字符转义Unicode名称字符\b\u0008退格backspaceBS\t\u0009水平制表符HT\n\u000a换行linefeedLF\f\u000c换页form feedFF\r\u000d回车CR\s\u0020空格\\u0022双引号\\u0027单引号\\\u005c反斜杠\此外字符与字符串字面量还识别\uxxxx形式的 Unicode 转义每个x为十六进制数字。若字符或字符串字面量中的反斜杠不能构成合法转义序列则为编译错误。对应实现见 Scanners.scala 的uEscape与非法转义、八进制转义octal escape literals are unsupported的报错逻辑。符号字面量Symbol LiteralssymbolLiteral :: plainid符号字面量x是表达式scala.Symbol(x)的弃用简写。Symbol伴生对象的apply方法会缓存符号的弱引用从而保证相同符号字面量在引用相等reference equality意义上等价。空白与注释Whitespace and Commentstoken 之间可由空白字符和/或注释分隔。注释有两种形式单行注释以//开始延伸到行尾。多行注释介于/*与*/之间。多行注释可以嵌套但必须正确嵌套因此/* /* */会因注释未闭合而被拒绝。扫描器中与此对应的逻辑位于 getOperatorRest运算符字符/后若紧跟*或/则转入skipComment跳过注释否则/仍作为普通运算符字符参与标识符切分。多行表达式中的尾随逗号Trailing Commas若一个逗号,后忽略空白紧跟换行与右括号)、右方括号]或右花括号}则该逗号被视为「尾随逗号」并被忽略。例如foo( 23, bar, true, )这一特性极大方便了多行参数列表、元组、集合字面量的增删与版本管理。XML 模式XML Mode为允许在源码中直接嵌入 XML 片段词法分析会在下列情形从 Scala 模式切换到 XML 模式遇到且该前是空白、左括号(或左花括号{并且紧随其后是一个能开启 XML 名称的字符( whitespace | ( | { ) (XNameStart | ! | ?) XNameStart :: _ | BaseChar | Ideographic // 同 W3C XML但不含 :扫描器在以下两种情况下切回 Scala 模式由初始开始的 XML 表达式或 XML 模式被成功解析或解析器遇到内嵌的 Scala 表达式或模式强制扫描器回到普通模式直至该 Scala 表达式或模式解析完成。由于代码与 XML 片段可以互相嵌套解析器需要维护一个栈来准确反映 XML 与 Scala 的嵌套层次。在 XML 模式下不构造任何 Scala token注释也被解释为文本。规范示例——一个含两处内嵌 Scala 表达式的 XML 字面量val b book titleThe Scala Language Specification/title version{scalaBook.version}/version authors{scalaBook.authors.mkList(, , , )}/authors /book延伸阅读完整 Scala 语法汇总见 spec/13-syntax-summary.md条件表达式与 while 循环的换行规则见 spec/06-expressions.md类型定义与类型别名type关键字后的换行见 spec/04-basic-declarations-and-definitions.md注解相关语法见 spec/11-annotations.md编译器词法分析实现见 Scanners.scala字符分类工具见 Chars.scala字符串插值器实现见 StringContext.scala赞分享编程语言编译器标准库语言运行时【免费下载链接】scalaScala 2 compiler and standard library. Scala 2 bugs at https://github.com/scala/bug; Scala 3 at https://github.com/scala/scala3项目地址https://gitcode.com/gh_mirrors/sc/scala点击查看免费下载相关推荐Carbon 语言词法单元 Word 完全指南关键字、标识符、类型字面量与 Raw 标识符Carbon 语言词法单元 Word 完全指南关键字、标识符、类型字面量与 Raw 标识符 本文基于 docs/design/lexical_conven编程语言编译器标准库Swift 词法结构Lexical Structure完全解析从标记、标识符到字面量与运算符的底层语法规则Swift 词法结构Lexical Structure完全解析从标记、标识符到字面量与运算符的底层语法规则 本篇技术指南以《The Swift Progr文档教程AssetRipper 实战教程Unity 资源提取与资产导出的最短路径AssetRipper 实战教程Unity 资源提取与资产导出的最短路径 AssetRipper 是一个开源的 GUI 工具专门做 Unity 资源提取 与开发工具逆向工程游戏开发上一篇OpenProject 工作包工作流配置详解基于矩阵的状态迁移权限控制与批量复制下一篇如何在5分钟内用Turbo Boost Switcher控制Mac过热完整温度管理指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/13 2:38:45

akshare 列名报错?TaoToken 这样改 Codex 的 Base URL

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/14 18:47:26

在哪可以查到电工证 电工证考前押题怎么找 拿证后到底能挣多少?

在哪可以查到电工证 电工证考前押题怎么找 拿证后到底能挣多少? 急需特种作业证才能上岗找工作,这事儿没人比你更急了。电工证是从事电工工作的“门槛证”,没有它连报名面试都难。现在不少地方明确要求持证上岗,尤其是在建筑、制造、电力、安装等行业。…

2026/11/14 18:47:26

电工证升职加薪攻略:2026河南最新政策下如何稳过实操考试

电工证升职加薪攻略:2026河南最新政策下如何稳过实操考试 实操考试心里没底怕挂科,这几乎是每个准备报考电工证的河南人的真实写照。特别是2026年河南最新政策出台后,电工证的报考门槛、考试难度以及证书含金量都有了新的变化。不少从事房建工程的…

2026/11/14 18:47:26

电工证是全国证件吗?良心建议帮你避开转证难题

电工证是全国证件吗?良心建议帮你避开转证难题 之前考的证在外省能不能转过来?这是很多学员在报考电工证前最关心的问题。尤其是从外地过来的学员,比如周口的很多小伙伴,手里拿着外地的电工证,到了本地却用不上,心里特别着急。 良心建议…

2026/11/14 18:47:26

低压电工证脱产培训内容网上查询最全指南

低压电工证脱产培训内容网上查询最全指南 你是不是也正为找不到低压电工证脱产培训内容发愁?网上查询半天,信息杂乱无章,根本不知道从哪儿下手?别急,这篇文章就是为像你一样急需特种作业证才能上岗找工作的朋友准备的。…

2026/11/14 18:42:25

怀化考电工证值不值得考?学历不高也能报上名

怀化考电工证值不值得考?学历不高也能报上名 你是不是也觉得, 学历不高怕报不上名 ,想着考个电工证,结果发现门槛挺高?其实不然,怀化考电工证的报名要求,并不像你想象中那么苛刻。只要满足基本条件,学历不高的你也一样可以报名,关键在于你是否了解…

2026/11/13 22:33:32

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/14 0:06:39

土木特种工考证官方报名入口怎么找 之前考的证在外省能不能转过来

土木特种工考证官方报名入口怎么找 之前考的证在外省能不能转过来 之前考的证在外省能不能转过来?这个问题我太熟悉了,作为一名干了十几年的特种作业证书办理从业者,每年都会遇到不少像你一样在外地考了证,回来却发现无法直接使用的学员。别急,今天我就…

2026/11/14 0:06:39

电工证要多久多钱保姆级教程:工地太忙根本没时间复习考试

电工证要多久多钱保姆级教程:工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,你不是一个人。在信阳浉河区,很多刚进入工地的电工都面临这样的困境:工作强度大,时间碎片化,根本没有系统复习考试的机会。但电工证是上岗的硬门槛,…

2026/11/13 22:32:11

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑