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
后续在对象的使用中进一步了解。