簡體   English   中英

將Scala中的類型作為參數傳遞

[英]Passing type in Scala as an argument

我想將類型傳遞給Scala中的函數。

問題詳細

第一次迭代

我有以下Java類(來自外部源):

public class MyComplexType {
    public String name;
    public int number;
}

public class MyGeneric<T> {
    public String myName;
    public T myValue;
}

在這個例子中,我想MyComplexType是實際類型的MyGeneric ; 在真正的問題中有幾種可能性。

我想使用Scala代碼反序列化JSON字符串,如下所示:

import org.codehaus.jackson.map.ObjectMapper

object GenericExample {
  def main(args: Array[String]) {
    val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
    val objectMapper = new ObjectMapper()
    val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]])
    val myComplexType: MyComplexType = myGeneric.myValue
  }
}

它編譯好,但發生運行時錯誤:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyComplexType
        at GenericExample$.main(GenericExample.scala:9)

第二次迭代

解決問題的工作方案:

val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val myGeneric: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, classOf[MyGeneric[MyComplexType]]) 
myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[MyComplexType])
val myComplexType: MyComplexType = myGeneric.myValue

不好但是很有效。 (如果有人知道如何讓它變得更好,那也會受到歡迎。)

第三次迭代

第二次迭代解決方案中的行多次出現在實際問題中,因此我想創建一個函數。 更改變量是JSON格式的字符串和MyComplexType

我想要這樣的東西:

def main(args: Array[String]) {
  val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
  val myGeneric = extractMyGeneric[MyComplexType](jsonString)
  val myComplexType: MyComplexType = myGeneric.myValue
}

private def extractMyGeneric[T](jsonString: String) = {
  val objectMapper = new ObjectMapper()
  val myGeneric = objectMapper.readValue(jsonString, classOf[MyGeneric[T]])    
  myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOf[T])
  myGeneric
}

這不起作用(編譯器錯誤)。 我已經玩過ClassClassTagclassOf各種組合,但它們都沒有幫助。 還有編譯器和運行時錯誤。 你知道如何傳遞以及如何在Scala中使用這種類型嗎? 謝謝!

當您使用jackson解析json時,您可以使用TypeReference來解析generic類型。 例:

val jsonString = "{\"myName\":\"myNumber\",\"myValue\":{\"name\":\"fifteen\",\"number\":\"15\"}}"
val objectMapper = new ObjectMapper()
val reference = new TypeReference[MyGeneric[MyComplexType]]() {}
val value: MyGeneric[MyComplexType] = objectMapper.readValue(jsonString, reference) 

如果您仍想使用Jackson ,我認為您可以使用TypeReference類型創建參數。 喜歡:

  implicit val typeReference = new TypeReference[MyGeneric[MyComplexType]] {}
  val value = foo(jsonString)
  println(value.myValue.name)


  def foo[T](jsonStr: String)(implicit typeReference: TypeReference[MyGeneric[T]]): MyGeneric[T] = {
    val objectMapper = new ObjectMapper()
    objectMapper.readValue(jsonStr, typeReference)
  }

使用您的方法,我認為您可以使用ClassTag獲取所需的類:

def extractMyGeneric[A : ClassTag](jsonString: String)(implicit generic: ClassTag[MyGeneric[A]]): MyGeneric[A] = {
  val classOfA = implicitly[ClassTag[A]].runtimeClass.asInstanceOf[Class[A]]
  val classOfMyGenericOfA = generic.runtimeClass.asInstanceOf[Class[MyGeneric[A]]]
  val objectMapper = new ObjectMapper()
  val myGeneric = objectMapper.readValue(jsonString, classOfMyGenericOfA)
  myGeneric.myValue = objectMapper.readValue(objectMapper.readTree(jsonString).get("myValue").toString, classOfA)
  myGeneric
}

我對jackson不熟悉,但在play-json中你可以輕松地為你的泛型類定義Reads

import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit def genReads[A: Reads]: Reads[MyGeneric[A]] = (
  (__ \ "myName").read[String] and
  (__ \ "myValue").read[A]
)((name, value) => {
    val e = new MyGeneric[A]
    e.myName = name
    e.myValue = value
    e
})

有了這個,並且只要存在MyComplexTypeReads實例,就可以實現你的方法

def extractMyGeneric[A: Reads](jsonString: String): MyGeneric[A] = {
  Json.parse(jsonString).as[MyGeneric[A]]
}

這里的問題是你需要為所有復雜類型提供Reads ,這很簡單

implicit complexReads: Reads[MyComplexType] = Json.reads[MyComplexType]

如果那些是案例類,那么我認為你必須用genReads方式手動定義它們與genReads所做的genReads

暫無
暫無

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

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