撰写了文章 更新于 2020-01-02 19:06:42
从C#开始的编程入门——运算与运算符
不知道有一直在看文章的朋友对前几篇尬爆的比喻和冷笑话感到腻烦没有。还有我也实在找不出合适的配图了。
我们来学习如何利用C#来当计算器。
算术运算符
计算机就该拿来计算。
这些代表具体运算方式的符号称为运算符。我们日常使用的加减乘除都有对应的符号。

%也是一个运算符,但是不是百分比的意思。求余运算符(Remainder Operator,亦称取模运算符,Modulus Operator)完成求余的操作。

结果是1
这些用于执行算术运算的运算符被称为算术运算符(Arithmetic Operator)。
思考:结果是多少
程序会输出多少?

答案是1和1.5。3和2都是整数,最终的结果也是整数,数学上虽然结果为1.5,但在这种情况下直接丢弃了小数部分,注意,是直接丢掉而不是四舍五入!但是在第二行里,3.0不是整型,2还是整型,这个时候会尝试把操作数像精度高的一边转换,2按照2.0计算,最终结果依然是double类型,输出1.5。有关隐式类型转换规则,参见Built-in numeric conversions - C# reference | Microsoft Docs
自增减运算符
两个连续的+或者-构成了自增减运算符(Increment/decrement Operator)。道理很简单。给操作数加上或者减去1。

怎么样,看上去很简单吧! 那么我要告诉你,自增减运算符有两种形式,前置和后置。 前置版本会在变量被使用之前进行增减,后置版本会在当前表达式中使用原值,计算完毕后再进行增减。
那么下面的代码段最终的输出是?

正确答案是:1,3,3。
其实如果要记住也很简单,放在前面先增减,后面就后增减,最直接的办法就是——避免使用。 自增减运算符其实是从C/C++沿袭下来的。围绕这个运算符其实牵扯出很多争议。大学里的计算机相关的考题时常会出现有关这类运算符的考题,令人头皮发麻。而运算符本身区分前置和后置也令初学者迷惑。很多语言直接剔除了这种运算符,比如Python和Swift就剔除了。有一个很显而易见的问题就是,你如果只是单纯想加一为什么不直接使用后面介绍的复合赋值呢?
表达式和语句
前面提到的,每个语句必须以分号结尾。也就是说分号结尾的就是语句。 这是一个赋值语句。
那么1+2算什么呢? 它们被称为表达式(expression)。简单来说,一系列操作数和运算符按照各自的语法组合在一起就构成了一个表达式,表达式还有一个特点就是,它是有值的。
似乎,表达式再加上一个分号结尾就成了一行语句?
但是在C#中,这是不完全正确的。C#中把由表达式和分号构成的语句称为表达式语句(Expression Statement)C#中只允许赋值、函数调用、new操作、自增减构成的表达式作为语句。所以单独的表达式很多时候是不能成为一行语句的。迄今为止我们学过的内容中,只有赋值和函数调用允许成为一行语句。除此之外,只打一个分号也是一行语句,这是空语句,它什么也不做。除此之外,还有一些没有分号的结构也是语句,我们在下一篇中介绍。
很多语言其实并没有这么严格的要求。表达式也可以直接写成一行语句,其实C#中不允许这样做的考虑在于,如果一个表达式执行完,它的结果没有赋值给某个变量或者被其他语句所使用,是没有什么意义的。
在C#中对于表达式和语句的更详细的介绍,参见C# Expressions - A tour of the C# language | Microsoft Docs和C# Statements - A tour of the C# language | Microsoft Docs。
true or false——逻辑运算
除了数值运算,计算机还能完成逻辑运算。简单来说,判断事物的正确与否。实际上这背后涉及到数理逻辑和布尔代数。但是我们可以简单地认为,这就是判断对错。布尔类型正是用来表示逻辑运算的结果。

