定义参数的公共下限
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
的值。
但是,如果A
和B
是cond
函数定义中的类型参数,它的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
这里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
感谢@nikhil 和@Kolmar 的回答,我可以想出这个解决方案:
class C[A](b: Boolean, t: A) {
def cond[B <: R, R >: A](f: B): R = if(b) t else f
}
在以下函数中,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
的值。
但是,如果A
和B
是cond
函数定义中的类型参数,它的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
这里A
和B
是参数的确切类型,C
是它们的LUB。 C
的约束是 A
的超类型:C >: A
,但它也应该是第二个参数的类型,因为它被定义为 f: B with C
,因此它推断为 A
和 B
.
我们可以使用以下代码检查此定义的正确类型推断:
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
}