Flutter/Dart第06天:Dart根底语法详解(变量)
Dart官网文档:https://dart.dev/language/variables
重要说明:本博客依据Dart官网文档,但并不是简略的对官网进行翻译,在掩盖中心功用情况下,我会依据个人研制经历,参加自己的一些扩展问题和场景验证。
Dart中的变量
变量是一个目标的引证,引证名便是变量的称号;就算引证是null
的变量也相同。
变量有3种界说办法:var
要害字,显现类型
和Object
/dynamic
类型。
var varName = 'Tom';
String strName = 'Tom';
Object objName = 'Tom';
dynamic dynName = 'Tom';
最佳实战:关于局部变量,优先运用var
要害字,其次为显现类型
,再次为Object
,不引荐运用dynamic
(原因:简单引发运行时过错,后续的学习会讲到)。
当运用var
要害字界说的变量,Dart会依据值内容,推导出变量的实践类型,如上诉代码varName
变量终究为String
类型。
Null safety空安全
Dart言语强制强健空安全。空安全能够避免意外运用null
而导致的过错(还记得在Java编程中,在许多目标运用的当地,咱们都需求进行null
判别,以避免NPE的产生)。Dart在编译期间,就会进行null潜在过错检测剖析,然后避免这些过错的产生(留意:并不是一切场景都能检测剖析到,后边章节会讲到)。
代码样例:如下代码,变量strName
的默许值为null
,在其他编程言语如Java言语中,下面的代码是合法的,可是在运行时,当履行strName.length
时会引发NPE反常;可是在Dart言语中,以下代码是不合法的(无法编译),因而阻挠产生NPE等这些潜在的过错。
String strName;
print(strName.length)
Dart为了强制履行空安全,有3个要害改动:
- 假如清晰期望某个变量、参数或许其他组件是能够为
null
的,那么需求在类型后边添加一个?
标识:
String? name // `name`的值可能为`null`, 或许为某个字符串
String name // `name`的值只能是某个字符串,不能为`null`
- Dart的变量在运用之前,有必要被初始化。可空变量(含有
?
标识)的默许值为null
,即默许初始化为null,因而无需显现的赋值初始化;而非空变量因没有默许值,因而有必要显现赋值初始化。 - 制止直接拜访可空类型的特点或许表达式办法,包括拜访
null
目标的hashCode
和toString()
办法(记住:Dart中一起皆目标,null也是),也会引发过错。
Dart空安全经过以上3个要害改动,保证null
潜在过错在代码编写阶段就能被前置发现,而不是比及代码运行时。
变量默许值
第2章节中,其实现已说到一点:任何变量在运用之前,有必要被初始化;可空变量由于默许值为null,因而可无需显现初始化;非空变量有必要显现初始化。
特别留意:非空变量只需求保证它在被运用时现已初始化即可,而不是有必要在声明的时分。如下代码,变量lineCount
在声明时并未初始化,可是在print
被运用时,Dart言语检测到它现已被初始化了,因而如下代码是空安全有用代码。
// 声明:未被初始化
int lineCount;
if (weLikeToCount) {
lineCount = countLines();
} else {
lineCount = 0;
}
// 运用:Dart检测到现已被初始化,因而是能够运用
print(lineCount);
late推迟变量
尖端变量和类变量会推迟初始化,当第一次运用到这些变量时,初始化代码的逻辑才会被履行(即:推迟初始化)。
在大多数情况下,Dart能够检测并剖析一个非空变量在运用时现已初始化,可是在有些场景下,Dart无法检测剖析或许检测剖析会失效。最常见的2种场景:尖端变量和实例变量,Dart无法确认它们在被运用时是否现已被初始化了。
假如咱们清晰一个非空变量在被运用之前能完结初始化(但Dart却无法检测到),可经过添加late
要害字,告知Dart该变量为推迟变量,在被运用之前保证能被初始化。当然,关于late
推迟变量,在被运用时却并没有初始化,那么运用它同样会导致运行时过错。
late String description;
void main() {
description = 'Feijoada!';
print(description);
}
late
推迟变量首要处理以下2种场景:
- 这些变量并不是有必要的,一起初始化它们十分耗时或许浪费资源(如网络交互等)。
- 在初始化实例变量时,需求用到实例自身。
代码样例:如下代码,当变量temperature
在第1次被运用时,才会被调用readThermometer()
办法,即该办法只是被调用1次。
late String temperature = readThermometer();
final变量和const常量
最佳实践:假如咱们清晰一个变量在被初始化之后,它的引证值再也不会改变,那么运用final
或许const
润饰,而不是运用var
者显现类型
。
const
变量隐式为final
变量const
变量是编译期的常量变量- 实例变量能够是
final
变量但不能是const
变量(原因:实例在运行时才干确认,因而其变量无法作为编译期常量)
final name = 'Bob';
final String nickname = 'Bobby';
const bar = 1000000;
const double atm = 1.01325 * bar;
特别留意:const
不只能够声明如上代码的常量变量,它也能够用于声明创立常量值,也能够用于声明创立常量值的结构器(还记得第2天学习内容:const结构函数?);一起,任何变量,都能够有常量值。
// 1. 常量值
var foo = const [];
final bar = const [];
const baz = []; // 同等:`const []`
// 2. 非final/const变量,它的常量值能够更新
foo = const [1, 2, 3];
特别留意:常量的界说,能够包括类型检测、类型转化、调集过滤和调集打开操作符。
// `i`是一个`Object`类型常量,它的值是int数字值
const Object i = 3;
// 1. 类型转化
const list = [i as int];
// 2. 类型检测和调集过滤
const map = {if (i is int) i: 'int'};
// 3. 类型检测、调集过滤、调集打开
const set = {if (list is List<int>) ...list};
final变量和const常量总结:
final
变量不行修正,可是它的值是能够更新。const
常量不行修正,一起它的值也不能够更新,即它的值是不行变的(immutable)。
void main() {
// 1. final变量
final finalList = [1, 2, 3];
print('1.1 final变量: $finalList');
// 输出:1.1 final变量: [1, 2, 3]
finalList
..add(4)
..add(5);
print('1.2 final变量: $finalList');
// 输出:1.2 final变量: [1, 2, 3, 4, 5]
// 2. const常量
const constList = ['a', 'b', 'c'];
print('2.1 const常量: $constList');
// 输出:2.1 const常量: [a, b, c]
constList
..add('c')
..add('d');
print('2.2 const常量: $constList');
// 过错:
// Unhandled exception:
// Unsupported operation: Cannot add to an unmodifiable list
// #0 UnmodifiableListMixin.add (dart:_internal/list.dart:114:5)
}
我的本博客原地址:https://ntopic.cn/p/2023100101