Scala:隐式转换列表

时间:2012-03-08 14:44:36

标签: scala implicit

以下是我想要做的简化示例。注释掉的行不会编译。

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会自动转换列表中的每个元素。

有一种优雅的方式来获得这种行为吗?如果是,怎么样?

我想知道的是,是否有一些不明显的scala角落可以强迫我希望的行为。我对添加残留的解决方案不感兴趣。我自己可以想到它们。例如,人们可以这样做:

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

并且上面的代码可以使用。

3 个答案:

答案 0 :(得分:2)

  

但是使用隐式函数,可以认为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)

但Scala如何知道这样做?谁说这是有效的代码,还是足够了?

如果存在另一个隐式转换,可以编写隐式教导X如何转换自身,并且List可能存在隐式转换,但隐式转换是危险的。它们越少越好。因此,这种暗示并不存在。

答案 1 :(得分:2)

你可以忘记隐含和映射,只需使用

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块中。

答案 2 :(得分:1)

map怎么样?

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

甚至更好:

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

请注意,asInstanceOf和超类型到子类型的隐式转换都不是很优雅。