将 String 中的类型名称反映为 Scala 中的实际类型 [英] Reflect type name in String to actual type in Scala

查看:37
本文介绍了将 String 中的类型名称反映为 Scala 中的实际类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类对象

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]

To use this I call DefaultValue.value[Int] or DefaultValue.value[Double] etc

但是,当我将用户输入为 "Int" 时,我需要能够调用 DefaultValue.value[Int] :用字符串编写的类型名,类似地其他.

However, I need the ability to call DefaultValue.value[Int] when I have user input as "Int" : the typename written in String, and similarly for others.

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

I wish to do this without pattern-matching, as it would essentially beat the purpose of inserting TypeTag in the function. Is there a better way to do this, perhaps using Scala Reflection?

推荐答案

这样做的一个问题是您将无法获得好的返回类型.AnyDefaultValue[_] 是最好的.

One problem with that is that you won't be able to get a good return type. Any or DefaultValue[_] is the best you can get.

你可以使用反射来写这样的东西:

You can use reflection to write something like this:

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 vals 一起使用(例如 implicit val DefaultString = new DefaultValue[String]("~")),则必须为这种情况:

This will work for implicit objects. If you want it to work with implicit vals (e.g. implicit val DefaultString = new DefaultValue[String]("~")), you'd have to add code for this case:

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 等提供多个可能的字符串.

This approach is probably faster and really not that hard to maintain. Also, it would be possible to not require direct correspondence between object name and user input, or to have several possible strings for a single DefaultValue, etc.

此外,如果您将基类声明为 sealed,并且仅使用 objects 对其进行扩展,则可以简化此 Map:

Also, if you declare the base class as sealed, and extend it only with objects, you could streamline the creation of this 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
  }
}

这篇关于将 String 中的类型名称反映为 Scala 中的实际类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