Scala: неявное преобразование списка - PullRequest
1 голос
/ 08 марта 2012

Вот сокращенный пример того, что я хочу сделать.Закомментированная строка не компилируется.

class Animal
object Animal { implicit def toElephant(a: Animal) = a.asInstanceOf[Elephant] }
class Elephant extends Animal

object Main {

    def main(args: Array[String]) = {
        val a: List[Animal] = List(new Elephant, new Elephant)
        // val e: List[Elephant] = a
    }
}

В обычной ситуации e = a, конечно, является недопустимым.Но с неявной функцией можно подумать, что scala автоматически преобразует каждый элемент в списке.

Есть ли элегантный способ получить такое поведение?Если да, то как?

Что я хочу знать, так это то, что есть какой-то неясный угол скалы, который может вызвать желаемое поведение.Я не заинтересован в решениях, которые добавляют хладнокровие.Я могу думать о них сам.Например, можно сделать:

object Animal {
    implicit def toElephant(a: Animal) = a.asInstanceOf[Elephant]
    implicit def toElephant(a: List[Animal]) = a.asInstanceOf[List[Elephant]] }

и приведенный выше код будет работать.

Ответы [ 3 ]

2 голосов
/ 08 марта 2012

Но с неявной функцией можно подумать, что scala автоматически конвертировать каждый элемент в списке.

Почему?

Давайте попробуем что-нибудь:

class X[T : Manifest] {
  override def toString = manifest[T].toString
}

val x = new X[Animal]

Как неявное преобразование Animal в Elephant поможет преобразовать X[Animal] в X[Elephant]? Нет даже экземпляра Animal для конвертации! Но давайте поместим экземпляр там:

class X[T : Manifest](t: T) {
  override def toString = manifest[T].toString + t.toString
}

Теперь у нас есть экземпляр, но, опять же, как Scala преобразует X[Animal] в X[Elephant]? Он даже не может добраться до t, потому что это личное. Давайте сделаем это публично, тогда:

class X[T : Manifest](val t: T) {
  override def toString = manifest[T].toString + t.toString
}

Там это публично. Но как это будет преобразовано? Одним из способов было бы это:

new X[Elephant](Animal toElephant x.t)

Но как Скала узнает, как это сделать? Кто сказал, что это правильный код или этого достаточно?

Можно написать неявное учение X, как преобразовывать себя, если присутствует другое неявное преобразование, и такое неявное подобное может существовать для List, но неявные преобразования опасны. Чем их меньше, тем лучше. И, следовательно, такого неявного не существует.

2 голосов
/ 09 марта 2012

Вы можете забыть импликации и отображение и использовать просто

val e = a.asInstanceOf[List[Elephant]]

НО, если вы настаиваете, вы, конечно, можете сделать это преобразование неявным образом. Наличие неявного от List[A] до List[B] не более грубое, чем неявное A => B. Я бы не стал этого делать, но если бы я это сделал, я бы обобщил его для повторного использования, импортировав локально, чтобы ограничить неявное значение. Объем:

object Implicits {
  implicit def AListToBList[A, B <: A](lst: List[A]) = lst.asInstanceOf[List[B]]
}

Тогда на сайте использования

import Implicits._
val a: List[Animal] = List(new Elephant, new Elephant)
val e: List[Elephant] = a
e.head.doSomethingElephanty

Помните о масштабах импорта и, если необходимо, вставляйте вещи в блок locally.

1 голос
/ 08 марта 2012

А как же map?

val e = a map {_.asInstanceOf[Elephant]}

или даже лучше:

val e = a collect {case e: Elephant => e}

Обратите внимание, что и asInstanceOf, и неявное преобразование для супертипа в подтип не очень элегантны.

...