Dart

Dart之旅04: 运算符

2019-02-12  本文已影响31人  suikaJY

有些语言翻译为运算符,有些叫操作符,都指的是Operator。

Dart定义的操作符都在下表中。你可以像C++或者Kotlin一样重写大部分操作符,这些操作符又叫可重载操作符。在类的章节详述。

描述 操作符
一元后缀 expr++ expr-- () [] . ?.
一元前缀 -expr !expr ~expr ++expr --expr
乘法级别 * / % ~/
加法级别 + -
进位 << >>
按位与 &
按位异或 ^
按位或 |
大小关系和类型判断 >= > <= < as is is!
相等 == !=
逻辑与 &&
逻辑或 ||
if null ??
三元运算 expr1 ? expr2 : expr3
及联 ..
赋值 = *= /= ~/= %= += -= <<= >>= &= ^= |= ??=

当你使用操作符时,你就是在创建表达式:

a++
a + b
a = b
a == b
c ? a : b
a is T

上面的操作符列表中,每一行都比下一行的优先级要高。

如果两个对象都重载了相同二元操作符,那么本次重载使用操作符使用左侧操作数的重载方法。比如Vector对象+Point对象aVector+aPoint的结果是调用Vector对象的加号重载方法。

算术运算符

dart支持的算术运算符如下表:

Operator Meaning
+ Add
- Subtract
-expr Unary minus, also known as negation (reverse the sign of the expression)
* Multiply
/ Divide
~/ Divide, returning an integer result
% Get the remainder of an integer division(modulo)

Example:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

Dart同样支持前缀和后缀自增自减运算符:

Operator Meaning
++var var = var + 1 (表达式值为var+1)
var++ var = var + 1 (表达式值为var)
--var var = var – 1 (表达式值为var – 1)
var-- var = var – 1 (表达式值为var)

Example:

var a, b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0

这里和大部分语言都是一样的。

等式和关系运算符

下表是等式和关系运算符的含义:

Operator Meaning
== 相等;见下面讨论
!= 不等
> 大于
< 小于
>= 大于等于
<= 小于等于

通常而言,dart的==操作符都是用来判断两个变量的内容是否相等。这和大部分语言都一样,但如果你想精确的确定两个变量指向的对象是一个对象,那么你可以使用identical()方法来代替。这里说明下==的工作原理:

  1. 如果x或者y是null,那么如果两者皆空则返回true
  2. 两者都不为空,调用x.==(y)。这里==先暂时看作一个函数名,更详细的参考操作符重载部分。

下面是一个例子:

assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

类型测试操作符

as, is and is!都是运行时的类型测试操作符

Operator Meaning
as 类型转换(在import时也可以用来指定库前缀
is 如果对象是指定类型返回true(相当于java的instanceof)
is! is的取反

如上所说,as就是java中的类型强转,用来将父类转换成子类。在dart中同样有智能转换的概念(和kotlin一样):

if (emp is Person) {
  // Type check
  emp.firstName = 'Bob';
}

当使用is判断之后emp其实在if语句中隐式的被认为了是Person对象。这在Kotlin中叫做智能转换,dart文档中并没有相关的命名。

你可以通过as来让代码变得更短:

(emp as Person).firstName = 'Bob';

注意:这里推荐使用is判断,因为as的本质是类型强转,强转失败会产生类型转换异常。而is则会什么也不做。

赋值操作符

赋值运算符也就是=的用法和其他语言基本一致。如果一个变量只有在null的情况下接受赋值可以使用??=:

// Assign value to a
a = value;
// 如果b是null,则赋值为value,否则b保持不变
b ??= value;

复合赋值运算符(例如+=,<<=)就是原有运算符和赋值运算符的结合。这里不再赘述了,有关复合赋值运算符的重载,参考运算符重载部分。

逻辑运算符

逻辑运算符就是!, ||, &&这个和java,php或者c语言都是一样的。

位运算符

如下表,和常用语言相通:

Operator Meaning
& AND
| OR
^ XOR
~expr Unary bitwise complement (0s become 1s; 1s become 0s)
<< Shift left
>> Shift right

用例:

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

条件表达式

dart有两个操作符用来简明地形容一个表达式,它们或许可以取代if-else语句:

condition ? expr1 : expr2

这个是三元运算符,和java等常用语言一样的。

expr1 ?? expr2

如果expr1是不为空,则表达式的值为expr1,否则为expr2.
由于三元运算符属于表达式而非语句,它们可以用在变量或者常量声明上:

var visibility = isPublic ? 'public' : 'private';

一般的判空取默认值操作可以使用??操作符:

String playerName(String name) => name ?? 'Guest';

及联符号..

及联符号的出现优雅了构建器模式的概念。一个类有多个属性可以设置,往往需要声明一个临时变量,并连续使用这个临时变量进行set操作。及联符号可以省去这个临时变量,而让代码看起来像构建器模式一样:

querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

这里querySelector()创造了一个选择器对象,后续的及联调用忽视了所有调用的返回值。这一连串的调用的最终返回值就是它们一直在设置的那个对象。

前面的例子就等同于:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

你也可以嵌套使用及联运算符:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

要小心使用及联运算符,它们必须用在一个真实对象上,下面是一个反例:

var sb = StringBuffer();
sb.write('foo')
  ..write('bar'); // Error: method 'write' isn't defined for 'void'.

这里的sb.write()方法是一个void类型的方法。他没有返回一个真实的对象。所以不能在此之上使用及联。

准确来说..运算符并不是一个运算符,它只是Dart语法的一部分。

其他操作符

你已经在其他的例子中看见过剩下的操作符了:

Operator Name Meaning
() Function application 代表调用一个函数
[] List access 获取中括号内索引指定的集合元素
. Member access 访问一个表达式的成员,比如foo.bar就是访问表达式foo的成员bar
?. Conditional member access 类似.,但这个操作符多数用于左值是一个可能为空的值。比如foo?.bar如果此时表达式foo的返回值为null,那么这个表达式整体为null值,否则为bar的值

这里有一个小技巧文档上没有讲:可以使用foo?.bar??defaultValue的形式来连续简化代码。

上一篇下一篇

猜你喜欢

热点阅读