43

我正在寻找一种在 Dart 中创建具有可变数量的参数或参数的函数的方法。我知道我可以创建一个数组参数,但我不想这样做,因为我正在开发一个语法简洁很重要的库。

例如,在纯 JavaScript 中,我们可以做这样的事情(从这里借用):

function superHeroes() {
  for (var i = 0; i < arguments.length; i++) {
    console.log("There's no stopping " + arguments[i]);
  }
}

superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');

但是,在 dart 中,该代码不会运行。有没有办法在飞镖中做同样的事情?如果不是,这是路线图上的内容吗?

4

6 回答 6

38

你暂时不能这样做。

我真的不知道varargs是否会回来——它们之前就在那里,但已被删除

但是,可以使用Emulating functions来模拟varargs。请参阅下面的代码片段。

typedef OnCall = dynamic Function(List arguments);

class VarargsFunction {
  VarargsFunction(this._onCall);
  
  final OnCall _onCall;

  noSuchMethod(Invocation invocation) {
    if (!invocation.isMethod || invocation.namedArguments.isNotEmpty)
      super.noSuchMethod(invocation);
    final arguments = invocation.positionalArguments;
    return _onCall(arguments);
  }
}

main() {
  final superHeroes = VarargsFunction((arguments) {
    for (final superHero in arguments) {
      print("There's no stopping ${superHero}");
    }
  }) as dynamic;
  superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
于 2012-12-05T21:07:15.440 回答
9

Dart 确实间接支持 var-args,只要您不太注重语法简洁性。

void testFunction([List<dynamic> args=[]])
{
  for(dynamic arg:args)
  {
    // Handle each arg...
  }
}

testFunction([0, 1, 2, 3, 4, 5, 6]);
testFunction();
testFunction([0, 1, 2]);

注意:您可以对命名参数执行相同的操作,但您必须在内部处理事情,以防万一用户(该函数的用户;可能是您)决定不向该命名参数传递任何值。


我要感谢@Ladicek 间接让我知道英语中存在像 简洁这样的词。

于 2020-05-26T18:20:31.313 回答
7

我对 Alexandre Ardhuin 的回答进行了一些尝试,发现我们可以调整一些东西以使其在当前版本的 Dart 中工作:

class VarArgsClass {
  noSuchMethod(InvocationMirror invocation) {
    if (invocation.memberName == 'superheroes') {
      this.superheroes(invocation.positionalArguments);
    }
  }

  void superheroes(List<String> heroNames) {
    for (final superHero in heroNames) {
      print("There's no stopping ${superHero}!");
    }
  }
}

main() {
  new VarArgsClass().superheroes('UberMan', 'Exceptional Woman', 'The Hunk');
}

这有很多问题,包括:

  • superheroes()由于签名与您的参数不匹配,因此无论您在哪里调用都会生成警告。
  • 需要进行更多的手动检查,以确保传递给超级英雄的参数列表确实是List<String>.
  • 如果您更改方法名称,则需要检查成员名称noSuchMethod()使得您更有可能忘记更改“超级英雄”字符串。
  • 反射使代码路径更难追踪。

但是,如果您对所有这些问题都满意,那么就可以完成工作。

于 2012-12-05T23:17:03.023 回答
6

这个版本:

  1. 适用于位置和关键字参数。
  2. 支持输入返回值。
  3. 适用于现代飞镖。
typedef VarArgsCallback = void Function(List<dynamic> args, Map<String, dynamic> kwargs);

class VarArgsFunction {
  final VarArgsCallback callback;
  static var _offset = 'Symbol("'.length;

  VarArgsFunction(this.callback);

  void call() => callback([], {});

  @override
  dynamic noSuchMethod(Invocation inv) {
    return callback(
      inv.positionalArguments,
      inv.namedArguments.map(
        (_k, v) {
          var k = _k.toString();
          return MapEntry(k.substring(_offset, k.length - 2), v);
        },
      ),
    );
  }
}

void main() {
    dynamic myFunc = VarArgsFunction((args, kwargs) {
      print('Got args: $args, kwargs: $kwargs');
    });
    myFunc(1, 2, x: true, y: false); // Got args: [1, 2], kwargs: {x: true, y: false}
}

谢谢,亚历山大的回答

于 2019-10-30T14:01:48.393 回答
3

如果您真的很喜欢简洁的语法,只需声明一个带有 10 个可选位置参数的函数/方法即可。不太可能有人会用超过 10 个参数来调用它。

如果它听起来像一个黑客,那是因为它一个黑客。但我看到 Dart 团队也在做同样的事情 :-)

例如

void someMethod(arg0, [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) {
  final args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];

  args.removeWhere((value) => value == null);

  /* do something the the args List */
  print(args);
}
于 2012-12-06T05:21:58.760 回答
2

对于您编写的示例,我认为您最好使用列表。对于那个很抱歉!

我正在查看 dartbug.com,但我没有看到对此的功能请求。绝对欢迎您创建一个!

于 2012-12-05T23:01:13.123 回答