猫很可爱。
克苏鲁很可爱。(对不起,个人看法)
猫和克苏鲁都很可爱?
&&被称为逻辑与(即AND)运算符,它的两个操作数都必须是布尔类型的表达式。只有当两者皆为true的时候,逻辑与运算的结果才为true。
如果有一个游戏,会员可以免费玩,但是如果你有钱也可以买着玩。对于能不能玩这个事情来说,就有如下的表达式。

||是逻辑或(即OR)运算符,两个操作数只要有一个为true的时候,结果即为true。需要注意的是,“或”的意思不是必须二选一,而是至少一个为true就行了,所有操作数都为true的时候结果仍然是true。道理很简单,就算你有会员可以免费玩,但你还是有钱任性想买,那也是可以的,反正你都可以玩。
飞行模式关闭的时候才能上网。

!代表非运算(NOT),很简单,结果是和操作数相反的。这是一个一元运算符。
位运算符
位运算符针对操作数按位进行操作。逻辑运算符和它们其实是类似的原理。
位运算符&、|和对应的逻辑运算符相比只有单个符号。

除此之外还有异或(XOR,exclusive or)运算符(^),只有两个位不同时,结果才是1。
取补码运算在二进制位上逻辑非是一个道理,它会求出操作数的补码,看起来在数学上是讲不通的,这涉及到数字在计算机中的表示方法的问题。
<<和>>分别是左移和右移运算符,会把左操作数向左或右移动n(有操作数)位。
这些运算符除了在处理特定问题时使用,相对来说不那么常用,我们具体用到再讲。更详细的介绍可以参见Bitwise operation - Wikipedia。
复合赋值

可以简写为

最终的值会赋值给左边的操作数。这样的操作被称为复合赋值(Compound Assignment)。C#中所有的二元算术运算符都可以进行复合赋值。
关系运算符
关系运算符和逻辑运算符一样,也返回true或false。 它们对应着数学符号的大于小于等等。>=和你想象的一样,是大于等于。

判断是否相等是两个等号==,切记不要和赋值的一个等号=搞混了!
那么不等于呢?回忆前面的逻辑非的感叹号

唯一的三目运算符
今天上班吗?

我个人认为这是很好理解的一个运算符,问号就像是在发问,这个表达式必须是布尔类型。冒号隔开的两个表达式分别对应前面的布尔类型表达式为true和false的时候。
很多语言都采用了这种形式的三目运算符(Tenary Operator,亦称三元运算符。unary是一元,binary是二元,二进制也是binary,tenary是三元。Arity就是所谓的“元”数,操作数的个数),但有些语言也有功能一样的运算符,但是有不同的风格。Python就是一个典型:true if condition else false。
运算顺序
小学学过,从左到右,先加减,后乘除,有括号先算括号。
编程也可以加括号,其功能和你想象的一样,改变运算顺序。

那么默认的运算顺序是什么呢?
针对运算符来说,有一个优先级(precedence)的概念,就是哪个运算符先计算,专业点来说,叫做求值(evaluate)。
大体上的原则是,先算术运算,再逻辑运算,最后赋值。这是符合一般直觉的,因为毕竟要把各种运算算好,然后判断结果的性质,最后把最终结果给某个变量。完整的优先级表参见C# operators - C# reference | Microsoft Docs
更重要的原则是,当你的表达式很复杂的时候,无论记不记得优先级都应当用括号对表达式进行分组整理,防止发生错误。
思考:结果是多少

结合性
结合性(associativity)听起来很神秘,但是加一个字你就明白了。明确地讲,赋值运算符=是右结合的,这就意味着是从右往左看的。也就是说,x=1是“把1给x”而不是“把x给1”。而加减乘除运算符都是从左往右看的,二元运算符都是从左往右看的。
试一下
结合所学的各种运算符,尝试做一些计算并输出。
其实C#里面还有很多运算符,包括调用函数的()其实也是运算符,不过常见的运算符就是这些了,具体的我们遇到时在细说。
下一篇里我们介绍程序的流程控制,让程序在不同的条件下执行不同的语句,让它更像真正的程序。
