我把它写成了一个REPL:
case class Thingy(s: String)
val things = List(Thingy("x"), Thingy("y"))
things.indexOf("x")
Run Code Online (Sandbox Code Playgroud)
那回来了-1.但我本来以为它不会编译,因为它"x"是a String,而不是a Thingy.事实上,事实证明你投入的类型并不重要indexOf:
things.indexOf(42)
things.indexOf(java.time.LocalDate.now())
Run Code Online (Sandbox Code Playgroud)
这些都返回-1.
indexOf 有这个签名:
def indexOf[B >: A](elem: B): Int
Run Code Online (Sandbox Code Playgroud)
我认为>:手段B应该是超类型A,但这些类都不是我的案例类的超类型Thingy.
我在这里错过了什么?
B被推断为java.io.Serializable,它是两者的超类型String和Thingy.1
这是两件事的不幸后果:
Any,Object,Serializable等).List是协变的.2定义indexOf为
def indexOf(elem: A): Int
Run Code Online (Sandbox Code Playgroud)
会把A在逆变位置,这是不允许的3,因为这将违反里氏替换原则:一个List[Thingy]是List[Any],你可以叫.indexOf("x")上List[Any],因此,你应该能够调用.indexOf("x")上List[Thingy].
1如果他们两个都没有实施Serializable,它仍然会推断Any.
2这是选择不变集合的理由,例如scalaz.IList.
3试一试 - 它不会编译:trait Foo[+A] { def bar(a: A) }