为了说明我的观点,这里有一个例子:
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/