使用 Scala CLI,您可以在單一行中要求整個 Toolkit
//> using toolkit latest
或者,您也可以只要求特定版本的 UPickle
//> using dep com.lihaoyi::upickle:3.1.0
在您的 build.sbt 檔案中,您可以新增對 Toolkit 的依賴項
lazy val example = project.in(file("example"))
.settings(
scalaVersion := "3.2.2",
libraryDependencies += "org.scala-lang" %% "toolkit" % "0.1.7"
)
或者,您也可以只要求特定版本的 UPickle
libraryDependencies += "com.lihaoyi" %% "upickle" % "3.1.0"
在您的 build.sc 檔案中,您可以新增對 upickle 函式庫的依賴項
object example extends ScalaModule {
def scalaVersion = "3.2.2"
def ivyDeps =
Agg(
ivy"org.scala-lang::toolkit:0.1.7"
)
}
或者,您也可以只要求特定版本的 UPickle
ivy"com.lihaoyi::upickle:3.1.0"
剖析與反序列化
使用 uJson 剖析只接受有效的 JSON,但它不會驗證欄位的名稱和類型是否符合預期。
反序列化則將 JSON 字串轉換為使用者指定的 Scala 資料類型,如果必要欄位存在且具有正確的類型。
在本教學課程中,我們將展示如何反序列化為 Map
,以及自訂 case class
。
將 JSON 反序列化為 Map
對於類型 T
,uPickle 可以將 JSON 反序列化為 Map[String, T]
,檢查所有欄位是否符合 T
。
例如,我們可以反序列化為 Map[String, List[Int]]
val json = """{"primes": [2, 3, 5], "evens": [2, 4, 6]} """
val map: Map[String, List[Int]] =
upickle.default.read[Map[String, List[Int]]](json)
println(map("primes"))
// prints: List(2, 3, 5)
如果值類型錯誤,uPickle 會擲出 upickle.core.AbortException
。
val json = """{"name": "Peter"} """
upickle.default.read[Map[String, List[Int]]](json)
// throws: upickle.core.AbortException: expected sequence got string at index 9
將 JSON 反序列化為自訂資料類型
在 Scala 中,您可以使用 case class
來定義自己的資料類型。例如,若要表示寵物主人,您可以
case class PetOwner(name: String, pets: List[String])
若要從 JSON 讀取 PetOwner
,我們必須提供 ReadWriter[PetOwner]
。uPickle 可以自動執行此操作
import upickle.default._
implicit val ownerRw: ReadWriter[PetOwner] = macroRW[PetOwner]
一些說明
implicit val
是可以自動提供為方法或函式呼叫的引數的值,而不必明確傳遞。macroRW
是 uPickle 提供的方法,可以使用欄位資訊為 case class 產生ReadWriter
的執行個體。
import upickle.default.*
case class PetOwner(name: String, pets: List[String])
derives ReadWriter
derives
關鍵字用於自動產生已給予的執行個體。使用編譯器對 PetOwner
中欄位的知識,它會產生 ReadWriter[PetOwner]
。
這表示您現在可以使用 upickle.default.read(petOwner)
從 JSON 讀取 (和寫入) PetOwner
物件。
請注意,您不需要將 ReadWriter[PetOwner]
的實例明確傳遞給 read
方法。但它確實會從上下文中取得它,作為「已給定」的值。您可以在 Scala 3 Book 中找到更多關於上下文抽象的資訊。
將所有內容放在一起,您應該會得到
import upickle.default._
case class PetOwner(name: String, pets: List[String])
implicit val ownerRw: ReadWriter[PetOwner] = macroRW
val json = """{"name": "Peter", "pets": ["Toolkitty", "Scaniel"]}"""
val petOwner: PetOwner = read[PetOwner](json)
val firstPet = petOwner.pets.head
println(s"${petOwner.name} has a pet called $firstPet")
// prints: Peter has a pet called Toolkitty
import upickle.default.*
case class PetOwner(name: String, pets: List[String]) derives ReadWriter
val json = """{"name": "Peter", "pets": ["Toolkitty", "Scaniel"]}"""
val petOwner: PetOwner = read[PetOwner](json)
val firstPet = petOwner.pets.head
println(s"${petOwner.name} has a pet called $firstPet")
// prints: Peter has a pet called Toolkitty