Skip to content

Dart语言入门 - 运算符与表达式详解(新手避坑指南)

⚠️ 特别注意:Dart某些运算符的语义与其他语言(如Java/JavaScript)大不相同!文内含大量易错点标注和示例对比


目录

  1. 算术运算符隐藏特性
  2. 关系运算符的微妙差别
  3. 逻辑运算符短路之谜
  4. 类型测试运算符
  5. 空安全三剑客
  6. 赋值运算符的冷知识
  7. 级联运算符妙用
  8. 条件表达式陷阱
  9. 位运算符实际应用
  10. 运算符优先级表

1. 算术运算符隐藏特性

dart
// 普通运算符
print(5 / 2);   // 2.5 → double类型结果(新手可能误以为返回整数)
print(5 ~/ 2);  // 2   → 真正意义的整除

// 自增运算的位置陷阱
int a = 1;
print(a++);  // 输出1 → 先用后增
print(++a);  // 输出3 → 先增后用

// 除零处理(不会crash!)
double x = 5 / 0;  // Infinity(与Java不同!)
print(x.isInfinite); // true → 重要校验方法

💥 致命误区

dart
// JavaScript习惯带过来的错误
var numStr = '123';
print(numStr + 5); // '1235' → 自动调用toString()
                   // 正确做法:先转int → int.parse(numStr) +5

2. 关系运算符的微妙差别

dart
// 对象比较的深坑
List list1 = [1,2];
List list2 = [1,2];
print(list1 == list2);  // false!(通过引用比较)

// 特殊NaN比较
double nan = 0.0 / 0.0;
print(nan == nan); // false! → 必须用 isNaN 判断

// 字符串字母序比较
print('Dart' compareTo('Flutter')); // 负整数 → 用来排序时很实用

🌰 实战技巧

dart
// 通过compareTo快速实现对象排序
class Person implements Comparable<Person> {
  int age;
  //... 必须实现compareTo方法才能在sort中直接使用
}

3. 逻辑运算符短路之谜

dart
bool condition() {
  print('condition called');
  return true;
}

// && 短路验证
false && condition(); // condition() 永不执行
true || condition();  // 同理:|| 左边为true则短路右边

// 非布尔值逻辑运算 → 会报错!
var x = '' || 'default'; // ❌ 与JS/PHP不同!
          ↓ ↓ ↓ 
var y = x.isEmpty ? 'default' : x; // 正确做法

4. 类型测试运算符

dart
// is 和 as 的使用规范
dynamic obj = 'hello';
if (obj is String) {   // √ safer
  print(obj.length);
}

// as强制转换风险
var num = 123;
var str = num as String; // ❌ 运行时抛出异常!
       ↓ ↓ ↓ 
var str = num.toString(); // 正确做法

5. 空安全三剑客

dart
// ?? → 空值合并运算符
String? name;
print(name ?? '无名氏'); // 安全替代null

// ?. → 安全导航运算符
List? list;
print(list?.length ?? 0); // 链式组合使用更安全

// ??= → 空时赋值运算符
int? score;
score ??= 60; // 等效于 score = score ?? 60

🔐 进阶技巧

dart
// 处理深层嵌套空值
var city = user?.address?.city ?? '未选择地区';

// 与集合配合使用
var firstItem = myList?[0] ?? defaultValue;

6. 赋值运算符的冷知识

dart
// 赋值表达式本身有值 → 可参与运算
int a;
int b;
print(a = b = 5); // 输出5 → 连续赋值可行但可读性差

// +=的隐含类型转换
double d = 3.14;
d += 1;  // √ 允许,等价于 d = d + 1
d = d + 1; // √ 同上

7. 级联运算符妙用

dart
// 建造者模式替代方案
Paint paint = Paint()
  ..color = Colors.red
  ..strokeWidth = 2.0
  ..style = PaintingStyle.fill;

// 相当于:
paint.color = Colors.red;
paint.strokeWidth = 2.0;
//... 能保持代码连贯性

8. 条件表达式陷阱

dart
// 条件表达式的类型推断
var result = condition ? 1 : 'error'; // 类型推断为Object(联合类型)
          ↓ ↓ ↓ 推荐做法 ↓ ↓ ↓
num result = condition ? 1 : 0;       // 保持类型一致

// 与??的优先级问题 → 总是加括号!
var msg = isVIP ? 'Welcome' : null;
print(msg ?? '普通用户' + '您好'); // ❌ 运算顺序误判!
        ↓ ↓ ↓ 
print((msg ?? '普通用户') + '您好'); // 正确写法

9. 位运算符实际应用

dart
// 快速开关功能(权限管理)
const VIEW = 1;    // 0001
const EDIT = 2;    // 0010 
const DELETE = 4;  // 0100

var permission = VIEW | EDIT;
print(permission & DELETE); // 0 → 未开启删除权限

// RGB颜色合成
int r = 255, g = 128, b = 64;
int color = (r << 16) | (g << 8) | b;

10. 运算符优先级表(常见)

优先级运算符描述案例
1() . ?. []方法/属性访问object.method()
2- ! ~ ++ --一元运算符!isActive
3* / % ~/乘除类5 % 3
4+ -加减法a + b - c
5<< >>位移运算flags << 2
6&按位与mask & 0xFF
7^按位异或a ^ b
8|按位或view | edit
9< > <= >= as is is!关系/类型测试age > 18
10== !=相等判断list1 == list2
11&&逻辑与isValid && isAdmin
12||逻辑或isEmpty || isDefault
13??空合并name ?? 'N/A'
14= *= /= ~/= %= += -= ...赋值运算符score += 5

生存法则:不确定优先级时永远用括号!


常见综合案例

案例1:安全解析数字

dart
String input = 'abc123';
int number = int.tryParse(input) ?? 0;

案例2:实现链式校验

dart
bool isValid = user != null 
    && user.email.isNotEmpty 
    && (user.age ?? 0) >= 18;

错误排查清单

  • 运行时出现Unhandled Exception:type 'int' is not a subtype of type 'String' → 检查类型转换引发的as误操作
  • 逻辑判断始终无效 → 可能混淆了&&/||优先级
  • List索引越界 → 使用?.时忽略了安全检查

练习题

  1. 写出表达式 (true ? 1 : 2.0) is int 的结果并解释原因
  2. user?.posts?.first.title ?? '无标题' 连续出现null时会发生什么?
  3. 如何使用位运算快速判断一个数是否是32的倍数?

(答案反白可见:1. false → 类型提升为double;2. 正确返回'无标题';3. (n & 31) == 0)