无论如何,在Scala中,是否可以从更通用的类型中获取某物的Singleton类型? [英] Is there anyway, in Scala, to get the Singleton type of something from the more general type?

查看:58
本文介绍了无论如何,在Scala中,是否可以从更通用的类型中获取某物的Singleton类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一种情况,我试图在单例类型上使用隐式分辨率.如果我在编译时知道单例类型,则此方法可以很好地工作:

I have a situation where I'm trying to use implicit resolution on a singleton type. This works perfectly fine if I know that singleton type at compile time:

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
    }
}

但是,如果在编译时我不知道这种类型,那么我会遇到问题.

However, if I don't know this type at compile time, then I run into issues.

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 并返回该字符串的单例类型?

Is there anyway I can get around this? Maybe some method that takes a String and returns the singleton type of that string?

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

那我也许可以做

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

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

Or is this just not possible? Maybe you can only do this sort of thing if you know all of the information at compile-time?

推荐答案

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

Normally implicits are resolved at compile time. But val string = StdIn.readLine() becomes known at runtime only. Principally, you can postpone implicit resolution till runtime but you'll be able to apply the results of such resolution at runtime only, not at compile time (static types etc.)

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

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

Please notice that I put implicits into the companion object of type class in order to make them available in the implicit scope and therefore in the toolbox scope. Otherwise the code should be modified slightly:

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 ._ .

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

这篇关于无论如何,在Scala中,是否可以从更通用的类型中获取某物的Singleton类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