gpt4 book ai didi

scala - 包装 isInstanceOf[] 调用的正确方法是什么?

转载 作者:行者123 更新时间:2023-12-02 01:21:58 26 4
gpt4 key购买 nike

我想为 isInstanceOf[T]asInstanceOf[T] 对构建一个包装器,它将输出 Option[T]使用方便的 mapgetOrElse 方法。

于是我尝试了一下,结果让我很失望。

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。看起来很清楚,但又明显违约了。它只能在编译时检查静态类型,而在运行时对实际类型的了解为零。

因此,我培育了这两种方法并诞生了第三种方法,它至少能产生正确的输出。但它看起来很糟糕,并且需要付出巨大代价才能激发反射(reflection)的力量。

是否有可能更优雅地解决问题?

最佳答案

查看 scala.reflect.ClassTag。它提供对已删除类 Type 和 according to the api docs 的访问。对于具有类型的函数

def unapply(x: Any): Option[T]

A ClassTag[T] can serve as an extractor that matches only objects of type T.

一个与问题中的预期输出相匹配并且看起来相当优雅的示例:

class Base()
class Deep() extends Base
class Deeper() extends Deep()

case object SimpleCaster {
def cast[A](t: Any)(implicit classTag: scala.reflect.ClassTag[A]): Option[A] = classTag.unapply(t)
}

object Test {
val base = new Base
val deep = new Deep
val deeper = new Deeper
val wile: Deep = new Deeper

def testSimple(): Unit = {
val a = SimpleCaster.cast[Base](deep)
val b = SimpleCaster.cast[Deeper](deep)
val c = SimpleCaster.cast[Deeper](wile)
println(s"${a.isDefined} - ${a.map(_.getClass)}")
println(s"${b.isDefined} - ${b.map(_.getClass)}")
println(s"${c.isDefined} - ${c.map(_.getClass)}")
}
}

控制台输出结果:

scala> Test.testSimple
true - Some(class Deep)
false - None
true - Some(class Deeper)

总结;虽然这使用了反射 api,但它看起来是一个不太冗长的实用解决方案。

关于scala - 包装 isInstanceOf[] 调用的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39581089/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com