簡體   English   中英

`circe`類型級Json =>一個函數?

[英]`circe` Type-level Json => A Function?

使用circeargonaut ,如何寫一個Json => A (注意 - Json可能不是該類型的名稱),其中ASSN類給出:

  // A USA Social Security Number has exactly 8 digits.
  case class SSN(value: Sized[List[Nat], _8])

偽代碼:

// assuming this function is named f

f(JsArray(JsNumber(1)))因為它的大小為1而不能成為A ,而

f(JsArray(JsNumber(1), ..., JsNumber(8))) === SSN(SizedList(1,...,8))

circe(當前)沒有為Sized提供實例,但它可能應該。 在任何情況下,你都可以直截了當地寫自己的:

import cats.data.Xor
import io.circe.{ Decoder, DecodingFailure }
import shapeless.{ Nat, Sized }
import shapeless.ops.nat.ToInt
import shapeless.syntax.sized._

implicit def decodeSized[L <: Nat, A](implicit
  dl: Decoder[List[A]],
  ti: ToInt[L]
): Decoder[Sized[List[A], L]] = Decoder.instance { c =>
  dl(c).flatMap(as =>
    Xor.fromOption(as.sized[L], DecodingFailure(s"Sized[List[A], _${ti()}]", c.history))
  )
}

我已將此限制為List表示,但如果您願意,可以使其更通用。

現在你可以像這樣編寫你的SSN實例(請注意,我使用的是Int而不是Nat用於個別數字,因為一旦你得到一些靜態類型為Nat東西,它就不值得了):

case class SSN(value: Sized[List[Int], Nat._8])

implicit val decodeSSN: Decoder[SSN] = Decoder[Sized[List[Int], Nat._8]].map(SSN(_))

然后:

scala> import io.circe.jawn.decode
import io.circe.jawn.decode

scala> decode[SSN]("[1, 2, 3, 4, 5, 6, 7, 8]")
res0: cats.data.Xor[io.circe.Error,SSN] = Right(SSN(List(1, 2, 3, 4, 5, 6, 7, 8)))

scala> decode[SSN]("[1, 2, 3, 4, 5, 6, 7]")
res1: cats.data.Xor[io.circe.Error,SSN] = Left(DecodingFailure(Sized[List[A], _8], List()))

如果你真的想要Json => SSN你可以這樣做:

val f: Json => SSN = Decoder[SSN].decodeJson(_).valueOr(throw _)

但這並不是對circe的慣用。

暫無
暫無

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

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