Get Runtime Type picked by implicit evidence

被刻印的时光 ゝ 提交于 2019-12-12 14:29:42

问题


Suppose I have a set of converters to String, as a Type class:

import scala.reflect.runtime.universe._

abstract class ToStringConverter[T] { 
    def convert(value: T): String 
}
implicit object IntToStringConverter extends ToStringConverter[Int] { 
     def convert(value: Int) = value.toString 
}
implicit object DoubleStringConverter extends ToStringConverter[Double] {
     def convert(value: Double) = value.toString 
}

and a convert method that uses the type information to pick right converter:

def convert[T](v: T)(implicit ev: ToStringConverter[T]): String = ev.convert(v)

This works fine If I have the concrete type in advance, for example:

scala> convert[Double](12.2)
res0: String = 12.2

scala> convert[Int](12)
res1: String = 12

Is it possible to use the convert method above with a runtime type, for example, with a type 't' below?

scala> val t = typeOf[Double]
t: reflect.runtime.universe.Type = Double

回答1:


If you want to do the resolution runtime, reflection is needed, as implicits are resolved compile time. A code like this should do the job:

import scala.reflect.runtime.universe._

abstract class ToStringConverterAny {
  def convertAny(value: Any): String
}

abstract class ToStringConverter[T] extends ToStringConverterAny {
  def convertAny(value: Any): String = convert(value.asInstanceOf[T])
  def convert(value: T): String
}
implicit object IntToStringConverter extends ToStringConverter[Int] {
  def convert(value: Int) = value.toString
}
implicit object DoubleStringConverter extends ToStringConverter[Double] {
  def convert(value: Double) = value.toString
}

val converters: Map[Type, ToStringConverterAny] = Map(
  typeOf[Int] -> IntToStringConverter,
  typeOf[Double] -> DoubleStringConverter
)

def convert(t: Type, v: Any) = {
  converters(t).convertAny(v)
}

def convert[T](v: T)(implicit ev: ToStringConverter[T]): String = ev.convert(v)

convert[Double](12.2)

convert[Int](12)

val t = typeOf[Double]
val v: Any = 1.23

convert(t, v)

If you want to building converters map automatically, you could also use reflection for this, but enumerating derived classes requires surprisingly non-trivial code (including class loaders - which is understandable when you think about it).

If you can make the ToStringConverterAny sealed, enumerating over its subclasses in a macro should be a bit easier.



来源:https://stackoverflow.com/questions/42292338/get-runtime-type-picked-by-implicit-evidence

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!