编程是一种思维方式
本书的第一个目标是教你如何用 Auto 编程。 但学习编程意味着学习一种新的思维方式,所以第二个目标是帮助你像计算机科学家一样思考。 这种思维方式融合了数学、工程学和自然科学的最佳特点。 像数学家一样,计算机科学家使用形式化语言来表达思想——特别是计算。 像工程师一样,他们设计事物,将组件组装成系统并评估各种方案的权衡。 像科学家一样,他们观察复杂系统的行为,提出假设并验证预测。
我们将从最基本的编程元素开始,逐步深入。 在本章中,我们将了解 Auto 如何表示数字、字母和单词。 你还将学习执行算术运算。
你还将开始学习编程词汇,包括运算符、表达式、值和类型等术语。 这些词汇很重要——你需要它们来理解本书的其余内容、与其他程序员交流,以及有效地使用工具。
算术运算符
算术运算符是表示算术计算的符号。 例如,加号 + 执行加法。
30 + 12减号 - 执行减法。
43 - 1星号 * 执行乘法。
6 * 7正斜杠 / 执行除法。
84 / 2注意除法的结果是 42.0 而不是 42。 这是因为 Auto 中有两种数字类型:
整数(integer),表示没有小数部分的数字,以及
浮点数(floating-point number),表示整数和带小数点的数字。
如果你对两个整数进行加法、减法或乘法,结果仍然是整数。 但如果你对两个整数进行除法,结果会是浮点数。
Auto 还提供了另一个运算符 //,执行整数除法(也称为"向下取整除法")。 整数除法的结果始终是整数——它总是向下取整。
84 // 2 // 结果是 42
85 // 2 // 结果是 42(向下取整,不是 42.5)取模运算符 % 计算整数除法的余数。
85 % 2 // 结果是 1最后,运算符 ** 执行幂运算,即将一个数字提升到某个幂次。
7 ** 2 // 结果是 49
2 ** 10 // 结果是 1024Python 程序员注意:
Auto 与 Python 使用相同的算术运算符:
+、-、*、/、//、%和**。这些运算符通过a2p转译时不会有任何变化。
表达式
由运算符和数字组成的集合称为表达式。 表达式可以包含任意数量的运算符和数字。 例如,下面是一个包含两个运算符的表达式。
6 + 6 ** 2注意幂运算先于加法执行。 Auto 遵循标准的运算顺序:幂运算先于乘法和除法,乘法和除法先于加法和减法。
在下面的例子中,乘法先于加法执行。
12 + 5 * 6如果你想先执行加法,可以使用括号。
(12 + 5) * 6每个表达式都有一个值。 例如,表达式 6 * 7 的值是 42。
工作原理
本程序演示了 Auto 中的所有七种算术运算符。前四行展示了四种基本运算:加法(+)、减法(-)、乘法(*)和除法(/)。注意 84 / 2 产生 42.0(浮点数),而不是 42(整数)——这是因为常规除法总是返回浮点数。
整数除法运算符 // 总是向下取整。所以 85 // 2 是 42,而不是 42.5。取模运算符 % 返回余数,所以 85 % 2 是 1。幂运算使用 **:7 ** 2 是 49,2 ** 10 是 1024。
最后三行展示了运算顺序。在 6 + 6 ** 2 中,幂运算先执行,所以这是 6 + 36 = 42。在 12 + 5 * 6 中,乘法先执行,所以这是 12 + 30 = 42。使用括号时,(12 + 5) * 6,加法先执行:17 * 6 = 102。
算术函数
除了算术运算符之外,Auto 还提供了处理数字的内置函数。
round 函数接收一个浮点数并将其四舍五入到最接近的整数。
42.4.round() // 结果是 42
42.6.round() // 结果是 43abs 函数计算一个数字的绝对值。
42.abs() // 结果是 42
(-42).abs() // 结果是 42Python 程序员注意:
在 Python 中,你这样调用:
round(42.4)和abs(-42)。在 Auto 中,方法直接在值上调用:42.4.round()和(-42).abs()。a2p转译器会将这些转换为等效的 Python 函数调用。
当我们像这样使用函数时,我们说我们在调用函数。 调用函数的表达式称为函数调用。
字符串
除了数字,Auto 还可以表示字母序列,称为字符串(string),因为这些字母像项链上的珠子一样串在一起。 要写字符串,我们将字符序列放在引号内。
"Hello"
'world'单引号和双引号都可以使用。双引号方便在字符串中包含撇号。
"it's a small world."字符串还可以包含空格、标点符号和数字。
"Well, "+ 运算符可以用于字符串;它将两个字符串连接成一个字符串,这称为拼接(concatenation)。
"Well, " + "it's a small " + "world."* 运算符也可以用于字符串;它将一个字符串复制多次并拼接起来。
"Spam, " * 4Auto 提供了 len 函数来计算字符串的长度。
"Spam".len() // 结果是 4注意 len 计算的是引号之间的字符数,不包括引号本身。
Auto 支持f-string(格式化字符串)。语法在字符串内的变量名前使用 $ 前缀。
let name = "Alice"
let age = 30
print(f"My name is $name and I am $age years old.")Python 程序员注意:
在 Python 中,f-string 使用
{name}语法。在 Auto 中,相同的功能使用$name语法。a2p转译器会自动将f"$name"转换为f"{name}"。
工作原理
我们首先打印了使用单引号和双引号的字符串。双引号特别适用于字符串中包含撇号的情况("it's a small world.")。
字符串拼接使用 + 运算符将三个字符串首尾相连。* 运算符重复字符串:"Spam, " * 4 产生 "Spam, Spam, Spam, Spam, "。.len() 方法返回字符串中的字符数——"Spam" 有 4 个字符。
f-string f"My name is $name and I am $age years old." 使用 $name 和 $age 来插值变量。在 Python 输出中,这些会变成 {name} 和 {age}。
值和类型
到目前为止我们见过三种值:
2是整数,42.0是浮点数,以及"Hello"是字符串。
一种值的类别称为类型(type)。 每个值都有一个类型——或者我们有时说它"属于"某个类型。
我们目前见过的类型有:
int表示整数(如42、-7、1_000_000等整数)float表示浮点数(如3.14、0.5等带小数点的数字)str表示字符串(如"Hello, World!"等字符序列)bool表示布尔值(true或false)
类型名 int、float 和 str 也可以用来将值从一种类型转换为另一种类型。 例如,int 可以接收一个浮点数并将其转换为整数(总是向下取整)。
42.9.int() // 结果是 42float 可以将整数转换为浮点数。
42.float() // 结果是 42.0现在,有一个容易混淆的地方。 如果你把一串数字放在引号里会怎样?
"126"它看起来像数字,但实际上是字符串。 如果你尝试像数字一样使用它,可能会得到错误。 如果你有一个包含数字的字符串,可以使用 int 将其转换为整数。
int("126") / 3 // 结果是 42.0如果你有一个包含数字和小数点的字符串,可以使用 float 来转换。
float("12.6") // 结果是 12.6当你书写较大的整数时,可以使用下划线使其更易读。
1_000_000 // 一百万Python 程序员注意:
在 Python 中,类型转换是函数调用:
int(42.9)、float(42)、int("126")。在 Auto 中,这些是值上的方法调用:42.9.int()、42.float()、int("126")。a2p转译器会将所有这些转换为标准的 Python 函数调用形式。Auto 使用小写的
true和false表示布尔值,a2p会将其转换为 Python 的True和False。
工作原理
第一组调用展示了内置函数:42.4.round() 返回 42,42.6.round() 返回 43。abs 函数返回绝对值——(-42).abs() 返回 42。
类型转换部分展示了如何在类型之间进行转换。42.9.int() 通过向下取整(截断)将浮点数转换为整数,结果为 42。42.float() 将整数转换为浮点数,结果为 42.0。
将字符串转换为数字在接收文本形式的数字输入时非常必要。int("126") 将字符串 "126" 转为整数 126。一旦转换完成,就可以用于算术运算:int("126") / 3 产生 42.0。
最后,1_000_000 展示了如何在数字字面量中使用下划线来提高可读性。Auto(和 Python)在计算数字时会忽略这些下划线。
形式语言与自然语言
自然语言是人们说的语言,如英语、西班牙语和法语。 它们不是由人设计的;它们是自然演变的。
形式语言是人们为特定应用而设计的语言。 例如,数学家使用的符号是一种形式语言,特别适合表示数字和符号之间的关系。 同样,编程语言是为了表达计算而设计的形式语言。
虽然形式语言和自然语言有一些共同特征,但存在重要差异:
歧义性:自然语言充满歧义,人们通过使用上下文线索和其他信息来处理歧义。 形式语言被设计为几乎或完全无歧义,这意味着任何程序无论在什么上下文中都只有一个含义。
冗余性:为了弥补歧义并减少误解,自然语言使用冗余。 因此,它们往往比较冗长。 形式语言的冗余较少,更加简洁。
字面性:自然语言充满惯用语和比喻。 形式语言字面意思就是其含义。
因为我们都是在自然语言中长大的,所以有时很难适应形式语言。 形式语言比自然语言更密集,所以阅读它们需要更长时间。 此外,结构很重要,所以并不总是从上到下、从左到右阅读最好。 最后,细节很重要。 在自然语言中可以忽略的拼写和标点小错误,在形式语言中可能会造成很大的差异。
调试
程序员会犯错误。 出于有趣的原因,编程错误被称为bug(缺陷),而追踪和修复它们的过程称为调试(debugging)。
你将遇到三种主要的错误:
语法错误(syntax error):程序的结构有问题。 例如,在函数调用中省略括号,或者使用反引号而不是引号来表示字符串。 编译器会在运行程序之前检测到语法错误。
运行时错误(runtime error):程序的语法是正确的,但在运行过程中出了问题。 例如,尝试将字符串除以数字会产生运行时错误。
逻辑错误(也称为语义错误):程序运行时没有产生错误消息,但它没有按照你的预期工作。
编程,尤其是调试,有时会引起强烈的情绪反应。 如果你正在为一个困难的 bug 苦恼,你可能会感到愤怒、悲伤或尴尬。 提前做好应对这些反应的准备可能会有所帮助。 一种方法是把计算机看作一个员工——它有某些优势(如速度和精度),但也有特定的弱点(如缺乏同理心、无法把握全局)。
你的任务是成为一个好的管理者:找到方法利用其优势,缓解其弱点。 找到方法让你的情绪投入到问题中,而不让你的反应影响你的工作效率。
学习调试可能令人沮丧,但它是一项在编程之外的许多活动中都很有用的宝贵技能。
术语表
算术运算符: 一个符号,如 + 和 *,表示加法或乘法等算术运算。
整数: 表示没有小数部分的数字的类型。在 Auto 中,该类型为 int。
浮点数: 表示整数和带小数部分的数字的类型。在 Auto 中,该类型为 float。
整数除法: 运算符 //,将两个数字相除并向下取整为整数。
取模: 运算符 %,计算整数除法的余数。
幂运算: 运算符 **,将一个数字提升到某个幂次。
表达式: 变量、值和运算符的组合。
值: 整数、浮点数、字符串或布尔值——或者我们后面会看到的其他类型的值。
函数: 执行某种有用操作的命名语句序列。
函数调用: 运行函数的表达式。在 Auto 中,它由函数名后跟括号中的参数组成。
语法错误: 程序中的错误,使其无法被解析——因此无法运行。
运行时错误: 直到程序开始运行后才会出现的错误。
字符串: 表示字符序列的类型。在 Auto 中,该类型为 str。
拼接: 使用 + 运算符将两个字符串首尾相连。
类型: 值的类别。我们目前见过的类型有 int、float、str 和 bool。
操作数: 运算符所操作的值之一。
自然语言: 人们所说的自然演变而来的语言。
形式语言: 人们为特定目的(如表示数学思想或计算机程序)而设计的语言。所有编程语言都是形式语言。
缺陷(bug): 程序中的错误。
调试: 发现和纠正错误的过程。
练习
练习 1
当你学习一个新功能时,你应该亲自尝试并故意犯错。 这样你可以学到错误信息,当你再次看到它们时,就会知道它们的意思。
你可以使用减号来创建负数,如
-2。如果在数字前放一个加号会怎样?2++2呢?如果两个值之间没有运算符,如
4 2,会怎样?如果你调用函数时省略括号,如
42.4.round,会怎样?
练习 2
以下问题给你练习编写算术表达式的机会。
42 分 42 秒等于多少秒?
10 公里等于多少英里?提示:1 英里等于 1.61 公里。
如果你用 42 分 42 秒跑完 10 公里,你的平均配速是多少秒/英里?
你的平均配速是多少分多少秒/英里?
你的平均速度是多少英里/小时?
编写一个 Auto 程序来计算并打印答案。
练习 3
思考以下问题,在运行任何代码之前尝试回答:
765的类型是什么?2.718的类型是什么?"2 pi"的类型是什么?"126" + "3"的结果是什么?为什么不是"129"?int("126") + int("3")的结果是什么?
现在编写一个 Auto 程序来验证你的答案。