2013-06-25 184 views
6

我正在使用Play框架2.1和Scala 2.10.1,並且想構建一個通用函數來構造一個JsArray列表的自定義案例類。斯卡拉類型推遲

private def buildJsArray[T](l: List[T])(result: JsArray): JsArray = { 
    l match { 
     case List() => result 
     case x::xs => buildJsArray(xs)(result :+ Json.toJson(x)) // compiling error here! 
    } 
    } 

用法:

val applyJsonArray = buildJsArray(List[Apple])(new JsArray()) 

然而,編譯錯誤被拋出:

No Json deserializer found for type T. Try to implement an implicit Writes or Format for this 
type. 

我確實有特殊情況類寫一個JSON解串器(即蘋果案例課)。

如何推遲編譯器在運行時而不是編譯時檢查x的類型?

非常感謝!

回答

15

如何改正錯誤

你有一個implicit parameter添加到您的方法是這樣的:

def buildJsArray[T](l: List[T])(result: JsArray)(implicit tjs: Writes[T]): JsArray 

有一個在Json.toJson方法等參數。

您必須添加此參數的原因是您知道如何僅在知道T是什麼時纔將T轉換爲json。這意味着您只有在調用buildJsArray時纔有序列化T的方法,並且此參數允許您將此序列化方法傳遞給方法buildJsArray

如何建立一個JSArray

你可以只使用JsArray構造。它需要一個Seq[JsValue]

new JsArray(l.map{Json.toJson(_)}) 

已經有一個implicit WritesTraversable,所以你不需要你自己的方法buildJsArray,你可以只使用方法Json.toJsonList[T]類型的參數。

加成

你應該看一看集合API。它可以讓你寫出更可讀和更短的代碼:

def buildJsArray[T](l: List[T])(implicit tjs: Writes[T]): JsArray = 
    l.foldLeft(new JsArray){ (r, x) => r :+ Json.toJson(x) } 
+0

完美的答案,沒有什麼要補充:) –

+0

當JsObject(S)打交道時,你不能使用你的隱式通用OFormat類型。你需要爲OWrites和Reads做一個隱含的操作 – JMess