一、参数
| 分类 | 修饰符 | 核心使用场景 | 极简示例 |
|---|
| 变量 / 空安全(核心) | final | 变量仅赋值一次(运行时确定值),不可修改 | final String name = '张三';(无法再赋值 name = '李四') |
| const | 编译时常量(值固定),不可变,适合全局常量 | static const int maxAge = 100;(编译期确定,内存复用) |
| late | 延迟初始化非空变量(空安全),避免声明时赋值 | late User user = Provider.of(context);(使用时才初始化) |
| ? | 标记变量为可空类型,允许赋值 null | String? username; username = null;(可空,使用需判空) |
| ! | 强制解包可空变量(断言非空,慎用) | String? name = '张三'; print(name!.length);(确保非空时用) |
| required | 构造函数参数必须传值(替代旧版 @required) | User({required this.name});(实例化必须传 name) |
| 类 / 继承(高频) | static | 静态成员(属于类,非实例),全局复用 | class Math { static int add(int a, int b) => a + b; }(调用:Math.add(1,2)) |
| abstract | 抽象类(不可实例化),定义接口规范 | abstract class Shape { void draw(); }(子类必须实现 draw 方法) |
| extends | 单继承类(Dart 唯一继承方式) | class Student extends Person {}(继承 Person 的属性 / 方法) |
| implements | 实现接口(多实现),必须重写所有成员 | class Dog implements Animal { @override void eat() {} } |
| mixin/with | 混入复用方法(多混入),替代多继承 | mixin Flyable { void fly() {} } class Bird with Flyable {} |
| 函数 / 方法(高频) | async/await | 异步函数,处理网络 / IO 等耗时操作 | Future<String> fetchData() async { return await http.get('url'); } |
| factory | 工厂构造函数,控制实例创建(单例 / 缓存) | factory Singleton() => _instance ??= Singleton._internal(); |
| @override | 标记重写父类方法(编译器检查正确性) | @override void draw() {}(确保正确重写抽象方法) |
| 访问控制(核心) | _(私有) | 文件级私有成员,跨文件不可访问 | class User { String _password; }(仅当前文件能访问 _password) |
| 默认(公有) | 无修饰符,跨库 / 跨类可见 | class User { String name; }(任意地方可访问 name) |
1、访问控制修饰符
| 修饰方式 | 语法示例 | 可见范围 | 说明 |
|---|
| 公开 (Public) | var name class MyClass | 全局可见 | 默认情况。只要不以 _ 开头,任何导入该文件的代码都可以访问。 |
| 私有 (Private) | var _name class _MyClass | 库内可见 | 标识符前加下划线 _。 仅在当前文件 (.dart) 内可见。 即使是同一个包下的其他文件也无法访问。 |
2、成员变量修饰符
| 可变性与常量修饰符 | 含义 | 典型场景 |
|---|
final | 运行时常量。 变量只能被赋值一次,值在运行时确定。 | 构造函数传入的参数、需要在 initState 中初始化的状态。 |
const | 编译时常量。 变量必须在编译时就知道确切值,且对象本身必须是不可变的。 | 配置项、数学常数、纯静态的 Widget 树。 |
late | 延迟初始化。 告诉编译器:“我保证在使用前会赋值,请先别报空安全错误”。 类型是非空的,但初始化被推迟了。 | 依赖注入、需要在 initState 异步加载后赋值的变量、循环引用。 |
| 作用域与生命周期修饰符 | 含义 | 典型场景 |
|---|
static | 静态成员。 属于类本身,不属于某个实例。所有实例共享同一份内存。 | 工具方法、单例模式、全局计数器、常量池。 |
3、dynamic参数
dynamic 并不是一个“修饰符” (像 final、static 或 @override 那样放在变量前面改变其行为的关键字),而是一个特殊的类型关键字,声明为 dynamic 的变量,编译器会跳过所有的类型检查。
什么时候使用 dynamic 参数?
- 处理 JSON/反序列化:JSON 数据结构复杂且嵌套,字段类型不固定时。
- 通用工具函数:例如一个打印日志的函数,需要接受任何类型的对象。
- 反射或元编程:需要动态调用对象方法时。
- 遗留代码兼容:迁移旧代码时暂时绕过类型检查。
| 特性 | dynamic | Object? | var (推断) |
|---|
| 类型检查 | 无 (关闭检查) | 有 (严格检查) | 有 (基于初始值锁定类型) |
| 方法调用 | 允许调用任何方法/属性 | 只能调用 Object 的方法 (如 toString, hashCode) | 只能调用推断出的类型的方法 |
| 赋值灵活性 | 可以随时赋值为任何类型 | 可以赋值为任何对象 (因为是 Object?) | 一旦推断完成,不能赋值为其他类型 |
| 安全性 | 低 (运行时才报错) | 高 (编译时报错) | 高 (编译时报错) |
| 典型用途 | 黑盒数据、反射、JSON | 接收任意对象但只进行通用操作 | 局部变量,类型明确 |