generics - 如何使用未出现在第一个参数列表中的类型参数来改进 Scala 的类型推断?

标签 generics scala parameters type-inference

为了说明我的观点,这里有一个例子:

abstract class Wrapper[A](wrapped: A) {

  protected def someCondition: Boolean

  def fold[B](whenTrue: => B)(whenFalse: => B): B =
    if (someCondition) whenTrue else whenFalse

}

我正在尝试根据包装类型 A 上定义的任意条件添加一个 fold 方法。上面代码的问题是它无法编译,尽管它可能返回 Any:

wrapper.fold("hi")(42)

因为当编译器到达第二个参数列表时,B 已经被推断为 String。假设我们不想编写类型注释。我们可以尝试将 fold 更改为:

def fold[B, B0 >: B](whenTrue: => B)(whenFalse: => B0): B0

但这不起作用,因为B0已经在第一个参数列表的末尾被解析为String,尽管它根本没有出现在里面!当然,简单的解决方案是使用单个参数列表,但为了示例,假设我想保留两个参数列表并尝试使其工作......理想情况下,我们应该能够延迟B0的分辨率。如果我们能写出这样的东西那就太好了:

def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0

但不幸的是这不起作用。有什么解决办法吗?

(我正在提供第一个答案,但我当然也在寻找其他解决方法。)

最佳答案

由于编译,您似乎想模仿 Either 类的行为和目标。 您可以执行以下操作:您的折叠将返回一个 Either 对象并从中获取 B0 值:

abstract class Wrapper[A](wrapped: A) {

  protected def someCondition: Boolean

  def fold[A, B](whenTrue: => B)(whenFalse: => A): Either[A, B] =
    Either.cond(someCondition, whenTrue, whenFalse)

}

并让 Either 类的隐式转换 either2mergeable 完成工作:

scala> new Wrapper[Unit] {def someCondition = true}
res0: Wrapper[Unit] = $anon$1@77026e40

scala> res0.fold(42)("hi").merge
res1: Any = 42

优点:

  • Either 结构允许您直接检索 A 和 B 类型
  • 您可以检查折叠过程中应用了哪些部分

缺点:

  • 您没有直接获得结果

关于generics - 如何使用未出现在第一个参数列表中的类型参数来改进 Scala 的类型推断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6954468/

相关文章:

java - 为什么在 Java 中使用泛型?它与重载有何不同?

node.js - 区分同一位置的请求参数?

mysql - 最小化MySQL存储过程中的参数

java - 在 Java 中评估 Scala 脚本时脚本引擎出错

html - 将 html/xml 代码与提升代码段分开的好方法是什么?

c++:ifstream打开问题,为文本文件名传递字符串

delphi - 泛型无法正确解析方法类型

Java 类型转换和原始类型

C# 到 Java : where T : new() Syntax

scala - java.lang.ClassNotFoundException,当我使用 "spark-submit"和一个新的类名而不是 "SimpleApp"时,