In the official dart document [Effective Dart]
The norms are mainly divided into four parts:
- Style specification
- Document specification
- Usage Specification
- design code
Each section has many examples. Each example begins with some of the following five words:
- DO: Represents what you need to follow
- DONT: That means it's very bad.
- PREFER: In most cases, recommended practices
- AVOID: In most cases, practices that should be avoided
- CONSIDER: What you need to think about
In my opinion, coding habits vary from person to person, and there is no so-called best solution.
If you develop by yourself, you certainly don't need to care about these issues, but if your code needs to be presented to others, or if you need to work with others, coding specifications are necessary.
Next, we will select the most basic, typical and high incidence cases from the official documents as the normative explanation.
Express positive practices and negative practices
Style specification
name
DO: Classes, enumerations, type definitions, and generics all require a hump nomenclature starting with capitals
✅ class SliderMenu { ... } class HttpRequest { ... } typedef Predicate<T> = bool Function(T value);
This should also be the case when using annotations
✅ class Foo { const Foo([arg]); } @Foo(anArg) class A { ... } @Foo() class B { ... }
However, when adding annotations to a class constructor, you may need to create an annotation variable at the beginning of lowercase
✅ const foo = Foo(); @foo class C { ... }
DO: Named libraries, packages, directories, and dart files should all be lowercase and 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: Names to be referenced using as conversion should also be lowercase underscored
✅ 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 name should be hump nomenclature at the beginning of lowercase
✅ 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 brackets
DO: When there is only one if statement and there is no else, and it can be displayed well in one line, you don't need curly braces.
✅ if (arg == null) return defaultValue;
But if the display in one line is reluctant, curly brackets are needed:
✅ if (overflowChars != other.overflowChars) { return overflowChars < other.overflowChars; }
❌ if (overflowChars != other.overflowChars) return overflowChars < other.overflowChars;
Document specification
DO: In dart's comments, it's more recommended to use /// rather than//
✅ /// 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, officials say it's because of historical reasons and because they think it's easier to read in some cases.
DO: Document comments should begin with a concise sentence
✅ /// 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: Separate the first sentence of the comment from the rest
✅ /// 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 thrown exceptions
❌ /// 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) => ...
Usage Specification
rely on
PREFER: Recommended relative path import dependencies
If the project structure is as follows:
my_package └─ lib ├─ src │ └─ utils.dart └─ api.dart
Want to import utils.dart in api.dart
✅ import 'src/utils.dart';
❌ import 'package:my_package/src/utils.dart';
assignment
DO: Use?? Make a conversion of null values
In dart, the?? operator indicates that a value is assigned when it is empty?? The following data
❌ if (optionalThing?.isEnabled) { print("Have enabled thing."); }
When optionalThing is empty, there will be an exception to the null pointer.
Here's a description. Operator is equivalent to a null operation. Only when optionalThing is not null will the isEnabled parameter be invoked. When optionalThing is null, null will be returned by default.
Here's the right way to do it
✅ // If you want to return false when it's empty: optionalThing?.isEnabled ?? false; // If you want to return to ture when it's empty: optionalThing?.isEnabled ?? true;
❌ optionalThing?.isEnabled == true; optionalThing?.isEnabled == false;
Character string
In dart, it is not recommended to use + to connect two strings
DO: Directly separating strings using the Enter key
✅ 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: Use ${} to connect strings to variable values
✅ 'Hello, $name! You are ${year - birth} years old.';
❌ 'Hello, ' + name + '! You are ' + (year - birth).toString() + ' y...';
aggregate
There are two ways to create an empty extensible List in dart: [] and List(); there are three ways to create an empty HashMap: {}, Map(), and LinkedHashMap()
If you want to create non-extensible lists or other custom collection types, you must use constructors.
DO: Create collections using simple literal quantities whenever possible
✅ var points = []; var addresses = {};
❌ var points = List(); var addresses = Map();
When you want to specify a type
✅ var points = <Point>[]; var addresses = <String, Address>{};
❌ var points = List<Point>(); var addresses = Map<String, Address>();
DON'T: Don't use the. length method to indicate that a collection 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 methods to transform sequences
var aquaticNames = animals .where((animal) => animal.isAquatic) .map((animal) => animal.name);
AVOID: Avoid using Iterable.forEach() with function literals
The forEach () function is widely used in JavaScript because the built-in for-in loop can't achieve the effect you usually want. In Dart, the usual way to iterate over sequences is to use loops.
✅ for (var person in people) { ... }
❌ people.forEach((person) { ... });
DON'T: Do not use List.from() unless you intend to change the type of result
There are two ways to get Iterable, List.from() and Iterable.toList().
✅ // Create a List <int>: var iterable = [1, 2, 3]; // Output "List < int>": print(iterable.toList().runtimeType);
❌ // Create a List <int>: var iterable = [1, 2, 3]; // Output "List < dynamic >": print(List.from(iterable).runtimeType);
DO: Use whereType() to filter a collection with types
❌ 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: Use = to set default values for parameters
✅ void insert(Object item, {int at = 0}) { ... }
❌ void insert(Object item, {int at: 0}) { ... }
DON'T: Do not set the default value of the parameter to null
✅ void error([String message]) { stderr.write(message ?? '\n'); }
❌ void error([String message = null]) { stderr.write(message ?? '\n'); }
variable
AVOID: Avoid storing computable values
❌ 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
DON'T: Don't write unnecessary getter s and setter s
✅ class Box { var contents; }
❌ class Box { var _contents; get contents => _contents; set contents(value) { _contents = value; } }
Constructor
DO: Use simple initialization forms whenever possible
❌ 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); }
DON'T: Don't use new to create objects
new is not required in dart
✅ 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!'), ], ); }
DON'T: Don't use redundant const s to decorate 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
DO: Rethrow the exception using rethrow
❌ try { somethingRisky(); } catch (e) { if (!canHandle(e)) throw e; handle(e); }
✅ try { somethingRisky(); } catch (e) { if (!canHandle(e)) rethrow; handle(e); }
Design
AVOID: Avoid returning methods to this for streaming calls
✅ var buffer = StringBuffer() ..write('one') ..write('two') ..write('three');
❌ var buffer = StringBuffer() .write('one') .write('two') .write('three');
AVOID: Avoid using FutureOr < T > 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 using bool values directly as input parameters
❌ 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);
DON'T: Do not empty in the custom == operator method
✅ 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 && ... }
Last
If you think the article is well written, give it a compliment? If you think it's worth improving, please leave me a message. We will inquire carefully and correct the shortcomings. Thank you.
I hope you can forward, share and pay attention to me, and update the technology dry goods in the future. Thank you for your support! ___________
Forwarding + Praise + Concern, First Time to Acquire the Latest Knowledge Points
Android architects have a long way to go. Let's work together.
The following wall cracks recommend reading!!!
- Android Learning Notes Reference (Knock on the Blackboard!!)
- "Winter is not over," Ali P9 architecture to share Android essential technical points, so that you get soft offer!
- Three years after graduation, how did I become a 30W senior Android developer from a 10W drag engineer?
- Tencent T3 Taurus gives you an understanding of the development trend of Android in 2019 and the necessary technical points!
- Eight years of Android development, from code farmer to architect to share my technological growth path, to encourage!
Finally, I wish you all a happy life.~