2015-09-04 47 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

感謝詳細的解答。 –