To learn about Flutter and Dart coding specifications?

Keywords: Android REST Javascript

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!!!

Finally, I wish you all a happy life.~

Posted by dprichard on Mon, 05 Aug 2019 01:15:39 -0700