在Scala中,有没有从更通用的类型中获得Singleton类型的东西



我有一种情况,我试图对单例类型使用隐式解析。如果我知道编译时的singleton类型:,这就非常好了

object Main {
type SS = String with Singleton
trait Entry[S <: SS] {
type out
val value: out
}
implicit val e1 = new Entry["S"] {
type out = Int
val value = 3
}
implicit val e2 = new Entry["T"] {
type out = String
val value = "ABC"
}
def resolve[X <: SS](s: X)(implicit x: Entry[X]): x.value.type = {
x.value
}
def main(args: Array[String]): Unit = {
resolve("S") //implicit found!  No problem
}
}

然而,如果我在编译时不知道这种类型,那么我就会遇到问题。

def main(args: Array[String]): Unit = {
val string = StdIn.readLine()
resolve(string) //Can't find implicit because it doesn't know the singleton type at runtime.
}

有什么办法我可以绕过这个吗?也许是某个方法获取String并返回该字符串的singleton类型?

def getSingletonType[T <: SS](string: String): T = ???

那也许我可以做

def main(args: Array[String]): Unit = {
val string = StdIn.readLine()
resolve(getSingletonType(string))
}

或者这是不可能的?也许只有在编译时知道所有信息的情况下才能做这种事情?

如果您在编译时了解Entry的所有可能实现(只有当它是密封的时才可能实现(,那么您可以使用宏来创建映射/部分函数String -> Entry[_]

由于这是开放的扩展,我担心在最好的情况下,一些运行时反射必须扫描整个类路径才能找到所有可能的实现。

但即便如此,您也必须以某种方式将String文本嵌入到每个实现中,因为JVM字节码对单例类型和实现之间的映射一无所知——只有Scala编译器知道。然后使用它来查找在所有实现中是否有一个(并且恰好有一个(与您的值匹配——对于隐式实现,如果在同一范围内同时有两个,编译将失败,但您可以有多个实现,只要它们不一起出现在同一范围内。运行时反射将是全局的,因此无法避免冲突。

因此,没有什么好的解决方案可以使这个编译时调度动态化。您可以自己创建这样的分派,例如自己编写Map[String, Entry[_]]并使用get函数来处理丢失的pice。

通常在编译时解析隐式。但val string = StdIn.readLine()仅在运行时才为人所知。原则上,你可以将隐式解析推迟到运行时,但你只能在运行时应用这种解析的结果,而不能在编译时(静态类型等(

object Entry {
implicit val e1 = ...
implicit val e2 = ...
}
import scala.reflect.runtime.universe._
import scala.reflect.runtime
import scala.tools.reflect.ToolBox
val toolbox = ToolBox(runtime.currentMirror).mkToolBox()
def resolve(s: String): Any = {
val typ = appliedType(
typeOf[Entry[_]].typeConstructor,
internal.constantType(Constant(s))
)
val instanceTree = toolbox.inferImplicitValue(typ, silent = false)
val instance = toolbox.eval(toolbox.untypecheck(instanceTree)).asInstanceOf[Entry[_]]
instance.value
}
resolve("S") // 3
val string = StdIn.readLine()
resolve(string)
// 3 if you enter S
// ABC if you enter T
// "scala.tools.reflect.ToolBoxError: implicit search has failed" otherwise

请注意,我将implicits放入类型类的伴随对象中,以便使它们在隐式作用域中可用,从而在工具箱作用域中也可用。否则,代码应稍作修改:

object EntryImplicits {
implicit val e1 = ...
implicit val e2 = ...
}
// val instanceTree = toolbox.inferImplicitValue(typ, silent = false)
//   should be replaced with
val instanceTree =
q"""
import path.to.EntryImplicits._
implicitly[$typ]
"""

在您的代码中,import path.to.EntryImplicits._就是import Main._

从动态生成的案例类加载数据集

最新更新