【问题标题】:How to call a named constructor from a generic function in Dart/Flutter如何从 Dart/Flutter 中的泛型函数调用命名构造函数
【发布时间】:2019-03-19 09:00:16
【问题描述】:

我希望能够从通用函数内部构造一个对象。我尝试了以下方法:

abstract class Interface
{
  Interface.func(int x);
}
class Test implements Interface
{
  Test.func(int x){}
}
T make<T extends Interface>(int x)
{
  // the next line doesn't work
  return T.func(x);
}

但是,这不起作用。我收到以下错误消息:The method 'func' isn't defined for the class 'Type'

注意:我不能使用镜子,因为我正在使用带有颤振的飞镖。

【问题讨论】:

    标签: generics constructor dart flutter


    【解决方案1】:

    Dart 不支持从泛型类型参数实例化。使用命名构造函数还是默认构造函数都没有关系(T() 也不起作用)。

    在服务器上可能有一种方法可以做到这一点,dart:mirrors(反射)可用(我自己还没有尝试过),但在 Flutter 或浏览器中不可用。

    您需要维护类型到工厂函数的映射

    void main() async {
      final double abc = 1.4;
      int x = abc.toInt();
      print(int.tryParse(abc.toString().split('.')[1]));
    //  int y = abc - x;
      final t = make<Test>(5);
      print(t);
    }
    
    abstract class Interface {
      Interface.func(int x);
    }
    
    class Test implements Interface {
      Test.func(int x) {}
    }
    
    /// Add factory functions for every Type and every constructor you want to make available to `make`
    final factories = <Type, Function>{Test: (int x) => Test.func(x)};
    
    T make<T extends Interface>(int x) {
      return factories[T](x);
    }
    

    【讨论】:

    • 很遗憾这是不可能的,因为那会非常有用。
    • 我想知道将这个功能添加到 dart 是否存在技术限制。我其实不知道。
    • 这主要是关于工作量和增加的复杂性是否值得。 Dart 团队正在努力使 Dart 变得更好,这是经常出现的事情。我想他们最终会解决这个问题,但目前似乎正在开发其他具有更好成本/价值比的功能。
    • 谢谢,这是一个非常有用的解决方法。
    • 有趣的是,Flutter Fetch data from the internet 教程显示了 fromJson 方法,然后 各种 线程尝试在泛型类型上调用它失败。我不明白为什么&lt;T implements X&gt; 不能保证 T 有例如由X (T.fromJson(...)) 声明的fromJson
    【解决方案2】:

    Günter Zöchbauer 出色答案的变体并使用 Dart 2.15 中的新构造函数分离功能可能是向通用函数添加一个额外参数以提供构造函数(如果需要,使用 Test.new 作为默认构造函数)。

    T make2<T extends Interface>(int x, T Function(int) constructor)
    {
      return constructor(x);
    }
    
    make2<Test>(5, Test.func);
    
    // Default constructor
    make<Test>(5, Test.new);
    

    T Function(int) constructor 参数是一个函数,它接受一个int 参数并返回类型T

    你也可以在没有构造函数的情况下完成这个,但是(至少对我来说)这有点太多了,无法解析。

    make<Test>(5, (int x) => Test.func(x));
    

    这还有一个有用的属性,即如果开发人员在不更改参数的情况下复制和粘贴函数,他们应该通过静态分析来提醒他们(因为 AnotherTest 不返回 Test),而不是只在运行时发现工厂时列表与类型进行比较。

    // ERROR: The argument type 'AnotherTest Function(int)' can't be 
    // assigned to the parameter type 'Test Function(int)'
    make2<AnotherTest>(5, Test.func);
    

    【讨论】:

      猜你喜欢
      • 2018-12-03
      • 1970-01-01
      • 1970-01-01
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-30
      • 2020-10-10
      相关资源
      最近更新 更多