[译] 类型及其在参数中的应用:利用 Dart 特性优化代码

类型及其在参数中的应用:利用 Dart 特性优化代码

本篇教程将会介绍 Dart 语言的一些基础特性,以及如何将其应用于代码中。前端

正确的使用这些特性,可以让你的代码更加整洁、轻量,而且健壮。android

1. 类型推断

Dart 编译器可以在变量初始化的时候自动推断它的类型,因此咱们也就没必要声明变量的类型。ios

在代码应用中,也就是咱们能够将这样的代码:git

String name = 'Andrea';
int age = 35;
double height = 1.84;
复制代码

转化为:程序员

var name = 'Andrea';
var age = 35;
var height = 1.84;
复制代码

这段代码之因此能生效,是由于 Dart 能够从表达式右边的值推断出变量的类型。github

咱们能够像这样声明变量:编程

var x;
x = 15;
x = 'hello';
复制代码

在这个例子中,x 声明在前,初始化在后。后端

此时它的类型是动态的,即 dynamic,这意味着,它能够被多个表达式赋值为不一样的类型。安全

小结less

  • 当使用 var 的时候,只要变量的声明和初始化是同时完成的,那么 Dart 将能正确的推断出变量类型。

2. final 和 const

当咱们使用 var 来声明变量的时候,这个变量能够被屡次赋值:

var name = 'Andrea';
name = 'Bob';
复制代码

也就是说:

使用 var 意味着能够屡次赋值

可是若是咱们使用了 final,就不能给变量屡次赋值了:

final name = 'Andrea';
name = 'Bob'; // 'name' 是一个 final 类型的变量,不能够被再次赋值
复制代码

final 的应用

在 widget 类中,很常见使用 final 声明的属性。例如:

class PlaceholderContent extends StatelessWidget {
  const PlaceholderContent({
    this.title,
    this.message,
  });
  final String title;
  final String message;
  
  // TODO:实现构建方法
}
复制代码

在这段代码中,titlemessage 在这个 widget 内是不能够被修改的,由于:

使用 final 意味着只能一次赋值

因此,使用 varfinal 的区别就是是否容许屡次或只能一次赋值。如今咱们再来看看 const

const

const 可以定义编译时常量

const 用来定义硬编码值,例如颜色、字体大小和图标等。

同时咱们也能够在定义 widget 类的时候使用 const 构建函数。

这是彻底可行的,由于全部 widget 内部的变量和方法都是编译时常量。例如:

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 优化为,当它的父级变化时,widget 自己不会重复构建

小结:

3. 命名参数和位置参数

在 Dart 中,咱们将变量使用大括号({})包起来,由此能够定义命名参数:

class PlaceholderContent extends StatelessWidget {
  // 使用命名参数的构建函数
  const PlaceholderContent({
    this.title,
    this.message,
  });
  final String title;
  final String message;
  
  // TODO:实现构建方法
}
复制代码

这段代码意味着,咱们能够像这样建立 widget:

PlaceholderContent(
  title: 'Nothing here',
  message: 'Add a new item to get started',
)
复制代码

还有一种替代方案是,咱们能够在构建函数中将大括号省略,声明位置参数:

// 使用位置参数的构建函数
const PlaceholderContent(
  this.title,
  this.message,
);
复制代码

结果就是,参数能够经过它们所在的位置来定义:

PlaceholderContent(
  'Nothing here', // title 参数位于 0 号位
  'Add a new item to get started', // message 参数位于 1 号位
)
复制代码

这彻底行得通,可是当咱们有多个参数的时候,这样很容易引发混乱。

此时命名参数就展露优点了,它们让代码更易写也更易读。

顺便说一句,你还能够将位置参数和命名参数结合起来:

// 位置参数优先,而后是命名参数
void _showAlert(BuildContext context, {String title, String content}) {
  // TODO:展现提示信息
}
复制代码

Flutter widget 中随处可见使用一个位置参数,而后使用多个命名参数的方式。Text widget 就是一个很好的例子。

我写代码的指导思想就是,代码必定要保持整洁、自洽。我会依照此合理选择命名参数和位置参数。

4. @required 和默认值

默认状况下,命名参数能够被省略。

省略命名参数就等于给它赋值为 null

有时候这会致使没法预期的后果。

在上面的例子中,咱们能够在定义 PlaceholderContent() 时并不传入 titlemessage 参数。

这将会致使错误,由于这样的话咱们会将 null 值传入 Text widget,但这是不容许的。

@required 是一种补救方法

咱们能够为任何变量添加 required 注释:

const PlaceholderContent({
  @required this.title,
  @required this.message,
});
复制代码

这样当咱们忘记传入参数的时候,编译器将会报出警告。

此时若是咱们须要,咱们仍旧能够明确写出传递 null 值:

PlaceholderContent(
  title: null,
  message: null,
)
复制代码

此时编译器就不会报警告了。

若是想要避免传入 null 值,咱们能够增长一些断言(assert):

const PlaceholderContent({
  @required this.title,
  @required this.message,
}) : assert(title != null && message != null);
复制代码

这些修改让咱们的代码安全系数更高,由于:

  • @required 会增长编译时检查
  • assert 会增长运行时检查

若是咱们为代码加入断言,那么运行时的错误就更容易改正,由于此时的报错会明确指出致使错误的代码位置。

非空类型

@requiredassert 让咱们的代码安全系数更高了,可是它们看上去有些笨重。

若是咱们能够指定对象在编译时不可为空就更好了。

经过使用非空类型咱们能够作到这一点,而它在一开始就内建在 Swift 和 Kotlin 中了。

并且非空类型如今也正计划应用于 Dart 语言。

让咱们祈祷它能够快点到来吧。🤞

默认值

有时候,指定合理的默认值也颇有用。

在 Dart 中这很容易就能作到:

const PlaceholderContent({
  this.title = 'Nothing here',
  this.message = 'Add a new item to get started',
}) : assert(title != null && message != null);
复制代码

使用这种语法,若是 titlemessage 参数被忽略了,那么默认值就会被使用。

顺便提一下,默认值也能够应用于位置参数:

int sum([int a = 0, int b = 0]) {
  return a + b;
}
print(sum(10)); // 打印出 10
复制代码

总结

代码是让机器执行的,可是也是要程序员阅读的。

时间宝贵。乖乖的写好代码 😉

  • 这样才能让你的应用更健壮,性能也更好。
  • 同时也能帮助你和你的团队有更好的发展。

编程愉快!

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索