简体   繁体   English

Scala类型界限行为(方法与类)

[英]Scala type bounds behaviour (method vs class)

Probably an easy one for Scala gurus. 对于Scala专家来说,这可能是一件容易的事。 I'm reading up on type bound constraints and wondering if I'm missing something, as I'm seeing a slightly unexpected behaviour. 我正在阅读类型绑定约束,并想知道是否遗漏了一些东西,因为我看到了一些意想不到的行为。 Let's say we have three types A,B,C in a hierarchy like this, for which we're experimenting with type bounds: 假设我们在这样的层次结构中有三种类型A,B,C,我们正在针对它们进行类型界限的实验:

class A {
}

class B extends A {
}

class C extends B {
}

class MyList1 { // T super B
  def add[T >: B](a: T): Unit = {}
}

class MyList2 { // T extends B
  def add[T <: B](a: T): Unit = {}
}

class MyList3[T >: B] { // T super B
  def add(a: T): Unit = {}
}

class MyList4[T <: B] { // T extends B
  def add(a: T): Unit = {}
}

object BoundsClass {

  def main(args: Array[String]) {
    val l1 = new MyList1
    l1.add(new A) 
    l1.add(new B)
    l1.add(new C) // why is this allowed??

    val l2 = new MyList2
    // l2.add(new A) // not allowed (OK)
    l2.add(new B)
    l2.add(new C)

    val l3a = new MyList3[A]
    val l3b = new MyList3[B]
    // val l3c = new MyList3[C] // not allowed (OK)

    // val l4a = new MyList4[A] // not allowed (OK)
    val l4b = new MyList4[B]
    val l4c = new MyList4[C]
  }

}

The collections are behaving as expected for all except one case, see l1.add(new C); 除一种情况外,其他所有集合的行为均符合预期,请参见l1.add(new C);。 not causing a compilation error. 不会导致编译错误。 Why is this allowed? 为什么允许这样做?

Thanks! 谢谢!

I'm not claiming to be a scala guru, but I'll take a stab at this. 我并没有声称自己是斯卡拉大律师,但我会为此而a之以鼻。

You've defined your type hierarchy along the lines of A >: B >: C , so you can do stuff like 您已经按照A >: B >: C定义了类型层次结构,因此您可以执行以下操作

val aa: A = new A
val ab: A = new B
val ac: A = new C

val bb: B = new B
val bc: B = new C

val cc: C = new C

just like you could say val a: Any = new Whatever . 就像您可以说val a: Any = new Whatever

So when you try to add a new C to l1 , it gets treated like a B instance because that is the closest available version of itself that conforms to the method's type bounds. 因此,当您尝试向l1添加new C时,它会被视为B实例,因为这是它自身最接近该方法的类型范围的可用版本。

Lower bounds are not useful when used in that way. 当以这种方式使用时,下界没有用。 You cannot enforce a value parameter to have a lower bound because, according to the Liskov substitution principle , you must be able to use an instance of a subclass anywhere an instance of a class is required. 您不能将value参数强制设置为下限,因为根据Liskov替换原则 ,您必须能够在需要类实例的任何地方使用子类实例。 Therefore, your code compiles because new C can be seen as an instance of B . 因此,您的代码可以编译,因为new C可以视为B的实例。

Generally, it is not useful to put a lower bound on a value parameter of a method because of that reason. 通常,由于这个原因,在方法的值参数上设置下限是没有用的。 Lower bounds are definitely more useful in your second case, where you bound the type parameter of a class. 在您绑定类的类型参数的第二种情况下,下界无疑更有用。 All type parameters are resolved at compile type and, as such, you can expect the compiler to yield compiler errors in your second case. 所有类型参数都是按编译类型解析的,因此,您可以期望编译器在第二种情况下产生编译器错误。 You can find a more concrete example of lower bound usage here . 您可以在此处找到下限用法的更具体示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM