【问题标题】:Callback with generic type parameter in Dart在 Dart 中使用泛型类型参数回调
【发布时间】:2019-09-14 19:30:22
【问题描述】:

我正在尝试定义一个需要接受泛型参数并返回相同类型值的回调函数。请记住,以下示例是我实际需要的过度简化版本。

final T Function<T>(T value) self = (value) => value

这会导致以下错误,我似乎无法摆脱。

The argument type '(dynamic) → dynamic' can't be assigned to the parameter type '<T>(T) → T'

dart(argument_type_not_assignable)

似乎唯一可行的方法是给值一个类型,但这违背了首先使用类型参数的目的。

final T Function<T>(T value) same = <String>(value) => value;

我需要它是通用的,以便调用者可以传递它期望的类型作为回报。我还需要将它存储在一个变量中,所以我可以将它作为回调函数传递。

如果这不能直接实现,您是否知道任何解决方法?提前谢谢你。


如果要求不明确,这里有一个更完整的示例。

abstract class Provider<T> {
  T get bar;
}

class StringProvider extends Provider<String> {
  String get bar => 'bar';
}

class NumberProvider extends Provider<int> {
  int get bar => 42;
}

class Foo {
  final T Function<T>(Provider<T> provider) provide;

  const Foo({ this.provide });
}

test() {
  final foo = Foo(provide: (provider) => provider.bar);

  String strValue = foo.provide(StringProvider()); // should be 'bar'
  int numValue = foo.provide(NumberProvider()); // should be 42
}

烦人的是,Dart 实际上知道 foo.provide(StringProvider()) 会返回一个字符串,而使用 NumberProvider 确实会返回一个整数,然而,对于变量实际赋值的行,错误仍然上升.

final foo = Foo(provide: (provider) => provider.bar);
The argument type '(dynamic) → dynamic' can't be assigned to the parameter type '<T>(Provider<T>) → T'

【问题讨论】:

    标签: generics dart type-parameter dart-2


    【解决方案1】:

    事实证明,我可以通过在定义值时给出任何具体类型来欺骗类型检查器。请注意,dynamic 是不允许的,但其他的都可以。

    final foo = Foo(provide: <int>(provider) => provider.bar);
    

    这既消除了错误,又允许provide 方法在调用时返回正确的类型。

    总之,这似乎是类型检查器的一个简单缺点,而不是使用现有语言功能实际上不可能或难以实现的东西。我将在该语言的 GitHub 存储库上提出一个问题,以便进一步调查和讨论。


    更新 #1:问题已在 GitHub 上打开。


    更新 #2:问题已解决,事实证明该行为是设计使然。引用 SDK 团队的Erik Ernst

    试试这个:final foo = Foo(provide: &lt;T&gt;(Provider&lt;T&gt; provider) =&gt; provider.bar);!

    问题是您将一个非泛型函数传递给 Foo 构造函数,而您应该传递一个泛型函数。泛型函数类型和非泛型函数类型之间没有子类型关系,所以根据类型检查器你还不如传递一个String,这就是'can't be assigned to'消息的原因。

    事实证明,只需在参数列表前添加&lt;T&gt;(而不是原始解决方法中的int)即可解决问题。

    final foo = Foo(provide: <T>(provider) => provider.bar);
    

    这迫使 Dart 了解 provider 的类型为 Provider&lt;T&gt;,并且该方法将返回类型为 T 的值,从而使我们免于使用具体类型并仍然摆脱错误。

    【讨论】:

      【解决方案2】:

      你必须定义一个独立的泛型函数:

      class Foo {
        final T Function<T>(Provider<T> provider) provide;
      
        const Foo({ this.provide });
      }
      
      main() {
        T f<T>(Provider<T> provider) => provider.bar;
        final foo = Foo(provide: f);
      
        String strValue = foo.provide(StringProvider()); // should be 'bar'
        int numValue = foo.provide(NumberProvider()); // should be 42
      }
      

      【讨论】:

      • 不幸的是,这定义了一个函数——例如,你将在一个类中使用的函数——而不是一个独立的变量。我需要它是后者,这样我就可以存储它并将它作为回调函数传递。我已将此评论添加到我原来的问题中。
      • 如果没有你的加入,我猜self 是一个顶级变量。
      • 很抱歉给您带来了困惑,感谢您的提醒。您更新的答案让我更接近,但仍然不是一路。给Foo 类型参数可以消除错误,但是这种方式foo.provide 只是返回dynamic 而不管传递的参数。
      • 我已经添加了我自己的答案,因为我设法找到了一种方法来欺骗类型检查器,让我得到我需要的结果。无论如何,我感谢您提供帮助。
      猜你喜欢
      • 2020-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多