以下是我想要做的简化示例。注释掉的行不会编译。
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]] }
并且上面的代码可以使用。
答案 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
和超类型到子类型的隐式转换都不是很优雅。