Skip to content
📖 Auto 编程语言(主书)本书目录

变量与运算符 ​

既然你已经用 "Hello, world!" 热了身,是时候学习每个程序都需要的基础构建块了:变量和运算符。在本章中,我们将讨论:

  • 使用 var 声明变量
  • 处理数字——整数和浮点数
  • 字符串字面量与拼接
  • 布尔值与逻辑运算符
  • 比较运算符
  • 变量遮蔽——重用变量名

var — 可变变量 ​

变量是给值起名字的方式,这样你就可以在后面使用它们。在 Auto 中,你使用 var 关键字声明变量:

auto
var x = 5

这一行同时做了三件事:

  1. 创建一个名为 x 的变量。
  2. 推断类型——5 是整数,所以 x 的类型是 int。不需要类型标注。
  3. 赋值——将值 5 赋给 x。

你不需要自己写类型。Auto 的编译器会帮你推断。这叫做 类型推断(type inference),它是让 Auto 既轻量又类型安全的特性之一。

用 var 声明的所有变量都是 可变的(mutable)——你可以在之后改变它们的值:

auto
var count = 0
count = count + 1

关于 let 和 var 的说明:

你可能注意到本章只使用了 var。这是有意的。Auto 有两个声明变量的关键字:var 用于可变变量,let 用于不可变变量。我们将在第 6 章讨论不可变性时介绍 let。目前,所有变量都用 var。

让我们看看不同类型的变量声明。

使用 `var` 声明变量

注意每种目标语言的不同处理方式:

  • Rust 使用 let mut 声明可变变量,并添加显式类型标注(i64、String、f64)。
  • Python 简单地写 x = 5。没有关键字,没有类型。最简洁。
  • C 既需要类型(long long、const char*、double),也需要分号。
  • TypeScript 走中间路线:let x: number = 5。类型在 TypeScript 中是可选的,但转译器会包含它们。

在每种语言中,含义都一样:创建一个变量,给它一个名字,存入一个值。

数字——整数与浮点数 ​

Auto 有两种数值类型:int 用于整数,float 用于浮点数。编译器根据字面量值决定使用哪种。

auto
var age = 25          // int —— 没有小数点
var temperature = 36.6  // float —— 有小数点

如果数字有小数点,就是 float。如果没有,就是 int。就这么简单。

算术运算符 ​

Auto 支持你期望的标准算术运算符:

运算符含义示例结果
+加法5 + 38
-减法10 - 46
*乘法6 * 742
/除法15 / 43
%取余17 % 52

注意两个整数相除会得到整数结果——15 / 4 是 3,而不是 3.75。小数部分被截断。如果你需要浮点结果,至少有一个操作数必须是浮点数:

auto
var precise = 15.0 / 4   // 3.75

代码清单 2-2 展示了所有算术运算符的实际使用。

整数与浮点数的算术运算

转译输出中有几点值得注意:

  • Python 使用 // 进行整数除法,而不是 /。当两个操作数都是整数时,a2p 转译器会将 Auto 的 / 转换为 Python 的 //。
  • TypeScript 将除法包装在 Math.trunc() 中以确保整数截断,因为 JavaScript 的 / 总是产生浮点数。
  • C 和 Rust 在两个操作数都是整数时自然执行整数除法,所以不需要特殊处理。

字符串——字面量与拼接 ​

字符串 是字符的序列。在 Auto 中,字符串字面量写在双引号内:

auto
var greeting = "Hello, world!"

Auto 中的字符串一旦创建就不可变。你可以用 + 运算符将现有字符串组合成新字符串:

auto
var first = "Hello"
var second = "Auto"
var combined = first + ", " + second + "!"

Auto 还支持多行字符串——只需在引号内包含实际的换行:

auto
var multi = "This is a
multiline string"

换行符会保留在字符串的值中。

字符串字面量与拼接

