Dart语言入门 - 运算符与表达式详解(新手避坑指南)
⚠️ 特别注意:Dart某些运算符的语义与其他语言(如Java/JavaScript)大不相同!文内含大量易错点标注和示例对比
目录
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) +52. 关系运算符的微妙差别
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索引越界 → 使用
?.时忽略了安全检查
✅ 练习题:
- 写出表达式
(true ? 1 : 2.0) is int的结果并解释原因 - 当
user?.posts?.first.title ?? '无标题'连续出现null时会发生什么? - 如何使用位运算快速判断一个数是否是32的倍数?
(答案反白可见:1. false → 类型提升为double;2. 正确返回'无标题';3. (n & 31) == 0)