为了清楚起见,我想在 Dart 中使用命名参数。我应该如何处理它们?

Posted

技术标签:

【中文标题】为了清楚起见,我想在 Dart 中使用命名参数。我应该如何处理它们?【英文标题】:I want to use named parameters in Dart for clarity. How should I handle them? 【发布时间】:2018-09-20 22:44:07 【问题描述】:

TL;DR:由于a conscious design choice,命名参数是可选的。如果没有官方语言支持,有没有办法强制(并通知)所需的命名参数?


我发现在定义类时使用命名参数非常有用。以 MMORPG 中的 Ability 为例:

class Ability 

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

effectDurationrecast 都携带相同类型的信息(即持续时间)并且可能由相同的数据类型表示。很容易混淆哪个数字去哪里。但是,它们都是对对象正确性至关重要的信息,因此在实例化过程中不能丢失。

我可以通过 try-catch 来破坏程序以强制执行这些参数的要求,但这对于使用该类并且不知道的人来说听起来并不有趣(缺乏阅读文档并直观地理解什么)课程确实)他们是必需的。

有什么方法可以强制执行某些命名参数的要求,同时设法通知调用者所述要求和/或帮助他们正确使用它?

【问题讨论】:

【参考方案1】:

meta 包提供了 DartAnalyzer 支持的 @required 注释。

Flutter 经常使用这个,直接从import 'package:flutter/foundation.dart' 提供@required

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
  // ...
    

【讨论】:

值得补充的是,flutter 有不同的参数约定:始终使用命名参数。 我也希望 Dart 团队在 Dart 2 之后改变参数的工作方式。 大小写可选命名参数 - 我在颤振中使用 dart 类,代码如下:class MyDataObject final int anInt;最终字符串 aString;最终双 aDouble; MyDataObject( this.anInt = 1, this.aString = 'Old!', this.aDouble = 2.0, );在 this.anInt = 1, this.aString = 'Old!' 之前出现需要“添加所需关键字”的错误并且 this.aDouble = 2.0,请提出问题所在以及我们如何解决它。谢谢。 断言解决方案在 NULL SAFETY 中对我不起作用。有什么建议吗?请分享。谢谢。【参考方案2】:

[更新] Dart 2.0 的新版本

在 dart 2.0 中,required 关键字已作为 null 安全更新的一部分添加到语言中。这意味着您获得的是编译器强制执行的非空值,而不是分析器检查的值;这使得空检查完全多余。

这意味着该代码实际上与下面的旧代码相同,只是您不必担心断言抛出作为nameeffectDurationrecast 的值不能 为空。

class Ability 
  final String name;
  final Duration effectDuration;
  final bool recast;
  final String? description;

  Ability(
    required this.name,
    this.effectDuration = Duration(seconds: 1),
    this.recast = false,
    this.description,
  );

在 Dart 2.0 之前

是的,有!

这是一个例子:

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

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

您不必断言 name 不等于 null,但它可能对您有用。

【讨论】:

asserts 充当运行时故障保险,对吗?理想情况下,@required 注释应该在用户错误地调用构造函数时向用户抛出一些警告。很好,谢谢! 在编译时,如果你不传递name:something,它会抛出一个错误,但它不知道something是否为空。断言在运行时执行此操作,但仅用于调试构建(因此它不会减慢您的生产构建速度!) 大小写可选命名参数 - 我在颤振中使用 dart 类,代码如下:class MyDataObject final int anInt;最终字符串 aString;最终双 aDouble; MyDataObject( this.anInt = 1, this.aString = 'Old!', this.aDouble = 2.0, );在 this.anInt = 1, this.aString = 'Old!' 之前出现需要“添加所需关键字”的错误并且 this.aDouble = 2.0,请提出问题所在以及我们如何解决它。谢谢。 此解决方案不适用于 NULL SAFATY @Kamlesh 我已经更新了空安全示例。这似乎不对;您的代码中一定还有其他内容,因为您发布的内容对我来说很好。我建议使用更完整的代码示例(理想情况下可在 DartPad 中重现)打开一个新问题,而不是评论 2 年前的问题。【参考方案3】:

虽然您可以按照接受的答案中的描述使用颤振 foundation 包,但当我使用不需要了解 Flutter 的模型类时,我更喜欢直接使用 meta 包。这样就不会对框架产生不必要的依赖。这允许您在 Flutter 之外共享 Dart 代码。

将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');

更新:

在即将发布的 Dart 版本中,应默认添加 required 关键字,因此根本不需要导入。

【讨论】:

required 关键字的任何更新。我不知何故无法从文档中找到它。 @Sisir,它将附带空安全更新。公测计划于今年年底进行,预计明年初进入稳定通道。 如何不隐式要求没有默认值的参数? @RichardHaven,目前默认为null【参考方案4】:

从 2.12 开始,具有空安全性,您可以使用 required 关键字(而不是 @required)。也不需要导入任何额外的包。

在此示例中,命名参数 name 是可选的,而 effectDurationrecast 是必需的。

class Ability 
  final name;
  final effectDuration;
  final recast;

  Ability(this.name, required this.effectDuration, required this.recast);

更新pubspec.yaml,例如:

environment:
  sdk: ">=2.12.0-0  <3.0.0"

参考资料:

    Sound null safety How does @required compare to the new required keyword?

【讨论】:

【参考方案5】:

具有空安全性:

不可为空的命名参数:

您需要标记命名参数required 或提供默认值,甚至将其标记为late。例如:

class Foo 
  final int a;
  final int b;
  late final int c; // Mark late and provide value later.

  Foo(
    required this.a, // Mark required.
    this.b = 0, // Provided a default value.
  );

可空命名参数:

你不需要任何特殊的东西来处理它们。

class Foo 
  final int? z;

  Foo(
    this.z,
  );

【讨论】:

【参考方案6】:

如果你想声明一个空变量但里面有方法,你可以:

1)使用late关键字

2) 声明可能的类型null 返回示例:int? number;

3)将变量初始化为空,例如:

  List listOfNumbers = [];
  Map mapOfPerson1 = ;

所以你可以使用变量的方法给它们添加值

【讨论】:

以上是关于为了清楚起见,我想在 Dart 中使用命名参数。我应该如何处理它们?的主要内容,如果未能解决你的问题,请参考以下文章

Dart - 使用Map命名参数

为了清楚起见,将图例添加到 ggplot

为了清楚起见,如何将 MainActivity 功能拆分为另一个类?

Dart StreamController 有两个参数

Dart:Dart 如何匹配类的构造函数中的命名参数?

带参数的 Dart Singleton(全局应用记录器)