scala类型的上限和下限

时间:2015-07-24 11:17:52

标签: scala types type-bounds

考虑以下层次结构:

class C1
class C2 extends C1
class C3 extends C2
class C4 extends C3

我想编写一个只接受C2C3类型的函数。为此我想到了以下内容:

 def f [C >: C3 <: C2](c :C) = 0

我期待以下行为

f(new C1)  //doesn't compile, ok
f(new C2)  //compiles, ok
f(new C3)  //compiles, ok
f(new C4)  // !!! Compiles, and it shouldn't 

问题是用C4调用它时,我不想允许,但编译器接受。我了解C4 <: C2是正确的,C4可以被视为C3。但是在指定绑定[C >: C3 <: C2]时,我希望编译器找到同时尊重两个边界的C,而不是一个接一个。

问题是:有没有办法实现我想要的,如果没有,编译器是否试图避免与此有些不一致?

编辑:从答案中我意识到我的推定是错误的。 C4始终满足C >: C3,因此两个边界确实得到尊重。我的用例的方法是C3 <:< C

2 个答案:

答案 0 :(得分:11)

静态地,是的。施加这种约束非常简单:

def f[C <: C2](c: C)(implicit ev: C3 <:< C) = 0

f(new C4)现在不会编译。

问题是,在编译时可能无法禁止以下行为:

val c: C3 = new C4
f(c)

此处变量c具有静态类型C3,它通过编译器传递任何类型的类型检查,但它在运行时实际上是C4

在运行时,您当然可以使用反射或多态检查类型并抛出错误或返回Failure(...)None

答案 1 :(得分:5)

我发现another stackoverflow question的解释非常有用:

  

S&gt;:T只是意味着如果传入的类型S等于T或其父类,则使用S。如果你将一个sublevel类型传递给T,那么将使用T.

所以在你的例子中所有,但首先应该编译。 以下示例说明了其含义: 让我们重新定义f:

def f[U >: C3 <: C2](c: U) = c

然后:

 val a2 = f(new C2)
 val a3 = f(new C3) 
 val a4 = f(new C4) 
 List[C2](a2, a3, a4)  //compiles
 List[C3](a3, a4)  //compiles
 List[C4](a4)  //does not cause a4 is C3

希望有所帮助。