Dart支持命名可选参数和位置可选参数。两者之间有什么区别?

另外,如何判断是否实际指定了可选参数?


当前回答

Dart有两种可选参数:named和positional。在讨论不同之处之前,让我先讨论一下相似之处。

Dart的可选参数是可选的,因为调用者在调用函数时不需要为参数指定值。

可选参数只能声明在任何必需参数之后。

可选参数可以具有默认值,当调用方未指定值时使用该值。

位置可选参数

由[]包装的参数是位置可选参数。这里有一个例子:

getHttpUrl(String server, String path, [int port=80]) {
  // ...
}

在上面的代码中,port是可选的,默认值为80。

您可以使用或不使用第三个参数调用getHttpUrl。

getHttpUrl('example.com', '/index.html', 8080); // port == 8080
getHttpUrl('example.com', '/index.html');       // port == 80

你可以为一个函数指定多个位置参数:

getHttpUrl(String server, String path, [int port=80, int numRetries=3]) {
  // ...
}

可选参数是位置参数,如果您想指定numRetries,则不能省略port。

getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', 8080);
getHttpUrl('example.com', '/index.html', 8080, 5);

当然,除非你知道8080和5是什么,否则很难说出这些看起来很神奇的数字是什么。您可以使用命名的可选参数来创建更具可读性的api。

命名可选参数

由{}包装的参数是命名的可选参数。这里有一个例子:

getHttpUrl(String server, String path, {int port = 80}) {
  // ...
}

您可以使用或不使用第三个参数调用getHttpUrl。在调用函数时,必须使用参数名。

getHttpUrl('example.com', '/index.html', port: 8080); // port == 8080
getHttpUrl('example.com', '/index.html');             // port == 80

你可以为一个函数指定多个命名形参:

getHttpUrl(String server, String path, {int port = 80, int numRetries = 3}) {
  // ...
}

因为命名形参是按名称引用的,所以它们的使用顺序可以与声明顺序不同。

getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', port: 8080);
getHttpUrl('example.com', '/index.html', port: 8080, numRetries: 5);
getHttpUrl('example.com', '/index.html', numRetries: 5, port: 8080);
getHttpUrl('example.com', '/index.html', numRetries: 5);

我相信命名参数使调用站点更容易理解,特别是当有布尔标志或脱离上下文的数字时。

检查是否提供了可选参数

不幸的是,您无法区分“未提供可选参数”和“提供默认值的可选参数”两种情况。

注意:你可以使用位置可选参数或命名可选参数,但不能在同一个函数或方法中同时使用。以下是不允许的。

thisFunctionWontWork(String foo, [String positonal], {String named}) {
  // will not work!
}

其他回答

Dart有两种可选参数:named和positional。在讨论不同之处之前,让我先讨论一下相似之处。

Dart的可选参数是可选的,因为调用者在调用函数时不需要为参数指定值。

可选参数只能声明在任何必需参数之后。

可选参数可以具有默认值,当调用方未指定值时使用该值。

位置可选参数

由[]包装的参数是位置可选参数。这里有一个例子:

getHttpUrl(String server, String path, [int port=80]) {
  // ...
}

在上面的代码中,port是可选的,默认值为80。

您可以使用或不使用第三个参数调用getHttpUrl。

getHttpUrl('example.com', '/index.html', 8080); // port == 8080
getHttpUrl('example.com', '/index.html');       // port == 80

你可以为一个函数指定多个位置参数:

getHttpUrl(String server, String path, [int port=80, int numRetries=3]) {
  // ...
}

可选参数是位置参数,如果您想指定numRetries,则不能省略port。

getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', 8080);
getHttpUrl('example.com', '/index.html', 8080, 5);

当然,除非你知道8080和5是什么,否则很难说出这些看起来很神奇的数字是什么。您可以使用命名的可选参数来创建更具可读性的api。

命名可选参数

由{}包装的参数是命名的可选参数。这里有一个例子:

getHttpUrl(String server, String path, {int port = 80}) {
  // ...
}

您可以使用或不使用第三个参数调用getHttpUrl。在调用函数时,必须使用参数名。

getHttpUrl('example.com', '/index.html', port: 8080); // port == 8080
getHttpUrl('example.com', '/index.html');             // port == 80

你可以为一个函数指定多个命名形参:

getHttpUrl(String server, String path, {int port = 80, int numRetries = 3}) {
  // ...
}

因为命名形参是按名称引用的,所以它们的使用顺序可以与声明顺序不同。

getHttpUrl('example.com', '/index.html');
getHttpUrl('example.com', '/index.html', port: 8080);
getHttpUrl('example.com', '/index.html', port: 8080, numRetries: 5);
getHttpUrl('example.com', '/index.html', numRetries: 5, port: 8080);
getHttpUrl('example.com', '/index.html', numRetries: 5);

我相信命名参数使调用站点更容易理解,特别是当有布尔标志或脱离上下文的数字时。

检查是否提供了可选参数

不幸的是,您无法区分“未提供可选参数”和“提供默认值的可选参数”两种情况。

注意:你可以使用位置可选参数或命名可选参数,但不能在同一个函数或方法中同时使用。以下是不允许的。

thisFunctionWontWork(String foo, [String positonal], {String named}) {
  // will not work!
}

颤振例子

命名参数

Duration类构造函数接受命名参数:

const Duration(
{int days = 0,
int hours = 0,
int minutes = 0,
int seconds = 0,
int milliseconds = 0,
int microseconds = 0}
)

位置参数

DateTime类的构造函数有1个必需的位置参数,7个可选的位置参数:

DateTime(
int year,
[int month = 1,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0]
)

什么时候用哪个?

对于日期/时间,如果不指定月份,那么指定一天是没有意义的。如果我告诉你星期一,你不会知道我说的是哪一个星期一。如果指定一个月而不指定一年,这是没有意义的。枣自然地由粗变细。当然,在现实中,您会假设下周一是哪一个星期一,但是程序不能这样假设。

对于Duration,指定哪个无关紧要。取值范围:1秒、1毫秒、5天。如果我告诉你等5秒,我不需要告诉你0天0小时0分5秒。

当一个函数的形参使用“paramName: value”语法指定时,它就是一个命名形参。这些参数可以通过将它们括在[和]括号中来表示为可选的。这个函数的基本演示可以在下面的Hello World程序中演示:

sayHello([String name = ' World!']) {
  print('Hello, ${name}');
}

void main() {
  sayHello('Govind');
}

从doc中我们得到位置形参和命名形参都是可选的,这意味着它们都可以不存在。

在我看来,命名参数比位置参数更严格。例如,如果你声明这样一个方法:

String say({String from, String msg})

上面的from和msg是命名参数,当你调用方法say时,你必须使用say(from: "xx", msg: "xx")。钥匙不能没有。

但是,如果使用位置参数,则可以自由使用。

以下方法:

getBMI(float weight, float height, {int age = 80}) {
  // method body
}

体重和身高为位置参数,年龄为命名参数。

我们将像下面这样调用该方法:

getBMI(65, 175, age: 35);

正如你所看到的,maned参数使呼叫站点更容易理解。