逻辑表达式
本课介绍了一种用于条件语句的特定类型表达式。
表达式
程序实际执行的工作是通过表达式完成的。任何能够产生值或产生副作用的程序部分都称为表达式。这个定义非常宽泛,因为即使是常量值如 42 和字符串如 "hello" 也属于表达式,因为它们分别产生常量值 42 和 "hello"。
注意: 像上面这样的常量值可以独立于变量使用。
像 writeln 这样的函数也是表达式,因为它们也会为输出流产生值。在 writeln 的情况下,输出流通过在其上放置字符而被修改。我们之前编写的程序中的另一个例子是赋值操作,它同样会修改其左侧的变量。
表达式可以作为其他表达式的一部分。这使得我们可以从简单的表达式组合出更复杂的表达式。例如,假设存在一个名为 currentTemperature 的函数,用于返回当前气温值,那么该函数产生的值可直接用于 writeln 表达式中:
1writeln("现在气温是 ", currentTemperature(), " 度。");
这一行代码包含四个表达式:
- "现在气温是 "
currentTemperature()- " 度。"
- 使用其他三个表达式的
writeln()表达式。
在本课中,我们将重点讲解条件语句中使用的特定类型表达式。
在继续深入之前,让我们重新回顾一下在给变量赋值一课中讨论过的赋值运算符,这次特别强调其左右两侧的两个表达式:赋值运算符 = 将右侧表达式的值赋给左侧表达式(例如变量)。
1temperature = 23 // temperature 的值变为 23
逻辑表达式
逻辑表达式用于布尔运算。它们使计算机程序能够做出决策,例如“如果答案是‘是’,我就保存文件”。
逻辑表达式只能有两个值之一:
- false,表示假
- true,表示真
让我们看几个使用 writeln 表达式的例子。如果某行末尾打印了 true,表示该行输出的内容为 true。类似地,false 表示该行内容为假。例如,如果程序的输出如下:
1有咖啡:true
则意味着“有咖啡”。同样地,
1有咖啡:false
则意味着“没有咖啡”。
注意: 我使用“... 是 ...: false”这种结构来表示“不是”或“为假”。
逻辑表达式广泛应用于条件语句、循环和函数参数中。理解它们的工作原理至关重要。幸运的是,逻辑表达式很容易解释和使用。
逻辑运算符
逻辑表达式中使用的逻辑运算符包括:
== 运算符
== 运算符回答的问题是:“是否相等?” 它比较其左右两侧的两个表达式,若两者相等则产生 true,否则产生 false。根据定义,== 产生的值是一个逻辑表达式。
举个例子,假设我们有以下两个变量:
1int daysInWeek = 7; 2int monthsInYear = 12;
下面的代码包含两个使用这些值的逻辑表达式:
1import std.stdio; 2 3int main() { 4 int daysInWeek = 7; 5 int monthsInYear = 12; 6 7 writeln(daysInWeek == 7); // true 8 writeln(monthsInYear == 11); // false 9 return 0; 10}
!= 运算符
!= 运算符回答的问题是:“是否不相等?” 它比较两侧的表达式,并产生与 == 相反的结果。
1import std.stdio; 2 3int main() { 4 int daysInWeek = 7; 5 int monthsInYear = 12; 6 7 writeln(daysInWeek != 7); // false 8 writeln(daysInWeek == 7); // true(与 != 相反) 9 writeln(monthsInYear != 11); // true 10 return 0; 11}
|| 运算符
|| 运算符表示“或”,只要任一逻辑表达式为真,就产生 true。
如果左侧表达式的值为真,则直接产生 true,而无需查看右侧表达式。如果左侧为假,则结果等于右侧表达式的值。该运算符类似于英语中的“或”:只要左边、右边或两者都为真,结果就是真。
下表列出了该运算符两边所有可能的取值及其结果:

1import std.stdio; 2 3void main() { 4 // false 表示“无”,true 表示“有” 5 6 bool existsCoffee = false; 7 bool existsTea = true; 8 9 writeln("有热饮:", existsCoffee || existsTea); 10}
由于两个表达式中至少有一个为真,上述逻辑表达式的结果为真。
&& 运算符
&& 运算符表示“和”,只有当两个表达式都为真时,才产生 true。
如果左侧表达式的值为假,则直接产生 false,而不去检查右侧表达式。如果左侧为真,则结果等于右侧表达式的值。该运算符类似于英语中的“和”:只有当左值和右值都为真时,结果才是真。

注意:
||和&&运算符可能不会评估右侧表达式,这种特性称为短路行为。我们将在后续章节中学习的三元运算符?:也有类似特性,它从不评估其三个表达式中的一个。其余所有运算符都会评估并使用其所有表达式。
^ 运算符
^ 运算符回答的问题是:“只有一个为真,但不能两个都为真?” 该运算符仅在其中一个表达式为真时产生 true,如果两个都为真或都为假,则产生 false。
注意: 实际上,这个运算符并非逻辑运算符,而是算术运算符。它仅在两个表达式均为布尔类型时才表现出逻辑运算的行为。

例如,当用户的朋友中只有一人到场时,他们才会玩国际象棋,这种逻辑可以这样编码:
1import std.stdio; 2 3int main() { 4 bool jimShowedUp = false; 5 bool bobShowedUp = true; 6 7 writeln("我会下棋:", jimShowedUp ^ bobShowedUp); 8 return 0; 9}
< 运算符
< 运算符回答的问题是:“是否小于?”(或“在排序顺序中是否靠前?”)
1import std.stdio; 2 3int main() { 4 int theirScore = 3; 5 int ourScore = 4; 6 7 writeln("我们赢了:", theirScore < ourScore); 8 return 0; 9}
> 运算符
> 运算符回答的问题是:“是否大于?”(或“在排序顺序中是否靠后?”)
1import std.stdio; 2 3int main() { 4 int theirScore = 3; 5 int ourScore = 4; 6 7 writeln("他们赢了:", theirScore > ourScore); 8 return 0; 9}
<= 运算符
<= 运算符回答的问题是:“是否小于或等于?”(或“在排序顺序中是否靠前或相同?”)该运算符是 > 运算符的相反。
1import std.stdio; 2 3int main() { 4 int theirScore = 3; 5 int ourScore = 4; 6 7 writeln("我们没有输:", theirScore <= ourScore); 8 return 0; 9}
>= 运算符
>= 运算符回答的问题是:“是否大于或等于?”(或“在排序顺序中是否靠后或相同?”)该运算符是 < 运算符的相反。
1import std.stdio; 2 3int main() { 4 int theirScore = 4; 5 int ourScore = 4; 6 7 writeln("我们没有赢:", theirScore >= ourScore); 8 return 0; 9}
! 运算符
! 运算符表示“相反”。与其他逻辑运算符不同,它只接受一个表达式,当该表达式为假时产生 true,当该表达式为真时产生 false。
1import std.stdio; 2 3int main() { 4 bool existsBicycle = true; 5 6 writeln("我将步行:", !existsBicycle); 7 return 0; 8}
表达式的分组
可以通过使用括号来指定表达式的求值顺序。当括号内的表达式出现在更复杂的表达式中时,括号内的表达式会先被求值,然后才能用于外层表达式。例如,表达式“如果有咖啡或茶,并且还有饼干或司康饼;那么我就开心”可以这样编写:
1import std.stdio; 2 3int main() { 4 bool existsCoffee = false; 5 bool existsTea = true; 6 bool existsCookie = false; 7 bool existsScone = true; 8 9 writeln("我开心:", 10 (existsCoffee || existsTea) && (existsCookie || existsScone)); 11 return 0; 12}
如果未对子表达式进行括号分组,表达式将按照 D 语言的运算符优先级规则进行求值(该规则继承自 C 语言)。由于在这些规则中 && 的优先级高于 ||,因此不加括号地书写表达式将无法按预期方式求值:
1import std.stdio; 2 3int main() { 4 bool existsCoffee = false; 5 bool existsTea = true; 6 bool existsCookie = false; 7 bool existsScone = true; 8 9 writeln("我开心:", 10 existsCoffee || existsTea && existsCookie || existsScone); 11 return 0; 12}
此时 && 运算符会优先计算,整个表达式等价于以下形式:
1writeln("我开心:", 2existsCoffee || (existsTea && existsCookie) || existsScone);
这具有完全不同的含义:“如果有咖啡,或者有茶和饼干,或者有司康饼;那么我就开心”。
1import std.stdio; 2 3int main() { 4 bool existsCoffee = false; 5 bool existsTea = true; 6 bool existsCookie = false; 7 bool existsScone = true; 8 9 writeln("我开心:", 10 existsCoffee || (existsTea && existsCookie) || existsScone); 11 return 0; 12}
读取布尔输入
上述所有布尔值都会自动显示为 false 或 true。同时,readf() 会自动将字符串 false 和 true 转换为布尔值 false 和 true。它接受大小写字母的任意组合。例如,'False' 和 'FALSE' 会被转换为 false,而 'True' 和 'TRUE' 会被转换为 true。
在下一课中,你将遇到一个与逻辑表达式相关的编程挑战。