Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Dart member


May 23, 2021 Dart Code style guide


Table of contents


Members

It is better to use constructors than static methods when creating instances.

Constructors are usually new const and their primary purpose is to return an instance of the class (or at least implement its interface).

In Dart you no longer need to create an instance in a static way. Named constructors enable you to illustrate how objects are built, and farm constructors allow you to build instances of sub-classes and sub-interfaces where appropriate.

Still, some methods of creating new objects with some skill don't look like constructors. F or example, although Uri.parse() is a static method, it creates a Uri object from a given parameter. Accordingly, classes that implement Builder pattern may look better than classes that use static methods.

However, in most cases, you should use constructors instead of static methods, even if it appears to be lengthy. When others use your class to create objects, they prefer to use constructors to create instances in the usual way.

class Point {    // good
  num x, y;
  Point(this.x, this.y);
  Point.polar(num theta, num radius)
      : x = radius * math.cos(theta),
        y = radius * math.sin(theta);
}
class Point {    // bad
  num x, y;
  Point(this.x, this.y);
  static Point polar(num theta, num radius) {
    return new Point(radius * math.cos(theta),
        radius * math.sin(theta));
  }
}

For empty constructor bodies, use ; Instead {}

In Dart, a constructor with an empty function body can end with a sign. T his is necessary for constructors of the const type. Other constructors should do the same, given consistency and simplicity.

class Point {    // good
  int x, y;
  Point(this.x, this.y);
}
class Point {    // bad
  int x, y;
  Point(this.x, this.y) {}
}

Be sure to put the call to super() at the end of the constructor initialization list.

The initialization of the fields will be in the order in which they appear in the constructor initialization list. If you place a super() the initialization in the parent class is initialized before the rest of the child class initializes the rest of the list.

This does not mean that the contents of the parent class constructor body will be executed. T his is often done after all initializations have been completed, independent of super() The impact of initializing the list is diminishing, so super() little effect on its position in the list.

It's a good idea to get into the habit of putting parent constructors at the end of sub-class constructors, which helps improve code consistency. And when the parent class constructor body is running, its readability increases, even to the effect of running.

View(Style style, List children)    // good
    :_children = children,
     super(style){
View(Style style, List children)    // bad
    :super(style),
     -children = children {

For operations that change property values, call setter to perform.

If the name of a function begins with set this usually means that the function may be a setter function. More precisely, it is a better choice to use setter instead of functions for the following cases:

  • A single parameter is used.
  • Changed a state in an object.
  • There is a corresponding getter. F or consumers, it is strange that there are some states that can be modified but not seen. (The guideline, in turn, is wrong, and it's enough to set up getter without defining setter for it)
  • It's idempotent. When you call setter twice with the same value, the second call should contain no other actions.
  • In order to run fast. Users expect foo.bar = value they execute quickly.
rect.width = 3;    // good
button.visible = false;

You should avoid encapsulating fields in getter and setter for "security."

In Java and in C#, we typically encapsulate all the fields in getter and setter (or in the properties of C#), even if the actions we need are directly corresponding to the fields. I n fact, if you need to do more on the member, you can not touch the call point. T his is because calling a setter function in Java is different from a direct operation field. The use of properties and direct action fields in C# is incompatible.

There is no such restriction in Dart. T he fields and getter/setter are exactly the same. You can use the field in the class first, and then encapsulate it in getter and setter without altering any code that uses the field.

class Box {    // good
  var contents;
}
class Box {    // bad
  var _contents;
  get contents => _contents;
  set contents(value) {
    _contents = value;
  }
}

It's better to use the public final field instead of defining a private field and then setting up a public setter for it.

If you have a field that is visible outside of code and you don't assign it a value (and you won't change it outside of the constructor), in most cases the easiest way is to fianl

class Box {    // good
  final contents = [];
}
class Box {    // bad
  var _contents;
  get contents => _contents;
}

When a member's function body returns a single expression, consider => . . . to define those members.

In addition to function expressions, Dart also allows you => a class using . This is a good habit for defining simple members that calculate and return a single value.

get width => right - left;    // good
bool ready(num time) => minTime == null || minTime <= time;
containsValue(String value) => getValues().contains(value);

Even if the function body is not a single => you can also use . . . but you think it would be better to split the line expression into multiple lines of code, so it would look better to put the entire function body in return declaration return.

You should avoid returning this from the function in order to use a regular this

For continuous function calls, it is a good practice to use function cascading.

var buffer = new StringBuffer()    // good
  ..write("one")
  ..write("two")
  ..write("three");
var buffer = new StringBuffer();    // bad
buffer
  .write("one")
  .write("two")
  .write("three");

You should avoid using Boolean-type parameters unless their meaning is very obvious.

Unlike other types, Boolean values typically use literal values directly rather than Boolean variables. L ike numbers we usually encapsulate them in named constants, but when we use them we usually use true false This makes it difficult for others to understand what boolean values mean in your call statement:

new Task(true);    // bad
new Task(false);
new ListBox(false, true, true);

Conversely, when calling, if you use named arguments, named constructors, or named constants, it looks comfortable.

new Task.oneShot();    // bad
new Task.repeating();
new ListBox(scroll: true, showScrollbars: true);