简体   繁体   中英

Right way of using optional named parameters in Dart class constructor

Dart noob here. I have defined a class as follows:

class Balance{
  String ccy;
  late Money receivable;
  late Money payable;
  Balance(this.ccy, {Money? receivable, Money? payable}){
   this.receivable = receivable??Money.from(0, code:ccy);
   this.payable = payable??Money.from(0, code:ccy);
  };
}

The reasons I have defined it as above are:

  1. I want the payables and receivables fields never to be null but, at the same time, I don't want to always have to pass a value for these fields whenever a Balance object is created.
  2. I want the ccy argument to be required and use that argument to initialize payables and receivables fields to 0.

Is this the right way to define the Balance class? Is there a better way?

The idiomatic way to write this code is:

class Balance{
  final String currency;
  final Money receivable;
  final Money payable;
  Balance(this.currency, {Money? receivable, Money? payable}) 
      : receivable = receivable ?? Money.from(0, code: currency),
        payable = payable ?? Money.from(0, code: currency);
}

(plus documentation!)

By initializing the fields in the initializer list (which exists for exactly that reason), you can make the fields final and non-nullable an still initialize them using computations that rely on arguments.

I'd never use late for a public field. In this case, you actually do initialize it immediately in the constructor, so there is no risk of clients of the class accidentally reading the field before it's initialized. They just don't know that, all they see is that the field is late . Even if you make the field final , a late final field with no initializer will still have a setter visible in the public API.

If you actually want the fields to be mutable, then you can remove the final . Then being late isn't as bad, as long as you still ensure that the fields are initialized before anyone else sees the object. Then you still usually do what I did here instead and avoid the late .

The one case where you might need late is when you need to create a cyclic structure of final fields. Something like

class MainNode {
  final String name;
  late final SubNode _sub;
  MainNode(this.name, String data) {
    _sub = SubNode(this, data);
  }
  SubNode get sub => _sub; 
}
class SubNode {
  final MainNode parent;
  String data;
  SubNode(this.parent, this.data);
}

For something like this, where you need to create the sub-node after you have access to this , a late final field makes sense, and ensures that _sub is actually only written once. (I avoid exposing the _sub setter in the API by making it private, though.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM