2015-09-04 46 views
1

我有下面的类对象在字符串反映类型名称实际类型斯卡拉

class DefaultValue[+A](val default: A) 

object DefaultValue { 

    implicit object DefaultDouble extends DefaultValue[Double](-1.0) 
    implicit object DefaultFloat extends DefaultValue[Float](-1f) 
    implicit object DefaultInt extends DefaultValue[Int](-1) 
    implicit object DefaultBoolean extends DefaultValue[Boolean](false) 

    def value[A](implicit value: DefaultValue[A]): A = value.default 
} 

要使用此我呼吁DefaultValue.value[Int]DefaultValue.value[Double]

不过,我需要调用DefaultValue.value[Int]的能力当我有用户输入为"Int":字符串中写入类型名称,并为其他类似。

我希望在没有模式匹配的情况下做到这一点,因为它本质上会超过在函数中插入TypeTag的目的。 有没有更好的方式来做到这一点,也许使用Scala反射?

回答

1

这样做的一个问题是,您将无法获得良好的返回类型。 AnyDefaultValue[_]是最好的,你可以得到。

您可以使用反射来写这样的事:

import scala.reflect.runtime.{currentMirror => cm, universe => ru} 

def defaultByTypename(typename: String): DefaultValue[_] = { 
    val defaultValueName = "Default" + typename.trim.capitalize 
    val objectSymbol = 
    ru.typeOf[DefaultValue.type].member(ru.TermName(defaultValueName)) 
    cm.reflectModule(objectSymbol.asModule).instance.asInstanceOf[DefaultValue[_]] 
} 

这将为implicit object的工作。如果你想让它与implicit val S(例如implicit val DefaultString = new DefaultValue[String]("~"))工作,你就必须为这种情况下添加代码:

def defaultByTypename(typename: String): DefaultValue[_] = { 
    val defaultValueName = "Default" + typename.trim.capitalize 
    val objectSymbol = 
    ru.typeOf[DefaultValue.type].member(ru.TermName(defaultValueName)) 
    val result = if (objectSymbol.isModule) { 
    cm.reflectModule(objectSymbol.asModule).instance 
    } else if (objectSymbol.isTerm) { 
    cm.reflect(DefaultValue).reflectField(objectSymbol.asTerm).get 
    } else sys.error("Unknown typename") 
    result.asInstanceOf[DefaultValue[_]] 
} 

但实际上,我认为,这不是一个坏主意,走了Map与对应关系:

val typename2DefaultValue = Map[String, DefaultValue[_]](
    "Double" -> DefaultDouble, 
    "Float" -> DefaultFloat, 
    "Int" -> DefaultInt, 
    "Boolean" -> DefaultBoolean 
) 

这种方法可能更快,实际上并不难以维护。此外,将有可能不需要对象名称和用户输入之间的直接通信,或者有几个可能的串单个DefaultValue


另外,如果你声明基类sealed,和只有object小号扩展它,你可以简化这个Map的创作:

import scala.reflect.runtime.{currentMirror => cm, universe => ru} 

sealed class DefaultValue[+A](val default: A) 

object DefaultValue { 
    implicit object DefaultDouble extends DefaultValue[Double](-1.0) 
    implicit object DefaultFloat extends DefaultValue[Float](-1f) 
    implicit object DefaultInt extends DefaultValue[Int](-1) 
    implicit object DefaultBoolean extends DefaultValue[Boolean](false) 

    val typename2DefaultValue: Map[String, DefaultValue[_]] = { 
    val subclasses = ru.symbolOf[DefaultValue[_]].asClass.knownDirectSubclasses 
    subclasses.map { subclass => 
     subclass.name.toString.stripPrefix("Default") -> 
     cm.reflectModule(cm.staticModule(subclass.fullName)).instance.asInstanceOf[DefaultValue[_]] 
    }.toMap 
    } 
} 
+0

感谢详细的解答。 –