在以下函数中,Scala编译器能够将返回类型定义为if / else表达式中使用的值的最低公共超类型:
def cond(b: Boolean, t: A, f: B) = if (b) t else f
考虑以下层次结构:
class X
class A extends X
class B extends X
上面的函数cond
被定义为返回类型X
的值。
但是,如果A
和B
是cond
函数定义中的类型参数,则其返回类型为Any
:
def cond[A, B](b: Boolean, t: A, f: B) = if (b) t else f
是否可以使编译器使用类型参数的最低常见超类型?
我尝试了以下一些变体,但没有成功:
def cond[A, B, R >: A with B](b: Boolean, t: A, f: B): R = if (b) t else f
def cond[A, B, R](b: Boolean, t: A, f: B)(implicit ev1: A <:< R, ev2: B <:< R): R = if (b) t else f
编辑:上述问题过于简单。事实上,我的真正问题是其中一个类型参数已经解决:
class C[A](b: Boolean, t: A) {
def cond[B](f: B) = if(b) t else f
}
答案 0 :(得分:1)
如果您静态了解LUB,则可以将上限类型应用于A和B.
def cond[A <: C, B <: C,C](b: Boolean, t: A, f: B) = if (b) t else f
答案 1 :(得分:1)
如果您不需要完全类型的参数,那么以下通常就足够了:
def cond[T](b: Boolean, t: T, f: T) = if (b) t else f
Scala会自动将参数类型向上转换为最小上限(LUB):
scala> cond(true, new A, new B)
res0: X = A@74a59bb6
但是如果您需要确切的类型,例如隐式解析,我相信以下技巧应该有效:
def cond[A, B, C >: A](b: Boolean, t: A, f: B with C): C = if (b) t else f
此处A
和B
是参数的确切类型,C
是他们的LUB。 C
的约束是A
:C >: A
的超类型,但它也应该是第二个参数的类型,因为它被定义为f: B with C
,因此它被推断为A
和B
的LUB。
我们可以使用以下代码检查正确的类型推断:
import reflect.runtime.universe._
def cond[A, B, C >: A](b: Boolean, t: A, f: B with C)(
implicit ta: TypeTag[A],
tb: TypeTag[B],
tc: TypeTag[C]
): C = {
println(ta)
println(tb)
println(tc)
if (b) t else f
}
scala> cond(true, new A, new B)
TypeTag[A]
TypeTag[B]
TypeTag[X]
res5: X = A@f0ad2ea
答案 2 :(得分:0)
感谢@nikhil和@Kolmar的答案,我可以提出这个解决方案:
class C[A](b: Boolean, t: A) {
def cond[B <: R, R >: A](f: B): R = if(b) t else f
}