Jea*_*let 6 generics parameters scala 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
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试添加一个fold
基于在包装类型上定义的任意条件的方法A
.上面的代码的问题是,这不会编译,虽然它可以想象返回Any
:
wrapper.fold("hi")(42)
Run Code Online (Sandbox Code Playgroud)
因为当编译器到达第二个参数列表时,B
已被推断为String
.假设我们不想编写类型注释.我们可以尝试fold
改为:
def fold[B, B0 >: B](whenTrue: => B)(whenFalse: => B0): B0
Run Code Online (Sandbox Code Playgroud)
但是这也行不通,因为B0
已经String
在第一个参数列表的末尾解决了,尽管它根本没有出现在它里面!当然,简单的解决方案是使用单个参数列表,但是为了示例,假设我想保留两个参数列表并尝试使其工作...理想情况下,我们应该能够延迟分辨率的B0
.如果我们能写出这样的东西会很棒:
def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0
Run Code Online (Sandbox Code Playgroud)
但不幸的是,这不起作用.有没有解决方法?
(我提供了第一个答案,但我当然也在寻找其他解决方法.)
由于编译,你似乎想模仿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)
}
Run Code Online (Sandbox Code Playgroud)
而让隐式转换either2mergeable
中的Either
类做的工作:
scala> new Wrapper[Unit] {def someCondition = true}
res0: Wrapper[Unit] = $anon$1@77026e40
scala> res0.fold(42)("hi").merge
res1: Any = 42
Run Code Online (Sandbox Code Playgroud)
优点:
Either
结构允许您直接检索A和B类型缺点:
一种解决方案是创建一个类的临时实例,该实例定义apply
模拟第二个参数列表的方法,该方法本身具有B0
类型参数:
abstract class Wrapper[A](wrapped: A) {\n\n // ... as before...\n\n def fold[B](whenTrue: => B) = new FoldRequest[B](whenTrue)\n\n class FoldRequest[B](whenTrue: => B) {\n def apply[B0 >: B](whenFalse: => B0) =\n if (someCondition) whenTrue else whenFalse\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n然后一切正常。我们是否可以想象这def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0
可以被解释为语法糖?\xe2\x80\xa6