# 运算符和控制流程语句

# 运算符

# 算术运算符

操作符 含义
+ 加法
- 减法
* 乘法
/ 除法
~/ 除法,返回整数结果
% 除法,获取余数(取模)
++var 自增,先增再运算
var++ 自增,先运算再增
--var 自减,先减再运算
var-- 自减,先运算再减
print(1+2);  // 3
print(1-2);  // -1
print(2*3);  // 6
print(7/2);  // 3.5
print(7~/2);  // 3
print(7%2);  // 1
var n = 2;
print(n++);  // 2
print(n);  // 3
print(--n);  // 2

# 关系运算符

操作符 含义
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

要判断两个对象是否表示相同的事物,使用 ==运算符(有时,要确定两个对象是否完全相同,用identical()函数)

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

# 类型判定运算符

操作符 含义
as 类型转换
is 如果对象具有指定的类型则为true
is! 如果对象具有指定的类型则为false

这几个运算符用于在运行时处理类型检查

void main(){
  var p = new Person('zhangsan');
  assert(p is Person);
  var s = new Student(12);
  assert(s is Student);

  if(p is Person){
    print(p.name);
  }
}

class Person {
  String name;
  Person(this.name);
}
class Student {
  int age;
  Student(this.age);
}

其中

if(p is Person){
  print(p.name);
}

可以变成

print((p as Person).name);

但是这两者并不是相等的,因为在第二种情况中,如果p不是Person的实例,那么是会抛出异常的

# 赋值运算符

使用=为变量赋值

var a = 1;

使用??=运算符,当被赋值的变量为null时才会赋值给它,否则还是原本的值

var a = 1;
var b = 2;
var c;
b ??= a;
c ??= a;
print(b);  // 2
print(c);  // 1

# 逻辑运算符

操作符 含义
&& 与,两个都成立则成立
|| 或,只要有一个成立就成立
! 非,将表达式反转,true变成false, false变成true

这个和其他的语言基本一样

# 条件表达式

操作符 含义
condition ? expr1 : expr2 三目运算符,如果condition为true,则执行expr1,否则执行expr2
expr1 ?? expr2 如果expr1是null,则返回expr2的值,否则返回expr1的值
var f = false;
var a = f ? 'Yes' : 'No';
print(a);  // No

var n = null;
print(n ?? 666);  // 666

# 级联运算符

实现对同一个对象进行一系列操作.除了调用函数,还能访问字段属性,有点像jQuery的链式调用.好处是可以节省创建临时变量的步骤,使编写出来的代码更加的流畅.

List<int> list = [1,2]
  ..add(3)
  ..add(4);
print(list);  // [1, 2, 3, 4]

# 其他运算符

?. 当运算符左边不为null的时候,获取其运算符右边的属性值.当为null时,返回null

var p = new Person('zhangsan');
var p2 = null;
print(p?.name);  // zhangsan
print(p2?.name);  // null

# 控制流程语句

顾名思义,就是用来控制dart程序流程走向的语句

# if和else

var a = 2;
if(a == 1){
  print(1);
}else if(a == 2){
   print(2);
}else{
  print(3);
}

# for循环

var list = ['zhangsan','lis'];
for(var i = 0; i < list.length; i++) {
  print(list[i]);
}

如果要迭代一个实现了 Iterable 接口的对象,可以使用forEach()方法 ,例如 List, Set 等

var list = ['zhangsan','lis'];
list.forEach((item) => print(item));

var s = {'zhangsan','lisi'};
s.forEach((item) => print(item));

同样的,它们也支持使用 for-in 来进行迭代

var s = {'zhangsan','lisi'};
for(var p in s){
  print(p);
}

# while和do-while

和其他语言的基本一样,while就是先判断再执行, do-while就是先执行再判断

var a = 1;
while(a < 5){
  print(a++);  // 1 2 3 4
}

var b = 1;
do{
  print(b++);  // 1
}while(b < 1);

# break和continue

和其他语言的基本一样,break停止循环,continue跳转到下次迭代

for(var i = 0; i < 5; i++){
  if(i == 2){
    break;
  }
  print(i);  // 0 1
}

for(var i = 0; i < 5; i++){
  if(i == 2){
    continue;
  }
  print(i);  // 0 1 3 4
}

# switch和case

每个非空的case语句结尾必须要跟一个break语句.除break以外还有continue, throw , return,否则会报错

var a = 1;
switch(a){
  case 1:
    print(1);
    break;
  case 2:
    print(2);
  default:
    print('other');
}

上面的代码会报错:Error: Switch case may fall through to the next case. 若匹配到某一个为空的case语句,则顺延执行下一个case语句,下面的代码打印出other

var a = 2;
switch(a){
  case 1:
    print(1);
    break;
  case 2:
  default:
    print('other');
}

可以使用continue语句跳转到具体的一个标签处

var a = 2;
switch(a){
  label:
  case 1:
    print(1);
    break;
  case 2:
    print(2);
    continue label;
  default:
    print('other');
}

# assert

断言语句,生产环境无效,只在开发环境中有效 可以有两个参数: 第一个参数是一个解析成bool类型的任何表达式.若为true,断言成功,程序继续执行,若为false,断言失败,抛出异常 第二个参数就是断言失败抛出异常时的自定义提示

var a = 1;
assert(a == 1);
assert(a != 1,'a的值为1,所以此次断言失败');