看看这个:
scala> class Container(val rows: Iterable[Iterable[Option[Any]]]) {}
defined class Container
scala> val row1 = Array(Some("test"),Some(1234))
row1: Array[Some[Any]] = Array(Some(test), Some(1234))
scala> val row2 = Array(Some("test2"), Some(12345))
row2: Array[Some[Any]] = Array(Some(test2), Some(12345))
scala> val listtest = List(row1, row2)
listtest: List[Array[Some[Any]]] = List(Array(Some(test), Some(1234)), Array(Some(test2), Some(12345)))
scala> val test = new Container(listtest)
<console>:11: error: type mismatch;
found : List[Array[Some[Any]]]
required: Iterable[Iterable[Option[Any]]]
val test = new Container(listtest)
^
scala> val test = new Container(List(row1,row2))
test: Container= Container@600a08
为什么以第二种方式定义 Container 而第一种方式不起作用?类型不一样吗?
最佳答案
这不是错误。 Array
不是协变的。 B 作为 B 的子类型不会使 Array[B] 成为 Array[A] 的子类型。这与java相反,其中B[]是A[]的子类型,这是不合理的:
A[] b = new B[1];
b[0] = new (A);
-> ArrayStoreException
所以你的 Array[Some[Any]] 不是 Array[Option[Any]]。你必须确保你有一个 Array[Option],你可以用它来做
val row2 = Array[Option[Any]](Some(test2), Some(12345))
您还可以在其中一项上使用类型归属:
val row2 = Array(Some(test2): Option[String], Some(12345))
或者如果你知道你的值是非空的,
val row2 = Array(Option(test2), Option(12345))
(在其中一个值上做到这一点就足够了)
List
,另一方面是协变的,这就是它起作用的原因。不幸的是,更精确的类型
Some
推断,您希望将某事物的类型称为 Some
是非常罕见的。 (或 None
)而不是 Option
.编辑 抱歉,看起来我完全没有捕获重点,关于为什么会有不同。
Array
不是协变的,但 Iterable 是。所以看起来Array[B]
虽然不是 Array[A]
, 应该是 Iterable[A]
,那么一切都应该正常工作。如果 Array 是 Iterable 的子类型,情况就会如此。不是,是JVM自带的,不能做扩展Iterable
.隐式转换为 WrappedArray
,这是一个 Iterable
.当你写
val l = List(row1, row2)
,没有理由应用这种转换。它尽可能精确地键入列表。那么 List 是协变的(如果 B 是 A,则 List[B] 是 List[A])这一事实不会在我们没有 B 是 A 但 B 隐式转换为 A 时出现。另一方面,当你写 val l: List[Iterable[A]] = List(x,y) 然后 List(...) 函数需要 Iterable[A] 参数,此时它会寻找隐式转换.
仍然不是错误,但比我想象的要棘手。也许你可以做一个
class Container[T <% Iterable[Option[Any]]](val rows: Iterable[T])
关于scala - Scala 中的奇怪输入错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7281716/