定义参数的公共下限

Define common lower bounds of parameters

在以下函数中,Scala 编译器能够将 return 类型定义为 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 定义为 returning 类型 X 的值。

但是,如果ABcond函数定义中的类型参数,它的return类型是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
}

如果您静态知道 LUB,则可以将类型上限应用于 A 和 B。

def cond[A <: C, B <: C,C](b: Boolean, t: A, f: B) = if (b) t else f

如果您不需要参数的确切类型,那么以下通常就足够了:

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

这里AB是参数的确切类型,C是它们的LUB。 C 的约束是 A 的超类型:C >: A,但它也应该是第二个参数的类型,因为它被定义为 f: B with C,因此它推断为 AB.

的 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

感谢@nikhil 和@Kolmar 的回答,我可以想出这个解决方案:

class C[A](b: Boolean, t: A) {
  def cond[B <: R, R >: A](f: B): R = if(b) t else f
}