This article is from the official Dart documentation.

The specification is mainly divided into four parts:

  • Style specification
  • Document specification
  • Use standard
  • The design specification

Each section has numerous examples, each of which begins with one of these five words:

  • DO: indicates a practice that you need to follow
  • DONT: Thats a very bad thing to do
  • PREFER: In most cases, it is recommended
  • AVOID: Something that should be avoided in most situations
  • -Leonard: CONSIDER a course of action that requires your own deliberation

In my opinion, coding habits are individual and there is no single best solution.

If you’re developing alone, you don’t need to worry about these issues, but if your code needs to be shown to others, or if you need to collaborate with others, coding specifications are absolutely necessary.

Below, some of the most basic, most typical and high incidence situations will be selected from official documents as specifications.

✅ is a positive approach, ❌ is a negative approach

Style specification

named

DO: Classes, enumerations, type definitions, and generics all need to use camel – case nomenclature

✅ class SliderMenu {... } class HttpRequest { ... } typedef Predicate<T> = bool Function(T value);Copy the code

This should also be the case when using annotations

✅ class Foo {const Foo([arg]); } @Foo(anArg) class A { ... } @Foo() class B { ... }Copy the code

However, to annotate a class constructor, you may need to create an annotation variable that begins with a lower case

✅ const foo = foo (); @foo class C { ... }Copy the code

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';
Copy the code
❌ library pegparser. SourceScanner; import'file-system.dart';
import 'SliderMenu.dart';
Copy the code

DO: Names that will be referenced using as conversions should also be lowercase underscores

✅

import 'dart:math' as math;
import 'package:angular_components/angular_components'
    as angular_components;
import 'package:js/js.dart' as js;
Copy the code
❌

import 'dart:math' as Math;
import 'package:angular_components/angular_components'
    as angularComponents;
import 'package:js/js.dart' as JS;
Copy the code

DO: Variable names, method names, and parameter names should all start with a lower case camel case nomenclature

✅

var item;

HttpRequest httpRequest;

void align(bool clearItems) {
  // ...
}
Copy the code
✅

const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');

class Dice {
  static final numberGenerator = Random();
}
Copy the code
❌

const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');

class Dice {
  static final NUMBER_GENERATOR = Random();
}

Copy the code

Curly braces

DO: When there is only one if statement with no else, and it is well represented on one line, curly braces are not needed

if (arg == null) return defaultValue;
Copy the code

But if a line is too tight, curly braces are needed:

if(overflowChars ! = other.overflowChars) {return overflowChars < other.overflowChars;
}
Copy the code
if(overflowChars ! = other.overflowChars)return overflowChars < other.overflowChars;
Copy the code

Document specification

DO: In the Dart comment, it is recommended to use // rather than //

✅

/// The number of characters in this chunk when unsplit.
int get length => ...
Copy the code
❌

// The number of characters in this chunk when unsplit.
int get length => ...
Copy the code

As for why it was done, officials say it was for historical reasons and they thought it would be easier to read in some cases.

DO: Documentation comments should begin with a simple sentence

✅ /// Deletes the file at [path] from the file system. Void delete(String path) {... Deletes the file at [path] from the file system. }Copy the code
❌

/// 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) {
  ...
}
Copy the code

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) {
  ...
}
Copy the code
❌

/// 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) {
  ...
}
Copy the code

DO: Use square brackets to declare parameters, return values, and thrown exceptions

/// /// @param name the name of the flag. // @param abbr the  abbreviationfor 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) => ...
Copy the code
✅ // 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) => ...
Copy the code

Use standard

Rely on

PREFER: It is recommended to import dependencies using relative paths

If the project structure is as follows:

├─ trash ├─ trash ├─ trash ├─ trashCopy the code

You want to import utils.dart in api.dart

✅

import 'src/utils.dart';
Copy the code
❌

import 'package:my_package/src/utils.dart';
Copy the code

The assignment

DO: use?? Perform a conversion to the null value

In the dart?? The operator assigns a value when it is null. The following data

if(optionalThing? .isEnabled) {print("Have enabled thing.");
}
Copy the code

When optionalThing is empty, the null pointer is abnormal.

So here’s the explanation. ? The isEnabled operator is called only if the optionalThing is not empty. If the optionalThing is empty, it returns null by default

Here’s how to do it

✅ // If you want to return when emptyfalseWords: optionalThing? .isEnabled ??false; // If you want to return ture when null: optionalThing? .isEnabled ??true;
Copy the code
❌ optionalThing? .isEnabled ==true; optionalThing? .isEnabled ==false;
Copy the code

string

Using + to concatenate two strings is not recommended in DART

DO: Use the enter key to separate strings directly

✅ raiseAlarm ('ERROR: Parts of the spaceship are on fire. Other '
    'parts are overrun by martians. Unclear which are which.');
Copy the code
❌ raiseAlarm ('ERROR: Parts of the spaceship are on fire. Other ' +
    'parts are overrun by martians. Unclear which are which.');
Copy the code

PREFER: use ${} to concatenate strings with variable values

'Hello, $name! You are ${year - birth} years old.';
Copy the code
'Hello, ' + name + '! You are ' + (year - birth).toString() + ' y... ';
Copy the code

A collection of

Dart creates an empty extensible List in two ways: [] and List(); There are three ways to create an empty HashMap: {}, Map(), and LinkedHashMap().

If you want to create an unextensible list or some other custom collection type, be sure to use constructors.

