Dart变量
在Dart 中,我们有多种方式来声明和使用变量
1、使用var 来声明一个变量,Dart 会自动推断出变量类型,语法如下:
var name = "hello"; //注意:Dart语句要以分号结尾


2、声明的时候指定类型为String,如图:


注意:var 和 String等类型不能同时使用,var是自动推断,String是显示指定,如下是错误的:
var String a = "hello"; //错误,var和String不能同时使用,int等其他类型也是一样
空安全:Dart 语言要求以健全的空安全方式编写代码,空安全能够防止意外访问 null 的变量而导致的错误。这样的错误也被称为空解引用错误,访问一个求值为 null 的表达式的属性或调用方法时,会发生空解引用错误,但是对于 toString() 方法和 hashCode 属性,空安全会体现出例外情况。 Dart 编译器可以在空安全的基础上在编译期检测到这些潜在的错误。例如,假设你想要查找 int 变量 i 的绝对值。如果 i 是 null ,调用 i.abs() 会导致空解引用错误。在其他语言中,尝试这样做可能会导致运行时错误,但是 Dart 的编译器通过禁止这些操作来防止此类错误发生。
空安全引入了三个关键更改:
(1)、当你为变量、参数或另一个相关组件指定类型时,可以控制该类型是否允许 null 。要让一个变量可以为空,你可以在类型声明的末尾添加 ?,如下图,即使不直接设置值为null,默认也是null


(2)、你必须在使用变量之前对其进行初始化。可空变量是默认初始化为 null 的。 Dart 不会为非可空类型设置初始值,它强制要求你设置初始值。 Dart 不允许你观察未初始化的变量。这可以防止你在接收者类型可以为 null 但 null 不支持的相关方法或属性的情况下使用它
(3)、你不能在可空类型的表达式上访问属性或调用方法。同样的例外情况适用于 null 支持的属性或方法,例如 hashCode 或 toString()
空安全将潜在的 运行时错误 转变为 编辑时 分析错误。当非空变量处于以下任一状态时,空安全会识别该变量:
- 未使用非空值进行初始化
- 赋值为空
你不必在声明变量时初始化变量,但在使用之前需要为其赋值。例如以下代码是合法的,因为 Dart 可以检测到 abcd在传递给 print() 时是非空的:


注:上述代码中如果if条件没有写else,那么执行后就会报错提示变量未初始化,因为Dart编译器看到了if条件后就会考虑还有else条件中没有初始化,所以就会报错
3、如果一个对象不限于单一类型,可通过Object来指定,但是需要判断类型,如图:

注:Dart3后不推荐使用了,可通过泛型替代,除非与某些原生平台交互(如通过 dart:ffi 调用 C 函数)
4、如果一个变量在初始化后值不再改变,我们可以使用final 或const 声明它,但是final和const有点区别
- const是编译时常量,在编译之前就要指定值,不能在运行过程中指定
- final和const都是一旦设置了值就不能改变
- 如果
const变量在类级别,请将其标记为static const


下面例子中final在运行时候指定的值不会报错,但是const就会报错,如图:


任何变量都可以拥有常量值,如图:


final 关键字用于声明一个不可变的变量,但这个变量可以引用一个可变的对象。换句话说,虽然 final 变量本身不能被重新赋值,但它的字段(即对象的属性)仍然可以被修改。下面是不可变变量引用可变对象的例子,如图:


const 对象及其字段都不能被改变:它们是不可变的,下面是不可变变量引用不可变对象的例子,如图:

- 使用
const时,对象的字段也必须是final的,以确保整个对象是不可变的
5、late 关键字用于声明 延迟初始化 的非空变量,如图:

- 优势:避免使用可空类型(
String?),同时允许延迟初始化 - 如果变量可能永远不被初始化,应使用可空类型(
String?)而非late
如果使用late 声明变量没初始化,直接请求变量会报错,如图:


late变量默认为非空,因此不能声明后再次给变量赋值为null,如下:
late String name;
name = null; //报错
如果需要为null的late变量,需要显式声明类型为可空,如下:
late String? name; //加?表示可为空
name = null; //不会报错
6、通配符变量(通配符变量要求语言版本至少为 3.7)
名称为 _ 的通配符变量声明了一个非绑定的局部变量或参数;本质上,它是一个占位符。如果存在初始化器,它仍会执行,但值不可访问。在同一命名空间中可以存在多个名为 _ 的声明,而不会发生命名冲突错误,顶层声明或可能影响库隐私的成员不适用于通配符变量,块范围内的局部变量可以用通配符,如下

for (var _ in list) {} //for循环中使用
// try...catch中使用
try {
throw '!';
} catch (_) {
print('oops');
}


