本篇介绍运算符与表达式
先看看文档里的描述
表达式是运算符和操作数构成的序列。
而对于运算符文档中并没有给出一个统一的定义而是给出了几种运算符类型
所以只能在网上搜索一下了并结合例子来看了
在百度百科我找到了运算符的定义:
用于执行程序代码运算,会针对一个以上操作数项目来进行运算。
结合文档中的例子
虽然表达式与运算符的定义理解起来有些晦涩,但是实际上他们是很简单的
举个例子马上就能理解
int i = 0;
其中 i 和 0 就是数据, = 就是运算符
而这一行代码就是一个表达式
这样的表达式在我们写代码的时候经常用到
文档中告诉我们运算符有以下类型
- 算术运算符:将对数值操作数执行算术运算
- 比较运算符:将比较数值操作数
- 布尔逻辑运算符:将对 bool 操作数执行逻辑运算
- 位运算符和移位运算符:将对整数类型的操作数执行位运算或移位运算
- 相等运算符:将检查其操作数是否相等
其中位运算符和移位运算符在实际使用中,相对少见一些
其他运算符我们都很常用
文档中指出:
在包含多个运算符的表达式中,先按优先级较高的运算符计算,再按优先级较低的运算符计算。
那么运算符的优先级是什么样的呢?
运算符 | 类别或名称 |
---|---|
x.y、f(x)、a[i]、x?.y、x?[y]、x++、x–、x!、new、typeof、checked、unchecked、default、nameof、delegate、sizeof、stackalloc、x->y | 主要 |
+x、-x、x、~x、++x、–x、^x、(T)x、await、&&x、*x、true 和 false | 一元 |
x…y | 范围 |
switch、with | switch 和with 表达式 |
x * y、x / y、x % y | 乘法 |
x + y、x – y | 加法 |
x << y、x >> y | 移位 |
x < y、x > y、x <= y、x >= y、is、as | 关系和类型测试 |
x == y、x != y | 相等 |
x & y | 布尔逻辑 AND 或按位逻辑 AND |
x ^ y | 布尔逻辑 XOR 或按位逻辑 XOR |
x | y |
x && y | 条件“与” |
x || y | 条件“或” |
x ?? y | Null 合并运算符 |
c ? t : f | 条件运算符 |
x = y、x += y、x -= y、x *= y、x /= y、x %= y、x &= y、x |= y、x ^= y、x <<= y、x >>= y、x ??= y、=> | 赋值和 lambda 声明 |
当运算符的优先级相同,运算符的结合性决定了运算的执行顺序:
运算符与数学中的运算符类似
当我们需要改变计算顺序时
可以为需要优先计算的内容加上()
int a = 13 / 5 / 2;
int b = 13 / (5 / 2);
Console.WriteLine($"a = {a}, b = {b}"); // output: a = 1, b = 6
文档中指出
通常可以重载这些运算符,也就是说,可以为用户定义类型的操作数指定运算符行为。
例如Unity中的Vector3就是靠运算符重载实现的两个向量相加减
运算符重载的方式为
运算符表示法 | 函数表示法 |
---|---|
op x | operator op(x) |
x op | operator op(x) |
x op y | operator op(x,y) |
例如:
public struct Money
{
public int value;
public static int operator *(Money x, Money y)
{
return x.value + y.value;
}
}
这样就实现了一个*
的运算符重载
需要注意的是,运算符重载一定要写在你定义的数据结构(类、结构体)内部,也就是说
public struct Money{
public int value;
}
public static int operator *(Money x, Money y)
{
return x.value + y.value;
}
这样的定义方式是错误的
常用表达式类型包括
一颗树中,所有叶节点的元素值都是数字,而所有父节点(即有子节点的节点)的元素值都是运算符。
因为Unity的IL2CPP不支持表达式树,所以我基本没有用过表达式树,就不多介绍了。