2017-01-24 1 views
1

я столкнулся со следующей странный вопрос, имея возможность в вложенных коллекциях:Weird типа стирания для варианта в вложенной коллекции

val works: Array[Option[Int]] = Array(1) 
    .map { t => Some(t)} 

val fails: Array[Array[Option[Int]]] = Array(Array(1)) 
    .map { ts => ts.map { Some(_)} } 
// error: type mismatch; found : Array[Array[Some[Int]]] required: Array[Array[Option[Int]]] 

val worksButUgly: Array[Array[Option[Int]]] = Array(Array(1)) 
    .map { ts => ts.map { case t => (Some(t).asInstanceOf[Option[Int]])}} 

Я предполагаю, что это может быть проблема с каким-то типом стиранием вдоль пути, но это ожидаемый поведение в Скала? Кто-нибудь знает, что именно происходит?

ответ

5

Массивы в Скале являются инвариантными. Это предотвращает некоторые проблемы, которые имеют массивы, например. Java, где вы можете создать массив чего-либо, объявите его массивом суперкласса, а затем добавьте еще один подкласс. Например, говоря, что массив яблок представляет собой массив фруктов, а затем помещает бананы. Хуже всего то, что он терпит неудачу во время выполнения, а не во время компиляции.

По этой причине Scala решила, что массивы должны быть инвариантными. Это означает, что Array[Apple] не является подклассом Array[Fruit]. (Обратите внимание, что в отличие от массивов неизменные коллекции чаще всего ковариантны, например, List, потому что неизменность мешает нам помещать какие-либо бананы позже)

Так что да. Some является подклассом Option, но Array[Some] не является подклассом Array[Option]. Они будут работать:

val foo1: Array[Array[Option[Int]]] = Array(Array(1)) 
    .map { ts => ts.map { Option(_)} } 

val foo2: Array[List[Option[Int]]] = Array(List(1)) 
    .map { ts => ts.map { Some(_)} } 
0

Использование Some(t): Option[Int] вместо Some(t).asInstanceOf[Option[Int]]. Он короче и безопаснее: он не сможет скомпилировать, если типы не совпадают.

Смежные вопросы