Carbon 语言字面量表达式详解:值驱动类型、iN/uN/fN 类型字面量与字符语义
Carbon 语言字面量表达式详解值驱动类型、iN/uN/fN 类型字面量与字符语义【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang本文围绕 docs/design/expressions/literals.md 展开结合 Carbon 仓库core/prelude中IntLiteral、FloatLiteral、CharLiteral等类型的真实实现如 int_literal.carbon、int.carbon、char.carbon系统讲解 Carbon 中数值字面量、数值类型字面量iN/uN/fN、字符串字面量、字符字面量与char类型字面量的语法、类型规则与隐式转换语义。读完本文你将理解 Carbon 如何做到字面量的值携带在类型中掌握数值字面量隐式转换的边界条件并能熟练在变量初始化、泛型约束与模式匹配中正确使用各类字面量。数值字面量类型由值决定Carbon 中数值字面量numeric literal的类型从其值推导而来这是整个字面量体系最核心的设计两个整数字面量同类型当且仅当它们表示同一个整数两个实数real number字面量同类型当且仅当它们表示同一个实数。也就是说对于每个整数都存在一个表示值为该整数的字面量的类型对于每个有理数也存在一个表示值为该实数的字面量的类型。实数类型与整数类型彼此不同即使该实数恰好是整数。例如1 / 2结果是0整数除法而1.0 / 2结果是0.5。原因正是1具有整数类型而1.0虽然数值相同却具有实数类型见 literals.md。数值字面量之间可以直接使用原语运算运算结果仍然保持字面量类型例如1 2的类型与3的类型相同。因此字面量的值被携带在类型之中类型系统可以在编译期做出该转换是否合法的判定——这为后面要讲到的范围检查式隐式转换打下了基础。数值字面量语法速查数值字面量的词法规范由 numeric_literals.md 定义。Carbon 支持以下语法字面量是大小写敏感的且没有像 C 那样的类型后缀整数字面量十进制整数写作非零十进制数字后跟零或多个数字或单独一个0。其他进制以0加进制说明符开头进制说明符进制可用数字b20、1o80…7x160…9、A…F注意该表是大小写敏感的0b1、0o7、0x1A合法而0B1、0O7、0X1A、0x1a非法。C 风格的0755八进制写法在 Carbon 中不合法必须写0o755。实数Real-Number字面量由十进制或十六进制整数、句点.以及一侧的十进制/十六进制数字序列组成且小数点两侧都必须有数字123.456小数点两侧均有数字123.456e789e后可选或-默认为效果是乘以 10±N0x1.2p123十六进制实数p后可选或-效果是乘以 2±N。实数后缀的指数对十进制与十六进制实数都是可选的。几个容易踩坑的词法边界0.与.3都会被切分为两个独立 token——0.(Util.Abs)()与tuple.3中的句点都被视为成员/元素访问而非小数点为了支持元组下标紧跟在.token 之后无空白时绝不会形成实数结果是整数字面量十进制整数后跟e不是实数3e10不是合法字面量。数字分隔符下划线_可以出现在字面量内任意两个数字之间例如1_23_456_7890、0x7_F_FF_FFFF、0o7_55、0b1_000_101_11、2_147.48_3648e12_345、0x1_00CA.FE_F00Dp2_4。这套语法刻意贴近 C 与多数语言的习惯同时选取了一个最小合理子集以降低程序员的选择成本、简化语法规则并提升代码一致性对齐项目目标 goals.md 中代码易于阅读、理解和编写的追求同时保留十六/八/二进制整数、科学计数法与十六进制科学计数法浮点数以满足底层系统编程需求。预定义的字面量相关类型Carbon prelude 定义了如下与字面量直接相关的类型Core.BigInt任意精度整数类型Core.Rational(T: type)有理数类型由分子/分母所用的类型参数化目前对T的具体约束尚未最终确定Core.IntLiteral(N: Core.BigInt)表示整数字面量的类型Core.FloatLiteral(X: Core.Rational(Core.BigInt))表示浮点字面量的类型。以上类型都可在编译期使用。Core.BigInt支持与Core.Int(N)相同的运算Core.Rational(T)支持与Core.Float(N)相同的运算。Core.IntLiteral(N)与Core.FloatLiteral(X)同样支持加减乘除、比较等原语运算但这些运算通常是**异质heterogeneous**的例如Core.IntLiteral(N)与Core.IntLiteral(M)相加结果类型是Core.IntLiteral(N M)。在仓库源码中可以看到这些类型的真实定义方式。以 int_literal.carbon 为例package Core library prelude/types/int_literal; private fn MakeIntLiteral() - type int_literal.make_type; alias IntLiteral MakeIntLiteral();float_literal.carbon 与 char_literal.carbon 采用同样的模式float_literal.make_type、char_literal.make_type即这些字面量类型由编译器内置的make_type原语构造参数化细节由编译期内置机制承载。隐式转换规则Core.IntLiteral(N)可以隐式转换为任何足够大的整数类型语义上等价于如下仅供阐述部分语法尚未最终确定impl forall [template N: Core.BigInt, template M: Core.BigInt] Core.IntLiteral(N) as ImplicitAs(Core.Int(M)) if N Core.Int(M).MinValue as Core.BigInt and N Core.Int(M).MaxValue as Core.BigInt { ... } impl forall [template N: Core.BigInt, template M: Core.BigInt] Core.IntLiteral(N) as ImplicitAs(Core.UInt(M)) if N Core.UInt(M).MinValue as Core.BigInt and N Core.UInt(M).MaxValue as Core.BigInt { ... }类似的Core.IntLiteral(X)与Core.FloatLiteral(X)可以隐式转换为任何足够大的浮点类型并产生最接近的可表示浮点值。两条补充规则当X恰好位于两个可表示值正中间tie时按IEEE 754 标准舍入到尾数为偶数的一侧——该决定来自 提案 #866当X超出浮点类型的有限值范围时转换被拒绝而不是饱和到有限范围或产生无穷大。这些规则在 prelude 源码中有直接对应物。例如 int.carbon 中impl forall [To: IntLiteral] IntLiteral as ImplicitAs(Int(To)) { fn Convert(self) - Int(To) int.convert_checked; }同样地uint.carbon 提供了IntLiteral as ImplicitAs(UInt(To))同样是int.convert_checked而 float.carbon 提供了impl forall [N: IntLiteral] FloatLiteral as ImplicitAs(Float(N)) { fn Convert(self) - Float(N) float.convert_checked; } // ... impl forall [To: IntLiteral] IntLiteral as ImplicitAs(Float(To)) { fn Convert(self) - Float(To) int.convert_float_checked; }int.convert_checked这类名字中的checked正是范围检查的体现值必须在目标类型可表示范围内否则转换不成立——这从实现层面印证了文档中值携带在类型里由类型级决策判定转换是否有效的设计。综合示例与逐段解读原文档给出了丰富的实战示例这里完整保留并逐段说明// 合法-2147483648 虽然是「一元负号 字面量」写成 // 但其初始化器的类型就是「值为 -2147483648 的整数字面量类型」。 var x: i32 -2147483648; // 将 y 初始化为 2^60。 var y: i64 1 60; // 形成一个值为三分之一的有理数字面量并转换为 f64 最近可表示值。 var z: f64 1.0 / 3.0; // 错误300 无法在类型 i8 中表示。 var c: i8 300; fn Ftemplate T: type { var x: i32 v * 2; } // 合法x 2_000_000_000。 F(1_000_000_000); // 错误4_000_000_000 无法在类型 i32 中表示。 F(2_000_000_000); // 当 Bound 是整数字面量类型时该成员无需存储空间。 struct Span(template T: type, template BoundT: type) { var begin: T*; var bound: BoundT; } // 返回 11.3 可隐式转换为 f32即使转换到 f64 可能更精确。 fn G() - i32 { match (1.3) { case _: f32 { return 1; } case _: f64 { return 2; } } } // 只能以字面量 0 调用。 fn PassMeZero(_: Core.IntLiteral(0)); // 只能以给定范围内的整数字面量调用。 fn ConvertToBytetemplate N: Core.BigInt) - i8 if N -128 and N 127 { return N as i8; } // 给定任意整数字面量产出值加一的字面量。 fn OneHigher(L: Core.IntLiteral(template _: Core.BigInt)) - auto { return L 1; } // 错误256 无法在类型 i8 中表示。 var v: i8 OneHigher(255);要点归纳-2147483648合法一元负号作用于字面量后结果仍被视作值为 -2147483648 的整数字面量类型恰好落在i32最小值边界上因此可以初始化i32字面量参与模板/泛型运算时仍保持字面量类型F(1_000_000_000)中v * 2的乘法在编译期以精确整数语义求值结果2_000_000_000仍在i32范围内故合法F(2_000_000_000)得到的4_000_000_000超出i32表示范围报错字面量类型可以零开销存储struct Span中bound: BoundT若BoundT为整数字面量类型不需要任何存储空间——因为该值已编码在类型中字面量类型影响模式匹配match (1.3)时1.3可隐式转换到f32也可转换到f64匹配选择f32分支即使转换到f64理论上更精确可以用具体值约束字面量参数PassMeZero只接受字面量0ConvertToByte通过where约束-128 N 127才允许调用OneHigher接受任意整数字面量并返回值加一的字面量——var v: i8 OneHigher(255)因为256溢出i8而报错。备选方案回顾数值字面量语义在设计过程中曾评估过多个备选方案相关讨论记录在提案中使用普通整数或浮点类型作为字面量类型所有字面量使用同一种类型允许字面量 token 前导-禁止浮点平局ties。最终采用值即类型方案正是为了在编译期完成范围检查、实现零存储的字面量类型参数以及精确的算术传播。数值类型字面量iN、uN、fNCarbon 提供了形如iN、uN、fN的关键词式类型字面量分别表示二进制补码twos complement有符号整数、无符号整数与 IEEE-754 浮点数。其中N必须是 8 的正倍数包括常见的 2 的幂尺寸如N 8, 16, 32i16—— 16 位二进制补码有符号整数类型u32—— 32 位无符号整数类型f64—— 64 位 IEEE-754 二进制浮点数类型。语义Core 包的别名这些类型字面量是 prelude 自动导入的Core包中参数化类型的别名iN是Core.Int(N)的别名uN是Core.UInt(N)的别名fN是Core.Float(N)的别名。在源码中int.carbon 给出了Core.Int的真实形态private fn MakeInt(size: IntLiteral) - type int.make_type_signed; class Int(N: IntLiteral) { adapt MakeInt(N); }可以看到Core.Int(N)是一个以IntLiteral为参数、由内置int.make_type_signed构造的类uint.carbon 对应int.make_type_unsignedfloat.carbon 对应float.make_type。而i32这类写法本质上就是对这些参数化类的语法糖。用法示例package sample; fn Sum(x: i32, y: i32) - i32 { return x y; } fn Run() - i32 { return Sum(4, 2); }上述例子中Sum的参数x、y的类型都是 32 位二进制补码有符号整数Run返回Sum的结果类型同为 32 位二进制补码有符号整数。备选方案回顾iN/uN/fN语法在 提案 #2015 中经过了充分讨论备选方案包括C LP64 约定带长度后缀的类型名大写后缀额外的位宽选择。字符串字面量字符串字面量的词法由 string_literals.md 定义。需要特别说明的是截至目前字符串类型的设计尚未走完提案流程——也就是说Carbon 虽然已经定义了字符串字面量的词法形态但String类型本身的规范仍在设计中。仓库中已存在 string.carbon 的初步实现但按其设计文档的表述字符串类型层面的语义设计仍在推进中使用时应以该文档的最新状态为准。字符字面量字符字面量的词法由 character_literals.md 定义。在 Carbon 中字符字面量的类型是Core.CharLiteral表示单个 Unicode 码点。支持加减法Core.CharLiteral支持加法和减法具体语义见 arithmetic.md 中字符类型一节。例如a 1的结果是值为b的Core.CharLiteral产生非法 Unicode 码点的运算如a 0xFFFFFF是编译期错误。从源码看这一行为由 int.carbon 中CharLiteral与整数类型的异质运算实现支撑impl forall [N: IntLiteral] CharLiteral as AddWith(Int(N)) where .Result CharLiteral { fn Op(self, other: Int(N)) - CharLiteral char_literal.add; } impl forall [N: IntLiteral] Int(N) as AddWith(CharLiteral) where .Result CharLiteral { fn Op(self, other: CharLiteral) - CharLiteral int.add_char_literal; } impl forall [N: IntLiteral] CharLiteral as SubWith(Int(N)) where .Result CharLiteral { fn Op(self, other: Int(N)) - CharLiteral char_literal.sub_int; }这类运算的结果类型恒为CharLiteral值的合法性校验非法码点报错由编译期内置逻辑完成。隐式转换到charCore.CharLiteral在其值位于0x00..0x7F范围内时可隐式转换为char详见 implicit_conversions.md 中字符类型一节。在 char.carbon 中可以看到对应实现impl CharLiteral as ImplicitAs(Char) { fn Convert(self) - Char char_literal.convert_char; }即只有落在 ASCII 范围内的字符字面量才能免于显式转换地赋给char。字符类型字面量charCarbon 将char定义为一个类型字面量它与Core.Char是同一个类型——而Core.Char本质上是u8的适配器adapterclass Char { adapt u8; }见 char.carbon。char的语义要点概念上表示单个 UTF-8 编码单元code unit它可以包含非法的 UTF-8 编码单元只要仍保持 8 位即可不保证任何运行时校验Carbon 的字符串类型使用char作为元素类型。因此char与Unicode 码点是两个不同层次的概念码点由Core.CharLiteral承载编译期类型 编译期合法性校验而char只是 8 位字节的语义化包装便于字符串按编码单元寻址。参考提案与进一步阅读字面量相关设计均经过 Carbon 的提案流程按时间线可追踪到提案 #143数值字面量提案 #144数值字面量语义问题 #543为定宽整数类型定名提案 #866允许浮点字面量平局提案 #1964字符字面量提案 #2015数值类型字面量语法提案 #6710char重新设计。进一步深入源码时推荐阅读以下文件均为仓库根目录相对路径词法 numeric_literals.md、string_literals.md、character_literals.mdprelude 类型实现int_literal.carbon、float_literal.carbon、char_literal.carbon、int.carbon、uint.carbon、float.carbon、char.carbon。综上所述Carbon 的字面量体系可以概括为一条主线把字面量的值编码进类型IntLiteral/FloatLiteral/CharLiteral让范围检查、舍入规则、模式匹配与零存储绑定都在编译期完成同时通过iN/uN/fN这类简洁的类型字面量为程序员提供日常使用的定宽整数与浮点类型。理解这一设计是正确编写 Carbon 泛型代码与数值代码的前提。【免费下载链接】carbon-langCarbon Languages main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考