DO: Create collections using as simple literals as possible

✅

var points = [];
var addresses = {};
Copy the code
❌

var points = List();
var addresses = Map();
Copy the code

When you want to specify a type

✅

var points = <Point>[];
var addresses = <String, Address>{};
Copy the code
❌

var points = List<Point>();
var addresses = Map<String, Address>();
Copy the code

DON’t: DON’t use it.lenghtTo indicate that a set is empty

if (lunchBox.isEmpty) return 'so hungry... ';
if (words.isNotEmpty) return words.join(' ');
Copy the code
if (lunchBox.length == 0) return 'so hungry... ';
if(! words.isEmpty)return words.join(' ');
Copy the code

CONSIDER using higher-order methods to transform sequences

var aquaticNames = animals
    .where((animal) => animal.isAquatic)
    .map((animal) => animal.name);
Copy the code

AVOID using iterable.foreach () with function literals

The forEach () function is widely used in JavaScript because the built-in for-in loop doesn’t do what you normally want. In Dart, if you want to iterate over a sequence, the conventional approach is to use loops.

for (var person in people) {
  ...
}
Copy the code
❌ people. ForEach ((person) {... });Copy the code

DON’t: Do not use list.from () unless you intend to change the type of the 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);
Copy the code
❌ // Create a List<int>: var iterable = [1, 2, 3]; / / output"List<dynamic>":
print(List.from(iterable).runtimeType);
Copy the code

DO: Use whereType() to filter a collection by type

❌

var objects = [1, "a", 2, "b", 3];
var ints = objects.where((e) => e is int);
Copy the code
❌

var objects = [1, "a", 2, "b", 3];
var ints = objects.where((e) => e is int).cast<int>();

Copy the code
✅

var objects = [1, "a", 2, "b", 3];
var ints = objects.whereType<int>();
Copy the code

parameter

DO: use=Set default values for the parameters

✅ void insert(Object item, {int at = 0}) {... }Copy the code
❌ void insert(Object item, {int at: 0}) {... }Copy the code

DON’t: Do not set the default value of the parameter to NULL

✅

void error([String message]) {
  stderr.write(message ?? '\n');
}
Copy the code
❌

void error([String message = null]) {
  stderr.write(message ?? '\n');
}
Copy the code

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; }}Copy the code
✅ class Circle {num radius; Circle(this.radius); num get area => pi * radius * radius; Num get circumference => PI * 2.0 * RADIUS; }Copy the code

Members of the

DON’t: DON’t write unnecessary getters and setters

✅ class Box {var contents; }Copy the code
❌ class Box {var _contents; get contents => _contents;setcontents(value) { _contents = value; }}Copy the code

The constructor

DO: Use a simple initialization form whenever possible

❌ class Point {num x, y; Point(num x, num y) { this.x = x; this.y = y; }}Copy the code
✅ class Point {num x, y; Point(this.x, this.y); }Copy the code

DON’t: DON’t use itnewTo create an object

Dart does not require new

✅

Widget build(BuildContext context) {
  return Row(
    children: [
      RaisedButton(
        child: Text('Increment'),
      ),
      Text('Click! '),]); }Copy the code
❌

Widget build(BuildContext context) {
  return new Row(
    children: [
      new RaisedButton(
        child: new Text('Increment'),
      ),
      new Text('Click! '),]); }Copy the code

DON’t: DON’t use extraconstModify the object

✅ const primaryColors = [Color()"red", [255, 0, 0]),
  Color("green", [0, 255, 0]),
  Color("blue", [0, 0, 255]),];Copy the code
❌ const primaryColors = const [const Color()"red", const [255, 0, 0]),
  const Color("green", const [0, 255, 0]),
  const Color("blue", const [0, 0, 255]),
];
Copy the code

Exception handling

DO: userethrowRethrow an exception

❌

try {
  somethingRisky();
} catch (e) {
  if(! canHandle(e)) throw e; handle(e); }Copy the code
✅

try {
  somethingRisky();
} catch (e) {
  if(! canHandle(e)) rethrow; handle(e); }Copy the code

The design specification

AVOID: AVOID having a method return this in order to implement a streaming call

✅

var buffer = StringBuffer()
  ..write('one')
  ..write('two')
  ..write('three');
Copy the code
❌ var buffer = StringBuffer().write('one')
    .write('two')
    .write('three');
Copy the code

AVOID using FutureOr<T> as the return type

✅

Future<int> triple(FutureOr<int> value) async => (await value) * 3;
Copy the code
❌

FutureOr<int> triple(FutureOr<int> value) {
  if (value is int) return value * 3;
  return (value as Future<int>).then((v) => v * 3);
}
Copy the code

AVOID using a bool as an input parameter

❌ new Task (true);
new Task(false);
new ListBox(false.true.true);
new Button(false);
Copy the code
✅ Task. OneShot (); Task.repeating(); ListBox(scroll:true, showScrollbars: true);
Button(ButtonState.enabled);
Copy the code

DON’t: DON’t customize= =Nulls in the operator method

✅ class Person {final String name; // ··· bool operator ==(other) => other is Person && name == other.name; int gethashCode => name.hashCode;
}
Copy the code
❌ class Person {final String name; // ··· bool operator ==(OTHER) => OTHER! = null && ... }Copy the code

The appendix

At last.

To learn about Flutter, you also need to know about this beautiful app😄

Todo-List