做算术
在本章中,您将学习:
- 如何计算整数之间或浮点数之间的算术运算
- 如何编写包含多个语句的程序
- 如何在多行中打印字符串
添加整数
让我们看看如何计算两个整数的和; 例如,80和34.将以下行作为main函数的大括号的唯一内容:
print!("The sum is {}.", 80 + 34);
执行将打印:“总和是114.”。
print宏的第二个参数是表达式80 + 34。
编译器肯定不会在可执行文件中以十进制格式存储这些数字。 如果关闭编译优化,则编译器=只转换两个数字n二进制格式并将可执行的二进制数和加法操作存储到可执行文件中。 但是,如果编译优化已启用,则编译器会意识到此表达式仅包含常量值,直接计算该表达式,获得整数114,并以二进制格式将此数字存储到可执行程序中。 在这两种情况下,在运行时,这样的数字被格式化为三字符十进制字符串114,然后文字字符串的占位符{}被这样的字符串替换。 最后,当然,结果字符串将打印到控制台
请注意字符串“总和是114”。 已经由程序产生的; 它不存在于源代码中; 所以它仍然是一个字符串,但不是文字字符串。
类似地,双字符序列80直接在源代码中表示整数,因此它被称为“文字整数”。 对于两个字符34也是如此。相反,以二进制格式保存到可执行文件中并在运行时加载到内存中的整数114不是文字整数,因为它不出现在源代码中。
它也允许写:
print!("{} + {} = {}", 34, 80, 80 + 34);
执行将打印“34 + 80 = 114”。
在这种情况下,宏的第二个参数将放在存在第一个占位符的位置,第三个参数存在第二个占位符,第四个参数存在第三个占位符。
您可以为“print”宏指定数百个参数,只要第一个参数之后的参数与第一个参数中的占位符“{}”一样多。
整数之间的其他操作
可以使用C语言的所有整数算术运算符。 例如:
print!("{}", (23 - 6) % 5 + 20 * 30 / (3 + 4));
这将打印87。
让我们看看为什么。
这样的公式由Rust编译器完全按照C编译器的方式进行评估。
首先,评估括号23-6和3 + 4中的操作,分别获得17和7。
在这一点上,我们的表达已成为17%5 + 20 * 30/7。
然后,评估乘法和除法运算,因为它们优先于加法和减法,并且对于相同优先级的运算,它们按从左到右的顺序进行计算。 17%5是“整数除法的余数”运算,结果为2,即运算的剩余部分17/5。表达式20 * 30在下一个除法之前进行求值,就像它在 它的左边。 此时,我们的表达已成为2 + 600/7。
然后,执行整数除法(截断)600/7,并且我们的表达式变为2 + 85。
最后,计算总和,结果以十进制表示法格式化,占位符由格式化的数字替换,并打印结果字符串。
这些算术运算始终在整数二进制数上执行,获得整数二进制数,只有在用于替换占位符时,结果才会转换为十进制格式。
通常,编译器生成机器语言指令,然后在程序运行时执行; 但是,Rust编译器是高度优化的,因此它尝试在编译时直接评估可以使用源代码中的可用信息进行评估的表达式。 我们的表达式只由字面整数组成,因此整个表达式将在编译时进行评估,在可执行程序中仅存储要打印的结果。 但是,从概念上讲,我们可以认为计算是在运行时执行的。
浮点运算
让我们看看如何用小数部分计算两个数之间的和
例如,80.3和34.9。
将语句替换为:
print!("The sum is {}", 80.3 + 34.8);
运行将打印总和为115.1。
现在用第二个数字替换字符“8”和“9”,获得:
print!("The sum is {}", 80.3 + 34.9);
运行将打印总和为115.19999999999999。
这将使那些期望115.2的人感到惊讶。
这种现象也发生在许多其他编程语言中,这是因为Rust几乎与每种编程语言一样,使用“浮点”格式执行涉及非整数的计算。 但是在这里我们不再对待这种格式了。
还可以评估包含浮点数的表达式:
print!("{}", (23. - 6.) % 5. + 20. * 30. / (3. + 4.));
这将打印87.71428571428571。
让我们看看为什么。
通过在文字数字后面加一个点,它将转换为具有相同值的文字浮点数。 优先级规则与整数运算相同,但除法有不同的结果。
让我们看看如何执行表达式的评估。
23.- 6.和3. + 4的评估类似于整数的评估。
通过评估17.%5.,2获得,类似于整数。 对于浮点数,这种运算符在C语言中不存在,并且它对应于C语言的表达式fmod(17。,5。)。
通过评估“20. * 30”,获得600,类似于整数。
通过评估“600./ 7.”,获得浮点数,其不能以二进制表示法或十进制表示法精确表示。 在内部,生成二进制格式的近似表示; 如果你要求Rust将这个数字转换为十进制格式的近似表示,你将获得字符串85.71428571428571。
最后,将值2添加到这样的二进制数,获得另一个无法准确表示的值,以上面显示的方式打印。
请注意,与C语言不同,在Rust中,您不能简单地混合整数和浮点数。 以下语句生成编译错误:
print!("{}", 2.7 + 1);
使其有效的一种方法是添加一个点:
print!("{}", 2.7 + 1.);
然而,这一个是仅语法限制,而不是可操作的限制,因为无论如何机器代码都不能将整数和浮点数相加,而不是在将两个操作数之一转换为另一个操作数的类型之前。 AC编译器遇到表达式2.7 + 1时,隐式发出机器语言指令,将整数1转换为浮点数,或者更好,1为常量,在编译时将其转换为浮点数。 在Rust中,这种转换必须是明确的。
最后,关于“%”运算符的说明。 这通常被错误地命名为“模数”(或“模数”)运算符。 好吧,它应该更好地命名为“余数”运算符,因为数学模运算符对负数具有不同的行为。 “%”运算符在Rust语言中表现如下:
print!("{} {}", -12 % 10, -1.2 % 1.);
This will print "-2 -0.19999999999999996".
陈述的序列
由于主函数体,写:
print!("{} + ", 80);
print!("{} =", 34);
print!(" {}", 80 + 34);
这将打印80 + 34 = 114。
该程序现在包含三个语句,每个语句都以“;”结尾 字符。 这些陈述按出现的顺序执行。
如果主要功能的主体将成为
print!("{} + ",80);print!("{} = ",34);
print ! ( "{}" ,
80 + 34 ) ;
它的结果不会改变。 实际上,忽略了额外的空格(空格,制表符和换行符)。
但是,Rust程序员有以下习惯:
- 在函数内用四个空格缩进行;
- 避免在语句中添加多个连续空格;
- 避免超过80列,可能在多行上拆分长语句。
打断文字串
如前所述,为了避免代码行太长,你可以在语法符号之间的任何点断开它们,比如C语言; 但是,打破文字字符串的语法是不同的。 此代码是非法的:
println!("{}", "This"
"is not allowed");
实际上,在Rust中你不能简单地并置文字字符串,就像在C中一样。
但是,您可以在一行中开始一个文字字符串,然后在下面几行结束。 例如,这是一个有效的程序:
fn main() {
println!("{}", "These
are
three lines");
}
输出:
These
are
three lines
如您所见,文字字符串包含源文件中字符串开头和结尾之间的所有字符,包括换行符和行前导空格。
也许这就是你想要的,但你可以做一些不同的事情:
fn main() {
println!("{}", "This \
is \
just one line");
}
它输出:
This is just one line
通过在文字字符串中添加反斜杠字符(“\”),就在行尾之前,结果字符串既不包含该行尾字符,也不包含以下空格; 因此,省略了下一行的前导空格。 鉴于我们至少需要一个空白,我们在反斜杠之前插入了这样一个空白。
最后,如果我们想要一个包含多个结果行的单个文字字符串,而没有前导空格,我们可以这样写:
fn main() {
println!("{}", "These
are
three lines");
}
或
fn main() {
println!("{}", "These\n\
are\n\
three lines");
}
二者都输出:
These
are
three lines
第一种解决方案的缺点是不遵守压痕惯例,因此通常第二种解决方案是优选的。 在这样的解决方案中,在行的末尾存在序列“\ n”,其被编码为换行符序列,然后是另一个反斜杠以从字符串中排除源代码换行符和以下空格。