持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情
Operator运算符,通常也称为“操作符”。
Dart中的运算符提供对数据操作和处理的能力,其中的算术运算符、逻辑运算符非常符合现实中的使用情况,其他不同的运算符则有着自己的操作逻辑。
下面是Dart中运算符描述【可先做了解】,其前后顺序表示了优先级(即多个操作符使用时,优先计算的顺序,使用()可以改变优先级)
| 描述 | 运算符 | ||
|---|---|---|---|
| 一元后缀 | 表达式++ 表达式-- () [] . ?. ! | ||
| 一元前缀 | -表达式 !表达式 ~表达式 ++表达式 --表达式 | ||
| 乘除法 | * / % ~/ | ||
| 加减法 | + - | ||
| 位运算 | << >> >>> | ||
| 二进制与 | & | ||
| 二进制异或 | ^ | ||
| 二进制或 | ` | ` | |
| 关系和类型测试 | >= > <= < as is is! | ||
| 相等判断 | == != | ||
| 逻辑与 | && | ||
| 逻辑或 | ` | ` | |
| 空判断 | ?? | ||
| 条件表达式 | _表达式 1_ ? _表达式 2_ : _表达式 3_ | ||
| 级联 | .. ?.. | ||
| 赋值 | = *= /= += -= &= ^= 等等…… |
算术运算符(Arithmetic operators)
算术运算
算术运算是最基础的数值计算,包括:
+Add-Subtract-expr减去,也称为负 (表达式的符号反转)*Multiply/Divide 返回double类型的相除的结果。~/返回相除的整数,即取商,大多数编程语言/会返回结果的整数。%取余(或取模),返回两个数相除的余数。
如下,算术运算符的使用:
int a = 10;
int b = 3;
print(a + b); // 13
print(a - b); // 7
print(a * b); // 30
print(a / b); // 3.3333333333333335
print(a ~/ b); // 3
print(a % b); // 1
精度问题
对于浮点数来说,会有精度损失的问题,通常按需要能满足精度要求即可(比如小数后几位)。
double a = 10.6;
double b = 3.3;
print(a + b); // 13.899999999999999
print(a - b); // 7.3
print(a * b); // 34.98
print(a / b); // 3.2121212121212124
print(a ~/ b); //3
print(a % b); // 0.7000000000000002
身高、体重、长度等一般保留两三位小数即可。对于金融场景下,需要非常高精度计算的时候,推荐使用decimal第三方库。
条件运算符(比较运算符,或Equality and relational operators)
比较运算符用于比较变量,其结果返回一个bool值。
==相等- `!= 不等
>大于<小于>=大于等于<=小于等于
如下,变量a、b比较运算:
int a = 5;
int b = 6;
print(a > b); // false
print(a < b); // true
print(a == b); // false
print(a != b); // true
print(a >= b); // false
print(a <= b); // true
逻辑运算符(Logical operators)
逻辑运算是对bool(真、假)的运算。有与-&& 、或-|| 、非-!三种。
&&—— 与运算,当两边都为true时,结果才为true。表示的是并且/同时。||—— 或运算,当两边有一个为true时,结果就为true。表示的是或者/满足其中一个。!—— 非或取反运算,对表达式的bool值取反。表示的是不是/非。
比如,对于游乐场的要求:
身高小于1.4,并且年龄小于16才能游玩,则可以如下表示:
int age = 16;
double height = 1.3;
if(age<16 && height<1.4){
print("允许游玩");
}
else{
print("不允许游玩");
}
// 不允许游玩
身高小于1.4,或年龄小于16才能游玩,则可以如下表示:
int age = 16;
double height = 1.3;
if(age<16 || height<1.4){
print("允许游玩");
}
else{
print("不允许游玩");
}
// 允许游玩
身高大于1.4或年龄大于16,不满足这个条件的就能游玩,则可以如下表示:
int age = 16;
double height = 1.3;
if (!(age > 16 || height > 1.4)) {
print("允许游玩");
} else {
print("不允许游玩");
}
// 允许游玩
逻辑运算符的“短路”特点:
&&或||两元逻辑运算符在计算时,如果左侧的表达式就能确定逻辑结果时,则不会对右侧的表达式进行取值计算。
&&左侧为false,结果必然为false(一假全假);||左侧为true,结果必然为true(一真全真)。由于短路策略,则不会进行右侧表达式多余的计算。
位运算符(Bitwise and shift operators)
位运算针对的是计算机中的二进制位进行的运算,它是计算机中一切数据运算的本质(逻辑运算、算术运算、比较运算等都要转换为位运算)。
位运算符包括:
&按位与|按位或^按位异或~expr按位取反(即将 “0” 变为 “1”,“1” 变为 “0”)<<位左移>>位右移>>>无符号右移
final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // Shift left
assert((value >> 4) == 0x02); // Shift right
assert((value >>> 4) == 0x02); // Unsigned shift right
assert((-value >> 4) == -0x03); // Shift right
assert((-value >>> 4) > 0); // Unsigned shift right
体会下按位计算的特点:
int类型在内存中占据 4 字节,每字节(byte)由 8 个二进制位(bit)表示。
65 、11 在计算机中以 32 个二进制位来记录:
十进制: 65
二进制: 0000 0000 0000 0000 0000 0000 0100 0001
十进制: 11
二进制: 0000 0000 0000 0000 0000 0000 0000 1011
&按位与
int a = 65;
int b = 11;
int c = a & b;
0000 0000 0000 0000 0000 0000 0100 0001 a = 65
& 0000 0000 0000 0000 0000 0000 0000 1011 b = 11
0000 0000 0000 0000 0000 0000 0000 0001 c = 1
|按位或
int a = 65;
int b = 11;
int c = a | b;
0000 0000 0000 0000 0000 0000 0100 0001 a = 65
| 0000 0000 0000 0000 0000 0000 0000 1011 b = 11
0000 0000 0000 0000 0000 0000 0100 1011 c = 75
~按位取反
int b = 11;
int c = ~b;
0000 0000 0000 0000 0000 0000 0000 1011 b = 11
~ 1111 1111 1111 1111 1111 1111 1111 0100 c = -12
print(c); // -12
print(~c); // 11
1111 1111 1111 1111 1111 1111 1111 0100作为机器码,最高位表示符号位,计算机将数据存储为补码的形式,也就是,-12的补码为1111 1111 1111 1111 1111 1111 1111 0100。如果是无符号整数,则其取值将为
4294967284。原码是
符号位和真值的绝对值,比如-12的原码表示:最高位为符号位,后面为其真值的绝对值。-12 原码: 1000 0000 0000 0000 0000 0000 0000 1100正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反:
-12 原码: 1000 0000 0000 0000 0000 0000 0000 1100 -12 反码: 1111 1111 1111 1111 1111 1111 1111 0011正数的补码也是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即
反码+1)-12 原码: 1000 0000 0000 0000 0000 0000 0000 1100 -12 反码: 1111 1111 1111 1111 1111 1111 1111 0011 -12 补码: 1111 1111 1111 1111 1111 1111 1111 0100这就是上面取值为
-12的原因。
^按位异或
int a = 65;
int b = 11;
int c = a ^ b;
0000 0000 0000 0000 0000 0000 0100 0001 a = 65
^ 0000 0000 0000 0000 0000 0000 0000 1011 b = 11
0000 0000 0000 0000 0000 0000 0100 1010 c = 74
<<、>>按位进行左移和右移
int a = 65;
int c = a << 2;
0000 0000 0000 0000 0000 0000 0100 0001 a = 65
0000 0000 0000 0000 0000 0001 0000 0100 c = 260
赋值运算符(Assignment operators)
赋值运算符用于将一个值赋值给变量。使用的是=等于号,左侧为变量,右侧为可以获取的值(字面量、变量、表达式、函数等)。
-
=用于直接赋值。 -
??=用于为值为null的变量赋值。
int a = 10;
int b = a + 40;
??=当变量为null时,才会进行赋值,是对null判断并赋值的一种语法糖(简写形式)。
int? a;
a??=10;
// 等价于
if(a==null){
a=10;
}
=、??=的同时使用:
int b = a ??= 20;
- 组合赋值运算符
算数运算符、位运算符可以和赋值运算符进行组合,本质是两种运算符的简写。
比如 += :
int a = 10;
a += 20;
// 等同 a = a + 20;
此外还有:+= -= *= /= %= ~/= &= |= ^= <<= >>= >>>=
目前没有
~=。
--、++自增自减运算符
自增自减运算符分为前置和后置两种类型。前置自增/自减是先进行自增/自减运算然后再取值;后置自增/自减是先取值然后再进行自增/自减。
var a = 10;
var b = 15;
var c = a++;
var d = b--;
var e = ++a;
var f = --b;
print('a=$a');
print('b=$b');
print('c=$c');
print('d=$d');
print('e=$e');
print('f=$f');
输出结果如下,可以对比了解前置自增/自减、后置自增/自减的区别:
a=12
b=13
c=10
d=15
e=12
f=13
条件表达式(Conditional expressions)
条件表达式可以用来替代if-else语句,使条件处理更加简明。
condition?expr1:expr2 如果条件为真,执行 表达式1 并返回结果,否则执行 表达式2 并返回结果。
expr1 ?? expr2 如果 表达式1 不为 null 则返回其值,否则执行 表达式2 并返回其值。
如下,根据布尔表达式确定取值:
var visibility = isPublic ? 'public' : 'private';
根据是否为null确定取值:
var result = name ?? 'Guest';
??可以用?:三元表达式来实现:
var result = name!=null?name:'Guest';
?:有三个表达式,因此也被称为三元运算符,或三目运算符。上面介绍的其他运算符,比如
+、-、*、/等有两个表达式,被称为二元或二目运算符;!、~、++等有一个表达式,被称为一元或单目运算符。
类型判断运算符(Type test operators)
as、is、is! 运算符用于在运行时判断对象的类型。
- as 类型转换
- is 如果对象是指定类型则返回 true
- is! 如果对象是指定类型则返回 false
后续在对象的使用中进一步了解。