Я хочу использовать именованные параметры в Dart для ясности. Как мне обращаться с ними?

TL; DR: Именованные параметры являются необязательными в результате осознанного выбора дизайна. Кроме поддержки официального языка, есть ли способ обеспечить (и сообщить) требуемые именованные аргументы?


Я считаю чрезвычайно полезным использовать именованные параметры при определении класса. Взять, к примеру, Ability в MMORPG:

class Ability {

  final name;
  final effectDuration;
  final recast;            // wait time until next use
  // ...
}

effectDuration и recast содержат информацию одного и того же типа (т.е. длительность времени) и, вероятно, представлены одним и тем же типом данных. Легко перепутать, какой номер идет куда. Тем не менее, они оба являются информацией, необходимой для правильности объекта, поэтому они не могут отсутствовать во время создания экземпляра.

Я мог бы просто сломать программу с помощью try-catch, чтобы обеспечить выполнение требований этих параметров, но это не похоже на удовольствие для тех, кто использует класс и не имеет представления (если не читать документы и не понимать интуитивно, что делает класс) что они необходимы.

Есть ли способ обеспечить соблюдение требования определенных именованных параметров, одновременно информируя вызывающего абонента об этом требовании и/или помогая ему правильно его использовать?

Ответ 1

Пакет meta предоставляет аннотацию @required, которая поддерживается DartAnalyzer.

Флаттер часто использует это и предоставляет @required непосредственно из import 'package:flutter/foundation.dart'

foo({@required String name}) {...}

foo(); // results in static warning

@required не проверяет, является ли переданное значение null или нет, только то, что значение действительно было передано на сайт вызова. Чтобы проверить null, вы также можете использовать assert() для проверки переданных значений

class Ability {
  Ability(this.name, this.effectDuration, this.recast) : assert(name != null), assert(effectDuration != null), assert(recast != null);
  final name;
  final effectDuration;
  final recast;            // wait time until next use
  // ...
}    

Ответ 2

Да, есть!

Вот пример:

class Ability {
  final String name;
  final Duration effectDuration;
  final bool recast;

  Ability({
    @required this.name,
    this.effectDuration = new Duration(seconds: 1),
    this.recast = false,
  }): 
    assert(name != null),
    assert(effectDuration != null);
}

Вам не нужно утверждать, что имя не равно null, но оно может быть полезно для вас.

Ответ 3

Хотя вы можете использовать пакет flutter foundation, как описано в принятом ответе, когда я работаю с классами моделей, которым не нужно знать о Flutter, я предпочитаю использовать пакет meta напрямую. Таким образом, это не создает ненужную зависимость от платформы. Это позволяет вам делиться кодом Dart даже вне Flutter.

Добавьте meta в pubspec.yaml:

dependencies:
  meta: ^1.1.7

Импортируйте его в свой файл класса:

import 'package:meta/meta.dart';

Используйте аннотацию @required в своем коде:

class Person {
  String name;
  int age;

  Person({@required this.name, this.age,});
}

Таким образом, name является обязательным параметром, а age - нет.

final person = Person(name: 'Bob');