【问题标题】:how to pass generic types to Argonaut如何将泛型类型传递给 Argonaut
【发布时间】:2013-06-07 05:21:39
【问题描述】:

我正在尝试包装 Argonaut (http://argonaut.io) 以便在 Scala 项目中序列化/反序列化 JSON。我们以前在哪里使用 Jerkson,但由于它已停产,我们正在寻找替代方案。

这是基本的 JSON 包装器

import argonaut._, Argonaut._

object Json {
  def Parse[T](input: String): T = {
    input.decodeOption[T].get
  }
}

当我尝试编译它时,我得到以下错误。

could not find implicit value for evidence parameter of type argonaut.DecodeJson[T]
    input.decodeOption[T]
                  ^
not enough arguments for method decodeOption: (implicit evidence$6: argonaut.DecodeJson[T]) Option[T].
Unspecified value parameter evidence$6.
    input.decodeOption[T]
                  ^

任何关于如何解决此问题的建议或关于我做错了什么的指针将不胜感激。

也非常欢迎对替代 JSON 框架提出建议。

我对 Scala/Java 以及泛型如何在那里工作有点陌生,但我已经编写 .NET/C# 很多年了。

【问题讨论】:

  • 我假设decodeOption返回Option,但是你的方法返回T
  • 感谢 lukas,忘记在示例中添加 .get。

标签: scala jerkson


【解决方案1】:

似乎 Argonaut 与几乎所有 scala 序列化库一样,使用类型类模式。这听起来很花哨,但实际上它只是意味着在序列化/反序列化 T 类型的对象时,它需要您隐式传递另一个对象的实例,该对象的部分或全部过程被推迟到。 具体来说,当您执行decodeOption[T] 时,您需要在范围内拥有argonaut.DecodeJson[T] 的实例(decodeOption 将在反序列化期间使用)。

您应该做的只是要求将此隐式值传递给Parse(然后它会自动传递给decodeOption

def Parse[T](input: String)(implicit decoder: argonaut.DecodeJson[T]): Option[T] = {
  input.decodeOption[T]
}

Scala 甚至提供了一些语法糖来使声明更短(这称为“上下文绑定”):

def Parse[T:argonaut.DecodeJson](input: String): Option[T] = {
  input.decodeOption[T]
}

现在,当调用Parse 时,您需要在作用域中引入argonaut.DecodeJson 的隐式值,否则调用将无法编译。显然Argonaut 对象已经为许多标准类型定义了解码器,因此对于这些类型,您无需做任何特别的事情。 对于其他类型(例如您的自定义类型),您必须定义解码器并导入它们。

【讨论】:

    【解决方案2】:

    为了使您的代码正常工作,您需要重新定义 Json 对象,如下所示:

    object Json {
      def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = {
        input.decodeOption[T]
      }
    }
    

    您缺少的是隐含的 DecodeJson 实例,decodeOption 函数需要它来弄清楚如何解码。您还需要将返回类型定义为Option[T] 而不仅仅是T。这一切工作的完整示例如下所示:

    import argonaut._, Argonaut._
    case class User(id:Long, email:String, name:String)
    
    object Json {
      def Parse[T](input: String)(implicit decode:DecodeJson[T]): Option[T] = {
        input.decodeOption[T]
      }
    }
    
    object JsonTest{
      implicit val userDecode = casecodec3(User.apply, User.unapply)("id", "email", "name")
    
      def main(args: Array[String]) {
        val json = """{
          "id": 1,
          "email": "foo@test.com",
          "name": "foo bar"
        }"""
    
        val userOpt = Json.Parse[User](json)
        println(userOpt)
      }
    }
    

    至于其他 Json 框架,您可以查看:

    Play Json

    json4s

    spray-json

    Jackson Scala Module

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-04
      • 1970-01-01
      相关资源
      最近更新 更多