+
来链接它们。推荐的写法git
print( 'ERROR: Parts of the spaceship are on fire. Other ' 'parts are overrun by martians. Unclear which are which.');
不推荐的写法github
print('ERROR: Parts of the spaceship are on fire. Other ' + 'parts are overrun by martians. Unclear which are which.');
若是要插入是一个简单的标识符,而且后面没有紧跟着的字母,则应省略 {}
缓存
推荐的写法异步
'Hi, $name!' "Wear your wildest $decade's outfit." //标识符后面有紧跟着的字母了 加上大括号用以区分 'Wear your wildest ${decade}s outfit.'
不推荐的写法async
'Hi, ${name}!' "Wear your wildest ${decade}'s outfit."
当表达式的值能够为真、假或null,而且您须要将结果传递给不接受null的对象时,此规则适用。一个常见的状况是一个判断空值的方法调用被用做条件:ide
不推荐的写法函数
if (optionalThing?.isEnabled) { print("Have enabled thing."); }
若是optionalThing为空,此代码将抛出异常。(if只支持判断bool值,不支持null)要解决这个问题,您须要将null值“转换”为true或false。虽然您可使用==来完成此操做,但咱们建议使用?? :性能
推荐的写法学习
//若是你想要optionalThing是空值时返回false optionalThing?.isEnabled ?? false; //若是你想要optionalThing是空值时返回true optionalThing?.isEnabled ?? true;
不推荐的写法ui
// 若是你想要optionalThing是空值时返回false optionalThing?.isEnabled == true; // 若是你想要optionalThing是空值时返回true optionalThing?.isEnabled != false;
PS:若是这里你有些不理解,能够先阅读一下做者以前的文章<u>Flutter基础——Dart语法</u>,学习一下'?' '??' '??=' 的使用
两种操做都会产生一样的结果,并且作的都是正确的事情,但首选??操做符,主要有三个缘由。
??运算符清楚地代表,代码与空值有关。
Dart 集合中原生支持了四种类型:list, map, queue, 和 set。 下面是应用于集合的最佳实践。
两种方式来构造一个空的可变 list : []
和 List()
。 一样,有三种方式来构造一个空的Map map:{}
, Map()
, 和 LinkedHashMap()
。
若是想建立一个固定不变的 list 或者其余自定义集合类型,这种状况下你须要使用构造函数。 不然,使用字面量语法更加优雅。 核心库中暴露这些构造函数易于扩展,可是一般在 Dart 代码中并不使用构造函数。
推荐的写法
var points = []; var addresses = {};
不推荐的写法
var points = List(); var addresses = Map();
若是须要的话,你能够提供一个泛型。
推荐的写法
var points = <Point>[]; var addresses = <String, Address>{};
不推荐的写法
var points = List<Point>(); var addresses = Map<String, Address>();
注意,对于集合类的 命名 构造函数则不适用上面的规则。 List.from()
、 Map.fromIterable()
都有其使用场景。 若是须要一个固定长度的结合,使用 List()
来建立一个固定长度的 list 也是合理的。
.length
来判断一个集合是否为空。经过调用 .length
来判断集合是否包含内容是很是低效的。相反,Dart 提供了更加高效率和易用的 getter 函数:.isEmpty
和.isNotEmpty
。 使用这些函数并不须要对结果再次取非(list.length ! =0)
推荐的写法
if (lunchBox.isEmpty) return 'so hungry...'; if (words.isNotEmpty) return words.join(' ');
不推荐的写法
if (lunchBox.length == 0) return 'so hungry...'; if (!words.isEmpty) return words.join(' ');
List.from()
除非想修改结果的类型。给定一个可迭代的对象,有两种常见方式来生成一个包含相同元素的 list:
var copy1 = iterable.toList(); var copy2 = List.from(iterable);
推荐的写法
明显的区别是前一个更短。 更重要的区别在于第一个保留了原始对象的类型参数:
// 建立一个 List<int>: var iterable = [1, 2, 3]; // 输出 "List<int>": print(iterable.toList().runtimeType);
不推荐的写法
// 建立一个 List<int>: var iterable = [1, 2, 3]; // 输出 "List<dynamic>": print(List.from(iterable).runtimeType);
若是你想要改变原始对象的类型参数,那么能够调用 List.from()
:
推荐的写法
var numbers = [1, 2.3, 4]; // List<num>. numbers.removeAt(1); // 如今集合里只包含int型 var ints = List<int>.from(numbers);
可是若是你的目的只是复制可迭代对象而且保留元素原始类型, 或者并不在意类型,那么请使用 toList()
。
=
来分隔参数名和参数默认值。因为遗留缘由,Dart 同时支持 :
和 =
做为参数名和默认值的分隔符。 为了与可选的位置参数保持一致,请使用 =
。
推荐的写法
void insert(Object item, {int at = 0}) { ... }
不推荐的写法
void insert(Object item, {int at: 0}) { ... }
null
值。若是你建立了一个可选参数,那么就不要为其赋默认值, Dart 默认使用 null
做为默认值,因此这里不须要为其 null
赋值语句。
推荐的写法
void error([String message]) { stderr.write(message ?? '\n'); }
不推荐的写法
void error([String message = null]) { stderr.write(message ?? '\n'); }
null
值。在Dart中,未自动显式初始化的变量或字段将初始化为 null
。 语言保证了赋值的可靠性。在 Dart 中没有“未初始化内存”的概念。 因此使用 = null
是多余的。
推荐的写法
int _nextId; class LazyId { int _id; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } }
不推荐的写法
int _nextId = null; class LazyId { int _id = null; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } }
在设计类的时候,你经常但愿暴露底层状态的多个表现属性。 经常你会发如今类的构造函数中计算这些属性,而后保存起来:
不推荐的写法
class Circle { num radius; num area; num circumference; Circle(num radius) : radius = radius, area = pi * radius * radius, circumference = pi * 2.0 * radius; }
上面的代码有两个不妥之处。首先,这样浪费了内存。 严格来讲面积和周长是缓存数据。 他们保存的结果能够经过已知的数据计算出来。 他们减小了 CPU 消耗却增长了内存消耗。 咱们尚未权衡,到底存不存在性能问题?
更坏的状况是,上面的代码是 错的 。上面的缓存是无效的— 你如何知道何时缓存失效了须要从新计算? 在这里,咱们永远不会重新计算,即便 radius
是可变的。 你能够给 radius
设置一个不一样的值,可是 area
和 circumference
仍是以前的值。
为了正确处理缓存失效,咱们须要这样作:
不推荐的写法
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; } }
这须要编写、维护、调试以及阅读更多的代码。 若是你一开始这样写代码:
推荐的写法
class Circle { num radius; Circle(this.radius); num get area => pi * radius * radius; num get circumference => pi * 2.0 * radius; }
上面的代码更加简洁、使用更少的内存、减小出错的可能性。 它尽量少的保存了表示圆所须要的数据。 这里没有字段须要同步,由于这里只有一个有效数据源。
在 Dart 中,对象成员能够是函数(方法)或数据(实例变量)。 下面是关于对象成员的最佳实践。
推荐的写法
class Box { var contents; }
不推荐的写法
class Box { var _contents; get contents => _contents; set contents(value) { _contents = value; } }
final
关键字来建立只读属性若是你有一个变量,对于外部代买来讲只能读取不能修改, 最简单的作法就是使用 final
关键字来标记这个变量。
推荐的写法
class Box { final contents = []; }
不推荐的写法
class Box { var _contents; get contents => _contents; }
this.
,在重定向命名函数和避免冲突的状况下除外。只有当局部变量和成员变量名字同样的时候,你才须要使用 this.
来访问成员变量。 只有两种状况须要使用 this.
。其中一种状况是要访问的局部变量和成员变量命名同样的时候:
推荐的写法
class Box { var value; void clear() { update(null); } void update(value) { this.value = value; } }
不推荐的写法
class Box { var value; void clear() { this.update(null); } void update(value) { this.value = value; } }
若是一个字段不依赖于构造函数中的参数, 则应该在定义的时候就初始化字段值。 这样能够减小须要的代码并能够确保在有多个构造函数的时候你不会忘记初始化该字段。
不推荐的写法
class Folder { final String name; final List<Document> contents; Folder(this.name) : contents = []; Folder.temp() : name = 'temporary'; // Oops! Forgot contents. }
推荐的写法
class Folder { final String name; final List<Document> contents = []; Folder(this.name); Folder.temp() : name = 'temporary'; }
固然,对于变量取值依赖构造函数参数的状况以及不一样的构造函数取值也不同的状况, 则不适合本条规则。
许多字段直接使用构造函数参数来初始化,如:
不推荐的写法
class Point { num x, y; Point(num x, num y) { this.x = x; this.y = y; } }
为了初始化一个字段,咱们须要取_四_次 x
。使用下面的方式会更好:
推荐的写法
class Point { num x, y,z; Point(this.x, this.y,{this.z}); }
这里的位于构造函数参数以前的 this.
语法被称之为初始化形式(initializing formal)。 有些状况下这没法使用这种形式。特别是,这种形式下在初始化列表中没法看到变量。 可是若是能使用该方式,就应该尽可能使用。(若是使用命名参数)
;
来替代空的构造函数体 {}
。在 Dart 中,没有具体函数体的构造函数可使用分号结尾。 (事实上,这是不可变构造函数的要求。)
推荐的写法
class Point { int x, y; Point(this.x, this.y); }
不推荐的写法
class Point { int x, y; Point(this.x, this.y) {} }
new
。建立对象不要使用new
推荐的写法
Widget build(BuildContext context) { return Row( children: [ RaisedButton( child: Text('Increment'), ), Text('Click!'), ], ); }
不推荐的写法
Widget build(BuildContext context) { return new Row( children: [ new RaisedButton( child: new Text('Increment'), ), new Text('Click!'), ], ); }
显式的异步代码是很是难以阅读和调试的, 即便使用很好的抽象(好比 future)也是如此。 这就是为什么 Dart 提供了 async
/await
。 这样能够显著的提升代码的可读性而且让你能够在异步代码中使用语言提供的全部流程控制语句。
推荐的写法
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; } }
不推荐写法
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; }); }
在 Dart 中标识符有三种类型。
UpperCamelCase
每一个单词的首字母都大写,包含第一个单词。lowerCamelCase
每一个单词的首字母都大写,除了第一个单词, 第一个单词首字母小写,即便是缩略词。lowercase_with_underscores
只是用小写字母单词,即便是缩略词, 而且单词之间使用 _
链接。UpperCamelCase
风格命名类型。Classes(类名)、 enums(枚举类型)、 typedefs(类型定义)、 以及 type parameters(类型参数)应该把每一个单词的首字母都大写(包含第一个单词), 不使用分隔符。
class SliderMenu { ... } class HttpRequest { ... } typedef Predicate = bool Function<T>(T value);
库
,包
,文件夹
,源文件
中使用 lowercase_with_underscores
方式命名。lowercase_with_underscores
风格命名库和源文件名。推荐的写法
library peg_parser.source_scanner; import 'file_system.dart'; import 'slider_menu.dart';
不推荐的写法
library pegparser.SourceScanner; import 'file-system.dart'; import 'SliderMenu.dart';
lowercase_with_underscores
风格命名导入的前缀。推荐的写法
import 'dart:math' as math; import 'package:angular_components/angular_components' as angular_components; import 'package:js/js.dart' as js;
不推荐的写法
import 'dart:math' as Math; import 'package:angular_components/angular_components' as angularComponents; import 'package:js/js.dart' as JS;
lowerCamelCase
风格来命名其余的标识符。类成员、顶级定义、变量、参数以及命名参数等 除了第一个单词,每一个单词首字母都应大写,而且不使用分隔符。
推荐的写法
var item; HttpRequest httpRequest; void align(bool clearItems) { // ... }
首字母大写缩略词比较难阅读, 特别是多个缩略词连载一块儿的时候会引发歧义。 例如,一个以 HTTPSFTP
开头的名字, 没有办法判断它是指 HTTPS FTP 仍是 HTTP SFTP 。
为了不上面的状况,缩略词和缩写词要像普通单词同样首字母大写, 两个字母的单词除外。 (像 ID 和 Mr. 这样的双字母缩写词仍然像通常单词同样首字母大写。)
推荐的写法
HttpConnectionInfo uiHandler IOStream HttpRequest Id DB
不推荐的写法
HTTPConnection UiHandler IoStream HTTPRequest ID Db
译者注:
acronyms
:首字母缩略词,指取若干单词首字母组成一个新单词,如:HTTP = HyperText Transfer Protocolabbreviations
: 缩写词,指取某一单词的部分字母(或其余缩短单词的方式)表明整个单词,如:ID = identification推荐的写法
defaultTimeout
不推荐的写法
kDefaultTimeout
dartfmt
格式化你的代码。格式化是一项繁琐的工做,尤为在重构过程当中特别耗时。 庆幸的是,你没必要担忧。 咱们提供了一个名为 dartfmt 的优秀的自动代码格式化程序,它能够为你完成格式化工做。 咱们有一些关于它适用的规则的 文档 , Dart 中任何官方的空格处理规则由 dartfmt 生成。
其他格式指南用于 dartfmt 没法修复的一些规则。
这样能够避免 dangling else (else悬挂)的问题。
if (isWeekDay) { print('Bike to work!'); } else { print('Go dancing or read a book!'); }
这里有一个例外:一个没有 else
的 if
语句, 而且这个 if
语句以及它的执行体适合在一行中实现。 在这种状况下,若是您愿意,能够不用括号
if (arg == null) return defaultValue;
可是,若是执行体包含下一行,请使用大括号:
推荐的写法
if (overflowChars != other.overflowChars) { return overflowChars < other.overflowChars; }
不推荐的写法
if (overflowChars != other.overflowChars) return overflowChars < other.overflowChars;
若是有时间推荐看一看官网上详细的Effective Dart,https://www.dartcn.com/guides/language/effective-dart/
做者把一些flutter经常使用的dart语法规范总结了出来,一些语法作了补充。
整洁的代码是创造一个好工程的前提