【问题标题】:Scala upper type bounds for reflectioned type反射类型的 Scala 类型上限
【发布时间】:2022-12-07 13:28:43
【问题描述】:

例如,a 的类型为 B。我知道它是A 的子类型。
我想在运行时使用 B 类型,只有类名并使用反射。

我正在尝试通过Class.forName("B").asSubclass(classOf[A])获取它

问题是,我不能在上界函数中使用这种类型
def test[T <: A]() = ???

最小的例子:

trait A
class B extends A

val cls: Class[_ <: A] = Class.forName("B").asSubclass(classOf[A])

def test[T <: A]() = ???

test[cls.type]()   // Error: type arguments cls.type 
                   // do not conform to upper bound A 
                   // of type parameter T

有什么方法可以使编译器工作吗?

【问题讨论】:

  • cls.typeClass[_ &lt;: A]。您想将 _ &lt;: A 传递到 test[...] 而没有此 Class[...] 部分。
  • @MateuszKubuszok 有可能吗?
  • 重载 def type[T &lt;: A](@unused clazz: Class[T]) = type[T]() 然后 test(cls) 应该可以工作。
  • @MateuszKubuszok 你能提供最小的例子作为答案吗?我不清楚,如何使用def type

标签: scala reflection


【解决方案1】:

您应该更好地描述您要解决的实际问题。目前这听起来像XY problem

你似乎混淆了类型(通常在编译时存在)和班级(通常在运行时存在)

What is the difference between a class and a type in Scala (and Java)?

What is the difference between Type and Class?

https://typelevel.org/blog/2017/02/13/more-types-than-classes.html

test[cls.type] 没有意义。

也许实际上 @MateuszKubuszok 提出的建议可以提供帮助

def test[T <: A](): Unit = ??? 

def test[T <: A](@unused clazz: Class[T]): Unit = test[T]()

如果您真的想将一个类替换为泛型方法的类型参数位置,那么问题是 T 是否是 A 的子类型应该由编译器在编译时检查并且 Class[_] 对象存在于运行。所以如果你真的想要这个,你应该找到一种方法来在编译时更早地处理这个类,例如用macro

trait A
class B extends A
class C
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

def myMacro: Unit = macro myMacroImpl

def myMacroImpl(c: blackbox.Context): c.Tree = {
  import c.universe._
  q"App.test[${c.mirror.staticClass("B")}]()"
}

def myMacro1: Unit = macro myMacro1Impl

def myMacro1Impl(c: blackbox.Context): c.Tree = {
  import c.universe._
  q"App.test[${c.mirror.staticClass("C")}]()"
}
object App {
  def test[T <: A]() = ???
}

myMacro // compiles
myMacro1 // doesn't compile: type arguments [C] do not conform to method test's type parameter bounds [T <: A]

反之亦然,将类型检查推迟到运行时,例如带运行时编译(反光toolbox

trait A
class B extends A
class C

object App {
  def test[T <: A]() = ???
}

val cls: Class[_ <: A] = Class.forName("B").asSubclass(classOf[A])
val cls1 = classOf[C]

import scala.reflect.runtime.{currentMirror => rm}
import scala.reflect.runtime.universe.Quasiquote
import scala.tools.reflect.ToolBox
val tb = rm.mkToolBox()
tb.typecheck(q"App.test[${rm.classSymbol(cls)}]()") // ok
tb.typecheck(q"App.test[${rm.classSymbol(cls1)}]()") // scala.tools.reflect.ToolBoxError: reflective typecheck has failed: type arguments [C] do not conform to method test's type parameter bounds [T <: A]

除了tb.typecheck还有tb.compiletb.eval

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2018-03-19
    • 1970-01-01
    相关资源
    最近更新 更多