【问题标题】:Creating function with variable number of arguments or parameters in Dart在 Dart 中创建具有可变数量的参数或参数的函数
【发布时间】:2012-11-23 18:35:26
【问题描述】:

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

例如,在纯 JavaScript 中,我们可以这样做(借用自 here):

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 中,该代码不会运行。有没有办法在飞镖中做同样的事情?如果没有,这是路线图上的内容吗?

【问题讨论】:

标签: dart


【解决方案1】:

你现在不能这样做。

我真的不知道 varargs 是否会回来 - 他们前段时间在那里,但 have been removed

但是,可以使用Emulating functions 模拟 varargs。见下面代码sn-p。

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

【讨论】:

  • 哇,这是一个非常巧妙的解决方案。我确实喜欢 dart 处理参数的方式,但这对喜欢它的开发人员有帮助。
  • 非常好!我没有过多研究该语言的 InvocationMirror 部分,因此感谢您提供了一个很好的示例。我稍微调整了你的答案,以创建一个适用于当前版本的 Dart 的版本。
  • 我复制并粘贴了上面的代码,但是在superHeroes('UberMan', 'Exceptional Woman', 'The Hunk'); 行中出现Too many positional arguments: 0 expected, but 3 found. Try removing the extra arguments.dart(extra_positional_arguments) 错误。我必须将final superHeroes = VarargsFunction((arguments) 更改为final dynamic superHeroes = VarargsFunction((arguments) 进行修复。
  • Dart 不是 Javascript!请不要使用“final x = MyFunction(() {...}); 之类的语法,它不是惯用的 Dart,除非你真的知道自己在做什么,否则不要使用 dynamic
  • @SergeyMolchanovsky 为什么它不是惯用的? VarargsFunction 是一个将函数作为构造函数参数的类,本例中的函数是匿名函数。这就像调用list.map((x) {...}); 一样惯用。虽然此解决方案肯定会被归类为 hack,但它需要将对象键入为 dynamic 才能工作,因此这是对它的有效使用。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    我对 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&lt;String&gt;
    • 需要检查noSuchMethod() 中的成员名称,如果更改方法名称,您很可能会忘记更改“superheroes”字符串。
    • 反射使代码路径更难追踪。

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

    【讨论】:

    • 还有一个我认为必须提到的问题:它只有在你传递多个参数时才会起作用。如果你只传递一个字符串,你将调用原来的 superheroes 方法并且 noSuchMethod 机制将被忽略。
    【解决方案4】:

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

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

    【讨论】:

    • 然后该方法必须对十个参数中的每一个进行特殊检查(如果 arg1 != null ...,如果 arg2 != null ...)?恶心!
    • 我已经说过这是一个 hack,而且 API 设计者可能愿意为此付出代价。
    • 它不可扩展。
    • 不,不是。我在答案中承认了这一点。也就是说,经过这么多年,我仍然认为这是迄今为止提供的所有答案中最好的答案——当然,除了简单地使用列表。
    【解决方案5】:

    这个版本:

    1. 适用于位置参数和关键字参数。
    2. 支持输入返回值。
    3. 适用于现代 Dart。
    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}
    }
    

    感谢 Alexandre 的answer

    【讨论】:

      【解决方案6】:

      只要你不太注重语法简洁,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 间接让我知道英语中存在像 brevity 这样的词。

      【讨论】:

      • 这是我个人在打开此页面之前想出的。在这里看到所有答案后,我选择继续使用这个解决方案,因为另一个解决方案看起来像一个 hack。我不喜欢每个函数的定义方式。是的,我不太喜欢简洁的语法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      • 2018-02-02
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多