看看每种目标语言如何处理字符串拼接:

  • Rust 使用 format!() 进行高效的字符串构建——转译器避免了在 String 上重复使用 + 操作。
  • Python 直接支持字符串的 + 操作,并使用三重引号表示多行字符串。
  • C 使用 snprintf() 写入缓冲区——转译器在编译时计算所需大小。
  • TypeScript 使用模板字面量(反引号)表示多行字符串,用 + 进行拼接。

布尔值 ​

布尔值只有两个可能的值:true 和 false。布尔值是程序中所有决策的基础。

auto
var is_active = true
var is_finished = false

Auto 提供三个逻辑运算符来操作布尔值:

运算符含义示例结果
&&与true && falsefalse
``或
!非!truefalse

这些运算符的行为完全符合逻辑预期:

  • && 仅当两边都为 true 时才为 true。
  • || 当至少一边为 true 时就为 true。
  • ! 翻转值:!true 变成 false,!false 变成 true。
布尔值与逻辑运算符

Python 转译器将 Auto 的符号运算符转换为 Python 的关键字等效形式:&& 变成 and,|| 变成 or,! 变成 not。Python 还使用 True 和 False(首字母大写)而不是 true 和 false。

C 通过 <stdbool.h> 支持布尔类型,但 printf 没有布尔值的格式说明符。转译器使用三元运算符将布尔值打印为字符串 "true" 或 "false"。

比较运算符 ​

比较运算符比较两个值并返回布尔值。Auto 支持六种比较运算符:

运算符含义示例结果
==等于10 == 20false
!=不等于10 != 20true
<小于10 < 20true
>大于10 > 20false
<=小于或等于10 <= 10true
>=大于或等于10 >= 20false

这些运算符可以用于数字、字符串和布尔值。字符串比较按字典序进行。

比较运算符

注意 TypeScript 转译器将 == 转换为 ===,将 != 转换为 !==。TypeScript 的严格相等运算符避免了 JavaScript == 和 != 的类型强制转换陷阱,因此转译器始终使用严格版本。

变量遮蔽 ​

Auto 允许你在同一作用域内声明一个与之前变量同名的新变量。这叫做 变量遮蔽(shadowing)。新变量 遮蔽 了旧变量——从那时起,这个名字指向新变量。

auto
var x = 5
var x = x + 1    // x 现在是 6

这与赋值不同。你不是在改变旧变量——而是在创建一个碰巧同名的新变量。因为它是新变量,你甚至可以改变类型:

auto
var x = 5          // x 是 int
var x = "now a string"  // x 现在是 string

这种改变类型的遮蔽在 Auto 中完全合法。在 Python 和 Rust(使用 let)中也同样合法。C 和 TypeScript 需要变通方案,转译器会自动处理。

用相同名称遮蔽变量

C 的输出最为引人注目。因为 C 是静态类型的,不支持用不同类型遮蔽变量,a2c 转译器生成了一个 标签联合体(tagged union)——一个同时携带类型标签和值的结构体。这是真实 C 程序中使用的真实技术,转译器会自动应用它,让你不必操心。

TypeScript 的输出使用联合类型(number | string)来表示可以持有任一类型的变量。

总结 ​

在本章中,你学习了在 Auto 中处理数据的基础知识:

  • 变量 使用 var 声明,是可变的。编译器会推断类型——你不需要类型标注。
  • 数字 有两种:int 用于整数,float 用于小数。算术运算符(+、-、*、/、%)的行为符合预期。
  • 字符串 使用双引号和 + 运算符进行拼接。多行字符串通过实际的换行来编写。
  • 布尔值 为 true 或 false。逻辑运算符 &&、|| 和 ! 用于组合布尔值。
  • 比较运算符(==、!=、<、>、<=、>=)比较值并返回布尔值。
  • 变量遮蔽 允许你重用变量名,甚至可以使用不同的类型。每个 var 都创建一个新变量。

现在你已经掌握了命名和转换数据的词汇。在下一章中,我们将通过编写函数——每个程序的可复用构建块——来运用这些词汇。

基于 MIT 许可发布。