无论如何,在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 ._
.