为了清楚起见,我想在 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
// ...
effectDuration
和 recast
都携带相同类型的信息(即持续时间)并且可能由相同的数据类型表示。很容易混淆哪个数字去哪里。但是,它们都是对对象正确性至关重要的信息,因此在实例化过程中不能丢失。
我可以通过 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 安全更新的一部分添加到语言中。这意味着您获得的是编译器强制执行的非空值,而不是分析器检查的值;这使得空检查完全多余。
这意味着该代码实际上与下面的旧代码相同,只是您不必担心断言抛出作为name
、effectDuration
和recast
的值不能 为空。
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,但它可能对您有用。
【讨论】:
assert
s 充当运行时故障保险,对吗?理想情况下,@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
是可选的,而 effectDuration
和 recast
是必需的。
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 中使用命名参数。我应该如何处理它们?的主要内容,如果未能解决你的问题,请参考以下文章