dart official document [Effective Dart]
Specification is divided into four parts:
- Style specifications
- Document specification
- Terms of Use
- Design Specification
Each section has a number of examples, each example will in the following five words as some of the beginning:
- DO : You need to follow the practice of representation
- DONT : represents this approach is very bad
- PREFER : In most cases, the recommended practice
- AVOID : In most cases, the practice should be avoided
- CONSIDER : you need to practice discretion
In my opinion, coding habits are personal, and no such thing as the best solution.
If you are a person develop, of course, we do not need to care about these issues, but if your code needs to show to others, or if you need to develop synergies with others, coding standards it is very necessary.
The following will be selected from the official document, the most basic, the most typical, a higher incidence in some cases, as a specification.
✅ expressed positive approach, ❌ represents the opposite approach
Style specifications
name
DO: class, enumeration, type definitions, as well as generic, require the use of capital at the start hump nomenclature
✅
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate<T> = bool Function(T value);
In use annotations, it should be like this
✅
class Foo {
const Foo([arg]);
}
@Foo(anArg)
class A { ... }
@Foo()
class B { ... }
But when a class constructor add annotations, you may need to create a lowercase beginning of the comment variables
✅
const foo = Foo();
@foo
class C { ... }
DO: Naming library package, directory, dart files should be lowercase underlined
✅
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
❌
library pegparser.SourceScanner;
import 'file-system.dart';
import 'SliderMenu.dart';
DO: Use as a reference to the name of the conversion should also be underlined lowercase
✅
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;
DO: variable name, method, parameter names should be lowercase beginning of the hump nomenclature
✅
var item;
HttpRequest httpRequest;
void align(bool clearItems) {
// ...
}
✅
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
❌
const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');
class Dice {
static final NUMBER_GENERATOR = Random();
}
curly braces
DO: Only when a statement and if there is no else, and can be a good show in a row, you can not braces
✅
if (arg == null) return defaultValue;
However, if one line to show more reluctant, then you need to use the braces:
✅
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
❌
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;
Document specification
DO: In the comments dart, the more recommended to use /// instead of //
✅
/// The number of characters in this chunk when unsplit.
int get length => ...
❌
// The number of characters in this chunk when unsplit.
int get length => ...
As for why, the official said that due to historical reasons and they feel that in some cases seem easier to read.
DO: Doc comments should begin with a simple word
✅
/// Deletes the file at [path] from the file system.
void delete(String path) {
...
}
❌
/// Depending on the state of the file system and the user's permissions,
/// certain operations may or may not be possible. If there is no file at
/// [path] or it can't be accessed, this function throws either [IOError]
/// or [PermissionError], respectively. Otherwise, this deletes the file.
void delete(String path) {
...
}
DO: The first sentence of the comments and other content separates
✅
/// Deletes the file at [path].
///
/// Throws an [IOError] if the file could not be found. Throws a
/// [PermissionError] if the file is present but could not be deleted.
void delete(String path) {
...
}
❌
/// Deletes the file at [path]. Throws an [IOError] if the file could not
/// be found. Throws a [PermissionError] if the file is present but could
/// not be deleted.
void delete(String path) {
...
}
DO: Use square brackets to declare parameters, return values, and exceptions thrown
❌
/// Defines a flag with the given name and abbreviation.
///
/// @param name The name of the flag.
/// @param abbr The abbreviation for the flag.
/// @returns The new flag.
/// @throws ArgumentError If there is already an option with
/// the given name or abbreviation.
Flag addFlag(String name, String abbr) => ...
✅
/// Defines a flag.
///
/// Throws an [ArgumentError] if there is already an option named [name] or
/// there is already an option using abbreviation [abbr]. Returns the new flag.
Flag addFlag(String name, String abbr) => ...
Terms of Use
rely
PREFER: recommended to use a relative path to import dependence
If the project is structured as follows:
my_package
└─ lib
├─ src
│ └─ utils.dart
└─ api.dart
Want to import utils.dart in api.dart in
✅
import 'src/utils.dart';
❌
import 'package:my_package/src/utils.dart';
Assignment
** DO: Use null values ?? will do a conversion **
In the dart will represent operator ?? ?? behind it a value when a data value is blank
❌
if (optionalThing?.isEnabled) {
print("Have enabled thing.");
}
When optionalThing is empty, the above will be a null pointer anomaly.
Explain here. ?. Operators equivalent of doing a sentence air operation only when optionalThing not empty when the only call isEnabled parameters, when optionalThing is empty, then default returns null, if used in determining the sentence to die naturally
Here's the right approach
✅
// 如果为空的时候你想返回false的话:
optionalThing?.isEnabled ?? false;
// 如果为空的时候你想返回ture的话:
optionalThing?.isEnabled ?? true;
❌
optionalThing?.isEnabled == true;
optionalThing?.isEnabled == false;
String
In the dart is not recommended to use two strings are connected to +
DO: Use directly the Enter key partition string
✅
raiseAlarm(
'ERROR: Parts of the spaceship are on fire. Other '
'parts are overrun by martians. Unclear which are which.')
❌
raiseAlarm('ERROR: Parts of the spaceship are on fire. Other ' +
'parts are overrun by martians. Unclear which are which.');
PREFER: $ {} is connected using the variable value string
✅
'Hello, $name! You are ${year - birth} years old.';
❌
'Hello, ' + name + '! You are ' + (year - birth).toString() + ' y...';
set
dart create an empty Extensible List two ways: [] and List (); Create an empty HashMap three ways: {}, the Map (), and a LinkedHashMap ()
If you want to create a non-expandable list or some other custom collection types, so be sure to use the constructor.
DO: create a collection using a simple literal as possible
✅
var points = [];
var addresses = {};
❌
var points = List();
var addresses = Map();
When you want to specify the type of
✅
var points = <Point>[];
var addresses = <String, Address>{};
❌
var points = List<Point>();
var addresses = Map<String, Address>();
DO NOT: Do not use the .lenght to represent a set is empty
✅
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(' ');
CONSIDER: Consider using higher-order conversion method sequence
var aquaticNames = animals
.where((animal) => animal.isAquatic)
.map((animal) => animal.name);
AVOID: Avoid using Iterable.forEach functions with literals ()
forEach () function is widely used in JavaScript, because the built-for-in loop can not achieve the effect you usually want. In Dart, if you want iterative sequence, then the conventional method is to use a loop.
✅
for (var person in people) {
...
}
❌
people.forEach((person) {
...
});
DO NOT: Do not use List.from () unless you plan to change the type of results
There are two ways to get Iterable, respectively List.from () and Iterable.toList ()
✅
// 创建一个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);
DO: Use WhereType () to set a filtered type
❌
var objects = [1, "a", 2, "b", 3];
var ints = objects.where((e) => e is int);
❌
var objects = [1, "a", 2, "b", 3];
var ints = objects.where((e) => e is int).cast<int>();
✅
var objects = [1, "a", 2, "b", 3];
var ints = objects.whereType<int>();
parameter
DO: using a default value to the parameter setting =
✅
void insert(Object item, {int at = 0}) { ... }
❌
void insert(Object item, {int at: 0}) { ... }
DO NOT: Do not use the default value of the parameter is set to null
✅
void error([String message]) {
stderr.write(message ?? '\n');
}
❌
void error([String message = null]) {
stderr.write(message ?? '\n');
}
variable
AVOID: Avoid the calculated value can be stored
❌
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;
}
member
DO NOT: Do not write unnecessary getter and setter
✅
class Box {
var contents;
}
❌
class Box {
var _contents;
get contents => _contents;
set contents(value) {
_contents = value;
}
}
Constructor
DO: Whenever possible, use a simple form initialization
❌
class Point {
num x, y;
Point(num x, num y) {
this.x = x;
this.y = y;
}
}
✅
class Point {
num x, y;
Point(this.x, this.y);
}
DO NOT: Do not use new to create an object
dart does not require 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!'),
],
);
}
DO NOT: Do not use excess const modified objects
✅
const primaryColors = [
Color("red", [255, 0, 0]),
Color("green", [0, 255, 0]),
Color("blue", [0, 0, 255]),
];
❌
const primaryColors = const [
const Color("red", const [255, 0, 0]),
const Color("green", const [0, 255, 0]),
const Color("blue", const [0, 0, 255]),
];
Exception Handling
: Use rethrow rethrows
❌
try {
somethingRisky();
} catch (e) {
if (!canHandle(e)) throw e;
handle(e);
}
✅
try {
somethingRisky();
} catch (e) {
if (!canHandle(e)) rethrow;
handle(e);
}
design
AVOID: Avoid To achieve the streaming method to return this call and let
✅
var buffer = StringBuffer()
..write('one')
..write('two')
..write('three');
❌
var buffer = StringBuffer()
.write('one')
.write('two')
.write('three');
AVOID: Avoid using FutureOr as the return type
✅
Future<int> triple(FutureOr<int> value) async => (await value) * 3;
❌
FutureOr<int> triple(FutureOr<int> value) {
if (value is int) return value * 3;
return (value as Future<int>).then((v) => v * 3);
}
AVOID: Avoid as an input parameter values directly bool
❌
new Task(true);
new Task(false);
new ListBox(false, true, true);
new Button(false);
✅
Task.oneShot();
Task.repeating();
ListBox(scroll: true, showScrollbars: true);
Button(ButtonState.enabled);
DO NOT: Do not empty == operator sentenced method in a custom
✅
class Person {
final String name;
// ···
bool operator ==(other) => other is Person && name == other.name;
int get hashCode => name.hashCode;
}
❌
class Person {
final String name;
// ···
bool operator ==(other) => other != null && ...
}
At last
If you think the article is well written give a praise chant? If you think there need to be improved, please give me a message. Will be serious inquiry, insufficiently corrected. Thank you.
I hope you can read this and look forward to share my future will update the technology of dry cargo, thank you for your support!
Here, I share the video and data from a philosophical level framework to analyze the share for everyone to sort out the many years of experience in architecture, nearly a month preparatory latest record, I believe that this video will give you a different inspiration, reward
Receive mode: Get a free bit architecture video material please me
+ + Forwarding thumbs attention, the first time to obtain the latest knowledge points
Android architects of the road is long, encourage each other with it!