2017-02-17 56 views
3

假设我有一个集转换为字符串的,作为一个Type类:获得运行时类型拿起隐式证据

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 
} 

和使用该类型的信息挑选合适的转换器转换方法:

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

这工作得很好。如果我有具体类型提前,例如:

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

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

是否有可能使用上面的转换方法和运行时类型,例如,类型't'在下面?

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

你的'convert'需要一个值作为参数 - 你想用't'做什么?如果你想调用'convert(t)',你可以很容易地提供'隐式对象RTUStringConverter extends ToStringConverter [runtime.universe.Type]'。 – Suma

+0

convert方法当前需要一个类型参数,并且此类型用于通过隐式机制将正确的转换器引入到范围中。 有时我不知道类型提前,我只有一个代表它的类型,所以我应该更改签名传入Type实例,并手动获取该类型的隐式转换器? – gnf

+0

你想以类似'val a:Any; convert [t](a)'的方式调用它? – Suma

回答

2

如果你想要做的分辨率运行时,需要反思,因为implicits都解决了编译时间。像这样的代码应该做的工作:

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) 

如果你想建立converters地图自动,你也可以使用这种反映,但列举派生类需要令人惊讶的不平凡的代码(包括类加载器 - 这是当你考虑它时可以理解)。

如果您可以使ToStringConverterAny密封,则枚举其宏中的子类应该会更容易一些。

+0

这工作正常,但我想知道(如问题的标题说)如果我可以通过隐式机制获得转换器而不是有一个Map,我猜不是 – gnf

+0

implicits只是编译时间。你需要像运行时分派的地图。你可以做的最大的工作就是用宏(编译时反射)以某种方式反映暗示来建立一个地图编译时间。 – Suma