在Scala中获取泛型类型的特定简单名称

时间:2011-08-24 12:48:13

标签: generics scala

是否可以在Scala中获取泛型类的类型名称?我知道在类型擦除的Java中这是不可能的,但我希望Scala会是另一种情况。

目前我必须做类似的事情:

trait Model
case class User(id: String) extends Model

def fromMap[M<:Model : Manifest](data: Map[String, String], modelType: String) = {
  modelType match {
    case "user" => User(data.get("id").get)
  }
}

val user = fromMap[User](Map("id" -> "id1"), "user")

显然,如果我可以在不必将其传入的情况下解决“用户”问题会更容易。

4 个答案:

答案 0 :(得分:9)

可以使用manifest.erasure.getName从清单(或ClassManifest)中检索类名(擦除是类实例)。例如

def className[A : ClassManifest] = classManifest[A].erasure.getName

编辑:看过Derek的回答,这使得erasure.getName的内容看起来相当愚蠢。我不考虑toString。我仍然希望以下内容可能会引起人们的兴趣

使用ClassManifestManifest之间的区别在于,Manifest对于泛型类,类型参数保证可用,而它们是{{1 (比较两个类中ClassManifest的签名)。这种保证的缺点是typeParameters可能不会隐含地显示Manifest

您是否考虑过使用类型类?

ClassManifest

这样,只有trait BuilderFromMap[A] {def build(data: Map[String, String]): A} // or better, return Option[A], accounting for possible failure object User { implicit val Builder extends BuilderFromMap[User] {...} } def fromMap[A](data: Map[String, String])(implicit builder: BuilderFromMap[A]) = builder.build(data) 可用于此特定类,而不是fromMap失败时,才会编译对Builder的调用。

答案 1 :(得分:2)

这应该有用(但我必须编辑你的代码才能猜出你想要的东西):

trait Model
case class User(id: String) extends Model

object Main extends App {
  def fromMap[M <: Model](data: Map[String, String])(implicit m: reflect.Manifest[M]): Model = {
    m.toString match {
      case "User" => User(data.get("id").get)
    }
  }

  val user = fromMap[User](Map("id" -> "id1"))
  println(user)
}

但基于我遇到的麻烦,我相信有人可以做得更好:)

答案 2 :(得分:1)

对于那些从使用Scala 2.12.x或2.13.x的世界来问这个问题的人,ClassTag[T]是执行此操作的首选方法。

import scala.reflect._ 

trait Model 
case class User(id: String) extends Model 

def fromMap[M <: Model : ClassTag](data: Map[String, String]) = {
  val modelType = implicitly[ClassTag[M]].runtimeClass.getSimpleName
  modelType match {
    case "User" => User(data("id"))
  }
} 

val user = fromMap[User](Map("id" -> "id1"))

答案 3 :(得分:0)

对于Scala 2.11,以下代码有效:

import scala.reflect.runtime.universe.{typeOf, TypeTag}

def name[T: TypeTag] = typeOf[T].typeSymbol.name.toString

def fullName[T: TypeTag] = typeOf[T].typeSymbol.fullName

执行示例:

scala> name[String]
res5: String = String

scala> fullName[String]
res6: String = java.lang.String

价: http://www.scala-lang.org/api/2.11.0/scala-reflect/index.html