我想建立一個isInstanceOf[T]
和asInstanceOf[T]
對的包裝,將輸出Option[T]
方便map
和getOrElse
方法。什麼是包裝isInstanceOf []調用的正確方法?
所以我試一試,但結果令我失望。
import scala.reflect.runtime.universe.{TypeTag, typeOf}
class Base()
class Deep() extends Base
class Deeper() extends Deep()
final case class WrapSimple[T](source : T) {
def cast[U] : Option[U] =
if (source.isInstanceOf[U]) Some(source.asInstanceOf[U]) else None
}
final case class WrapFullTagged[T: TypeTag](source : T) {
def cast[U : TypeTag] : Option[U] =
if (typeOf[T] <:< typeOf[U]) Some(source.asInstanceOf[U]) else None
}
final case class WrapHalfTagged[T](source : T) {
val stpe = {
val clazz = source.getClass
val mirror = scala.reflect.runtime.universe.runtimeMirror(clazz.getClassLoader)
mirror.classSymbol(clazz).toType
}
def cast[U : TypeTag] : Option[U] =
if (stpe <:< typeOf[U]) Some(source.asInstanceOf[U]) else None
}
object Test {
val base = new Base
val deep = new Deep
val deeper = new Deeper
val wile : Deep = new Deeper
def testSimple() : Unit = {
println(WrapSimple(deep).cast[Base].isDefined) // should be true
println(WrapSimple(deep).cast[Deeper].isDefined) // should be false
println(WrapSimple(wile).cast[Deeper].isDefined) // should be true
}
def testFullTagged() : Unit = {
println(WrapFullTagged(deep).cast[Base].isDefined) // should be true
println(WrapFullTagged(deep).cast[Deeper].isDefined) // should be false
println(WrapFullTagged(wile).cast[Deeper].isDefined) // should be true
}
def testHalfTagged() : Unit = {
println(WrapHalfTagged(deep).cast[Base].isDefined) // should be true
println(WrapHalfTagged(deep).cast[Deeper].isDefined) // should be false
println(WrapHalfTagged(wile).cast[Deeper].isDefined) // should be true
}
def testAll() : Unit = {
testSimple()
testFullTagged()
testHalfTagged()
}
}
WrapSimple
看起來不錯,但只是不工作,它會清除在isInstanceOf[U]
方法應用U
類型,所以它總是與true
響應。有趣的是,asInstanceOf[U]
保持U
類型正常,所以它只是產生運行時異常。
我試過的第二種方法是使用類型標籤的WrapFullTagged
。這似乎很清楚,但再次明顯地打破了合同。它只能在編譯時檢查靜態類型,並且對運行時的實際類型沒有深入瞭解。
因此,我培育了兩種方法並催生了第三種方法,至少能夠產生正確的輸出。但它看起來很糟糕,並且引起反思的力量,而這種反射的成本很高。
是否有可能通過更高雅的方式解決問題?
在運行時你永遠不會對類型有更多的瞭解,因爲它們被擦除。在運行時你可以擁有類型信息的唯一方法是如果你在編譯時通過TypeTag來保存它。在第一個例子中,'T'和'U'都被擦除。你能說出一個用例,其中'WrapFullTagged'沒有提供你想要的結果嗎? –
每次你想使用'isInstanceOf'。當您不知道運行時變量後面的實際類型時會發生這種情況。它經常發生。您可以嘗試記住您上次編寫項目時沒有任何匹配的模式。 – ayvango
shapeless typeable https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/typeable.scala –