定义参数的常见下限

时间:2016-10-12 04:40:57

标签: scala generics types type-bounds

在以下函数中,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的值。

但是,如果ABcond函数定义中的类型参数,则其返回类型为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
}

3 个答案:

答案 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

此处AB是参数的确切类型,C是他们的LUB。 C的约束是AC >: 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

答案 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
}