内容简介:Dart支持四种集合:list、map、queue和setDart的类成员包含成员属性和方法(静态方法和实例方法)
-
类名采用
UpperCamelCase
风格写法(即:单词首字母大写,多单词直接拼接,同 Java 中类命名规则) -
库和源文件使用
lowercase_with_underscores
风格(即:小写字母,多单词以_
分割—) -
import的库文件设置别名时,别名也使用
lowercase_with_underscores
风格 -
其他标识符均使用驼峰法
-
字母缩写时,<=两个字符均大写(如:IO),>两个字符首字符大写(如:Http)
-
不要使用字母前缀(如:Java中常见的
mName
写法)
排序
-
dart:
系列import放在最前面 -
package:
系列import放在相对import前面 -
三方包的
package:
放在自己写的package:
前面 -
export
写在所有import
后面,且留白一行以分开 - 同一优先级的import块按照字母进行排序
格式化
- 使用 dartfmt 进行代码格式化
- 避免一行超过80个字符的长度
-
对所有的流式控制均使用
{}
用法
库
-
引用自己的
lib
包中的文件时,考虑使用相对路径/// my_package /// └─ lib /// ├─ src /// │ └─ utils.dart /// └─ api.dart // api.dart引用utils.dart时 // good import 'src/utils.dart'; // bad import 'package:my_package/src/utils.dart';
字符串
-
使用相邻字符串方式进行字符串拼接
// good raiseAlarm( 'ERROR: Parts of the spaceship are on fire. Other ' 'parts are overrun by martians. Unclear which are which.'); // bad raiseAlarm('ERROR: Parts of the spaceship are on fire. Other ' + 'parts are overrun by martians. Unclear which are which.');
-
使用插值方式组合字符串和值
// good 'Hello, $name! You are ${year - birth} years old.'; // bad 'Hello, ' + name + '! You are ' + (year - birth).toString() + ' y...';
-
插值时避免使用
{}
,除非必要// good 'Hi, $name!' "Wear your wildest $decade's outfit." 'Wear your wildest ${decade}s outfit.' // bad 'Hi, ${name}!' "Wear your wildest ${decade}'s outfit."
集合
Dart支持四种集合:list、map、queue和set
-
使用集合简化式进行实例化
// good var points = []; var addresses = {}; // bad var points = List(); var addresses = Map();
-
不要使用
.length
来判断集合是否为空// good if (lunchBox.isEmpty) return 'so hungry...'; if (words.isNotEmpty) return words.join(' '); // bad if (lunchBox.length == 0) return 'so hungry...'; if (!words.isEmpty) return words.join(' ');
-
推荐使用集合的高阶函数进行相关处理(如:
where
、map
)// good var aquaticNames = animals .where((animal) => animal.isAquatic) .map((animal) => animal.name);
-
避免在
Iterable.forEach()
中处理方法体编码// good for (var person in people) { ... } // bad people.forEach((person) { ... }); // 只有forEach中是函数指针, 才鼓励使用, 如下 people.forEach(print);
-
除了要改变结果类型,否则不要使用
List.from()
方法// good // Creates a List<int>: var iterable = [1, 2, 3]; // Prints "List<int>": print(iterable.toList().runtimeType); // bad // Creates a List<int>: var iterable = [1, 2, 3]; // Prints "List<dynamic>": print(List.from(iterable).runtimeType);
需要改变类型时,可使用该方法
// good var numbers = [1, 2.3, 4]; // List<num>. numbers.removeAt(1); // Now it only contains integers. var ints = List<int>.from(numbers);
-
使用
whereType()
来进行集合的类型过滤// good var objects = [1, "a", 2, "b", 3]; var ints = objects.whereType<int>(); // bad var objects = [1, "a", 2, "b", 3]; var ints = objects.where((e) => e is int); // bad var objects = [1, "a", 2, "b", 3]; var ints = objects.where((e) => e is int).cast<int>();
-
当有更方便的操作符可使用时,不要使用
cast
// good var stuff = <dynamic>[1, 2]; var ints = List<int>.from(stuff); // bad var stuff = <dynamic>[1, 2]; var ints = stuff.toList().cast<int>(); // good var stuff = <dynamic>[1, 2]; var reciprocals = stuff.map<double>((n) => 1 / n); // bad var stuff = <dynamic>[1, 2]; var reciprocals = stuff.map((n) => 1 / n).cast<double>();
-
尽量避免使用
cast
关键字-
当有更方便的操作符可使用时,不要使用
cast
// good var stuff = <dynamic>[1, 2]; var ints = List<int>.from(stuff); // bad var stuff = <dynamic>[1, 2]; var ints = stuff.toList().cast<int>(); // good var stuff = <dynamic>[1, 2]; var reciprocals = stuff.map<double>((n) => 1 / n); // bad var stuff = <dynamic>[1, 2]; var reciprocals = stuff.map((n) => 1 / n).cast<double>();
-
创建集合时,通过指定泛型类型代替
cast
// good List<int> singletonList(int value) { var list = <int>[]; list.add(value); return list; } // bad List<int> singletonList(int value) { var list = []; // List<dynamic>. list.add(value); return list.cast<int>(); }
-
遍历集合每项元素时,使用
as
代替cast
// good void printEvens(List<Object> objects) { // We happen to know the list only contains ints. for (var n in objects) { if ((n as int).isEven) print(n); } } // bad void printEvens(List<Object> objects) { // We happen to know the list only contains ints. for (var n in objects.cast<int>()) { if (n.isEven) print(n); } }
-
需要对集合中的大多数元素做操作时,使用
List.from()
代替cast
// good int median(List<Object> objects) { // We happen to know the list only contains ints. var ints = List<int>.from(objects); ints.sort(); return ints[ints.length ~/ 2]; } // bad int median(List<Object> objects) { // We happen to know the list only contains ints. var ints = objects.cast<int>(); ints.sort(); return ints[ints.length ~/ 2]; }
注:
cast() cast()
-
函数
-
使用函数声明式来绑定函数和名称
// good void main() { localFunction() { ... } } // bad void main() { var localFunction = () { ... }; }
-
能够传递函数指针时不要取传递冗余的lambda式
// good names.forEach(print); // bad names.forEach((name) { print(name); });
参数
-
在
命名可选参数
中指定默认参数时使用=
代替:
// good void insert(Object item, {int at = 0}) { ... } // bad void insert(Object item, {int at: 0}) { ... }
注:
:
作为指定默认参数值的用法,正在被废弃 -
不要显式地置顶参数默认值为
null
// good void error([String message]) { stderr.write(message ?? '\n'); } // bad void error([String message = null]) { stderr.write(message ?? '\n'); }
注: 不指定默认参数值,Dart语言机制默认指定为
null
,不需要冗余指定
变量
-
初始化变量时不要显式地置顶变量为
null
// good int _nextId; class LazyId { int _id; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } } // bad int _nextId = null; class LazyId { int _id = null; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } }
-
不要存储你能计算的值
// bad class Circle { num radius; num area; num circumference; Circle(num radius) : radius = radius, area = pi * radius * radius, circumference = pi * 2.0 * radius; } // bad class Circle { num _radius; num get radius => _radius; set radius(num value) { _radius = value; _recalculate(); } num _area; num get area => _area; num _circumference; num get circumference => _circumference; Circle(this._radius) { _recalculate(); } void _recalculate() { _area = pi * _radius * _radius; _circumference = pi * 2.0 * _radius; } } // good class Circle { num radius; Circle(this.radius); num get area => pi * radius * radius; num get circumference => pi * 2.0 * radius; }
主要出于以下方面考虑:
radius
注:这里针对的是普通计算,而对于开销较大的计算,仍然要考虑存储结果作为cache。
类成员
Dart的类成员包含成员属性和方法(静态方法和实例方法)
-
不要给成员属性设置
setter
和getter
方法,除非必须// good class Box { var contents; } // bad class Box { var _contents; get contents => _contents; set contents(value) { _contents = value; } }
-
对于只读的成员属性,尽量用
final
修饰// good class Box { final contents = []; } // bad class Box { var _contents; get contents => _contents; }
注:对于需要在构造方法之外复制的成员属性,可使用private的成员属性 + public的getter方法来满足
-
对于简单的成员变量/方法可考虑使用
=>
// good double get area => (right - left) * (bottom - top); bool isReady(num time) => minTime == null || minTime <= time; String capitalize(String name) => '${name[0].toUpperCase()}${name.substring(1)}';
但不要为了使用
=>
而强行将多行表达式进行聚合,如:// good Treasure openChest(Chest chest, Point where) { if (_opened.containsKey(chest)) return null; var treasure = Treasure(where); treasure.addAll(chest.contents); _opened[chest] = treasure; return treasure; } // bad Treasure openChest(Chest chest, Point where) => _opened.containsKey(chest) ? null : _opened[chest] = Treasure(where) ..addAll(chest.contents);
还可以对无返回值的成员使用
=>
// good num get x => center.x; set x(num value) => center = Point(value, center.y);
-
除非你必须要使用
this
避免歧义,否则不要使用它// good class Box { var value; void clear() { update(null); } void update(value) { this.value = value; } } // bad class Box { var value; void clear() { this.update(null); } void update(value) { this.value = value; } }
另,Dart语言中,构造方法里不会出现成员变量与构造方法参数同名的歧义问题,如下写法是合法的
// good class Box extends BaseBox { var value; Box(value) : value = value, super(value); }
-
尽可能在成员变量声明时进行初始化
// good class Folder { final String name; final List<Document> contents = []; Folder(this.name); Folder.temp() : name = 'temporary'; } // bad class Folder { final String name; final List<Document> contents; Folder(this.name) : contents = []; Folder.temp() : name = 'temporary'; // Oops! Forgot contents. }
构造方法
-
尽可能使用标准构造式
注:标准构造式,官方原文是
initializing formals
,参代码// good class Point { num x, y; Point(this.x, this.y); } // bad class Point { num x, y; Point(num x, num y) { this.x = x; this.y = y; } }
-
不要在标准构造式中指定类型
// good class Point { int x, y; Point(this.x, this.y); } // bad class Point { int x, y; Point(int this.x, int this.y); }
-
对于空方法体的构造方法,使用
;
来替换{}
// good class Point { int x, y; Point(this.x, this.y); } // bad class Point { int x, y; Point(this.x, this.y) {} }
-
不要使用关键字
new
Dart1中的关键字
new
是需要的,单Dart2已经将其变为可选的了。官方为了减轻升级迁移的负担,仍然支持了new
关键字,但不建议使用。// good Widget build(BuildContext context) { return Row( children: [ RaisedButton( child: Text('Increment'), ), Text('Click!'), ], ); } // bad Widget build(BuildContext context) { return new Row( children: [ new RaisedButton( child: new Text('Increment'), ), new Text('Click!'), ], ); }
-
不要使用冗余的关键字
const
// good const primaryColors = [ Color("red", [255, 0, 0]), Color("green", [0, 255, 0]), Color("blue", [0, 0, 255]), ]; // bad const primaryColors = const [ const Color("red", const [255, 0, 0]), const Color("green", const [0, 255, 0]), const Color("blue", const [0, 0, 255]), ];
异步操作
-
尽可能使用
async
和await
来替换Future
的链式风格// good Future<int> countActivePlayers(String teamName) async { try { var team = await downloadTeam(teamName); if (team == null) return 0; var players = await team.roster; return players.where((player) => player.isActive).length; } catch (e) { log.error(e); return 0; } } // bad Future<int> countActivePlayers(String teamName) { return downloadTeam(teamName).then((team) { if (team == null) return Future.value(0); return team.roster.then((players) { return players.where((player) => player.isActive).length; }); }).catchError((e) { log.error(e); return 0; }); }
-
在关键字
async
并无实际效果时不要使用它// good Future afterTwoThings(Future first, Future second) { return Future.wait([first, second]); } // bad Future afterTwoThings(Future first, Future second) async { return Future.wait([first, second]); }
以下几种场景,
async
是有实际效果的-
使用了
await
关键字 -
返回一个异步错误时,
async
+throw
是return Future.error(...)
的简写形式 -
你想在你方法的返回值中隐式包一个
Future
以上三种情况对应代码如下
// good Future usesAwait(Future later) async { print(await later); } Future asyncError() async { throw 'Error!'; } Future asyncValue() async => 'value';
-
使用了
-
考虑使用高阶函数来处理流
Streams提供了一系列高阶函数对流数据进行操作处理,建议优先考虑使用高阶函数
-
避免直接使用
Completer
对象// bad Future<bool> fileContainsBear(String path) { var completer = Completer<bool>(); File(path).readAsString().then((contents) { completer.complete(contents.contains('bear')); }); return completer.future; } // good Future<bool> fileContainsBear(String path) { return File(path).readAsString().then((contents) { return contents.contains('bear'); }); } // good Future<bool> fileContainsBear(String path) async { var contents = await File(path).readAsString(); return contents.contains('bear'); }
-
对
FutureOr<T>
对象进行消除歧义时,优先判断Future<T>
// good Future<T> logValue<T>(FutureOr<T> value) async { if (value is Future<T>) { var result = await value; print(result); return result; } else { print(value); return value as T; } } // bad Future<T> logValue<T>(FutureOr<T> value) async { if (value is T) { // 传递Future<Object>时会永远走该分支 print(value); return value; } else { var result = await value; print(result); return result; } }
以上所述就是小编给大家介绍的《Dart语言最佳实践》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【语言模型系列】实践篇:ALBERT在房产领域的实践
- go语言中interface的实践
- GO语言泛型编程实践
- 探探长链接项目的 Go 语言实践
- Go 语言在百度 App 中的实践
- 我们必须遵循的 12 个 Go 语言最佳实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。