本教程介绍了Dart语言的一些基本特性,并展示了如何在实践中使用它们。
正确使用它们,可以使代码清晰、轻量、更健壮。
1.类型推断
Dart编译器可以从变量的初始化器中自动推断出变量的类型,这样我们就不必自己声明类型了。
在实践中,这意味着我们可以将这段代码。
String name = 'Andrea';
int age = 35;
double height = 1.84;
到这个。
var name = 'Andrea';
var age = 35;
var height = 1.84;
这样做是因为Dart可以从赋值右边的表达式中推断出类型。
我们可以像这样声明一个变量。
var x;
x = 15;
x = 'hello';
在这种情况下,x ,先声明,后初始化。
它的类型是dynamic ,意味着它可以从不同类型的表达式中被赋值。
经验之谈
- 在使用
var,只要变量是同时声明和初始化的,Dart会推断出正确的类型。
2.final和const
当一个变量用var声明后,它可以被再次赋值。
var name = 'Andrea';
name = 'Bob';
换句话说。
var意味着多次赋值。
这在final 中是不允许的。
final name = 'Andrea';
name = 'Bob'; // 'name', a final variable, can only be set once
Final在实践中
在widget类内部声明属性时,使用final 是非常常见的。例子。
class PlaceholderContent extends StatelessWidget {
const PlaceholderContent({
this.title,
this.message,
});
final String title;
final String message;
// TODO: Implement build method
}
这里,title 和message 不能在widget里面被修改,因为。
final意味着单一赋值。
所以,var 与final 之间的区别是关于多重赋值与单一赋值。现在让我们看一下const 。
const
const定义了一个编译时常量。
const 用于定义硬编码的值,如颜色、字体大小和图标。
但我们也可以在定义widget类时使用constructor。
这是有可能的,只要小组件内部的一切也是一个编译时常量。例子。
class PlaceholderContent extends StatelessWidget {
const PlaceholderContent({
this.title,
this.message,
});
final String title;
final String message;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
title,
style: TextStyle(fontSize: 32.0, color: Colors.black54),
),
Text(
message,
style: TextStyle(fontSize: 16.0, color: Colors.black54),
),
],
),
);
}
}
而如果一个widget有一个const 构造函数,它就可以像这样构建。
const PlaceholderContent(
title: 'Nothing here',
message: 'Add a new item to get started',
)
因此,这个widget被Flutter优化了,因为当父类改变时,它不会被重新构建。
经验之谈。
final意味着单个赋值const定义了一个编译时常量- const小部件在其父级变化时不会被重建。
- 在可能的情况下,优先选择
const而不是final
3.命名参数和位置参数
在Dart中,我们用大括号({})来定义命名参数。
class PlaceholderContent extends StatelessWidget {
// constructor with named parameters
const PlaceholderContent({
this.title,
this.message,
});
final String title;
final String message;
// TODO: Implement build method
}
这意味着我们可以像这样创建上面的小部件。
PlaceholderContent(
title: 'Nothing here',
message: 'Add a new item to get started',
)
作为一种选择,我们可以在构造函数中省略大括号来声明位置参数。
// constructor with positional parameters
const PlaceholderContent(
this.title,
this.message,
);
结果,参数是由它们的位置定义的。
PlaceholderContent(
'Nothing here', // title at position 0
'Add a new item to get started', // message at position 1
)
这很有效,但当我们有很多参数时,很快就会变得混乱。
命名的参数有助于解决这个问题,因为它们使代码更容易编写(和阅读)。
顺便说一下,你可以像这样结合位置参数和命名参数。
// positional parameters first, then named parameters
void _showAlert(BuildContext context, {String title, String content}) {
// TODO: Show Alert
}
Flutter小组件通常有一个单一的位置参数,然后是命名参数。Text widget就是一个很好的例子。
作为一个准则,我总是希望我的代码是清晰和不言自明的。而我也相应地选择使用命名参数或位置参数。
4.@required & default values
默认情况下,命名参数可以被省略。
省略一个命名的参数就等于给它一个
null。
而有时,这将导致意想不到的后果。
在上面的例子中,我们可以定义一个PlaceholderContent() ,而忘记传入title 和message 。
而这将导致一个红色屏幕的错误,因为我们将把null 的数据值传递给Text 小工具,这是不允许的。
非空字符串错误
@required来拯救
我们可以像这样注解任何需要的参数。
const PlaceholderContent({
@required this.title,
@required this.message,
});
如果我们忘记传入这些参数,编译器会发出警告。
必需参数警告
尽管如此,如果我们想的话,我们可以明确地传递null 值。
PlaceholderContent(
title: null,
message: null,
)
编译器对此也很满意。
为了防止传递null 值,我们可以添加一些断言。
const PlaceholderContent({
@required this.title,
@required this.message,
}) : assert(title != null && message != null);
我们的代码在这种改变下会更安全,因为。
@required增加了一个编译时检查assert增加了一个运行时检查
如果我们在代码中加入断言,那么运行时错误就更容易解决了,因为它们会准确地指向导致错误的那一行。
不可归零的类型
@required 和 ,使我们的代码更安全,但它们感觉有点笨拙。assert
如果我们能在编译时指定一个对象不能为空,那就更好了。
这一点可以通过非空洞类型来实现,这些类型从一开始就被内置于Swift和Kotlin。
而非空类型目前正在Dart语言中实现。
因此,我们可以掰着手指头希望它们尽快到来。🤞
默认值
有时,指定一些合理的默认值是很有用的。
这在Dart中是很容易的。
const PlaceholderContent({
this.title = 'Nothing here',
this.message = 'Add a new item to get started',
}) : assert(title != null && message != null);
通过这种语法,如果省略了title 和message ,那么就会使用默认值。
顺便说一下,默认值也可以用位置参数来指定。
int sum([int a = 0, int b = 0]) {
return a + b;
}
print(sum(10)); // prints 10
总结
代码是写给机器执行的,也是写给其他人类阅读的。
生命是短暂的。善待自己,写好代码 😉
- 它使你的应用程序更健壮,更有性能。
- 它可以帮助队友和你未来的自己。
编码愉快!