簡體   English   中英

在Scala中獲取泛型類型的特定簡單名稱

[英]Get the specific simple name of a generic type in 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")

顯然,如果我可以在不必將其傳入的情況下解決“用戶”問題會更容易。

可以使用manifest.erasure.getName (擦除是Class實例)從Manifest(或ClassManifest)中檢索類名。 例如

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

編輯 :看過Derek的回答,這使得erasure.getName這個東西看起來相當愚蠢。 我不考慮toString。 我仍然希望以下內容可能會引起關注

兩者的區別ClassManifestManifest的是,在Manifest的泛型類,類型參數都保證是可用的,而他們在盡最大努力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)

這樣,只有當Builder可用於此特定類時,才會編譯對fromMap調用,而不是使用MatchError失敗。

這應該工作(但我必須編輯你的代碼,以猜測你想要的):

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)
}

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

對於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

對於那些來自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"))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM