如何在Scala中表达这种类型?存在类型类(即隐式)限制吗?

编程入门 行业动态 更新时间:2024-10-14 08:23:24
本文介绍了如何在Scala中表达这种类型?存在类型类(即隐式)限制吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在使用Play框架的JSON库,该库使用类型类来实现 Json.toJson函数. (我可能会决定使用其他静态类型较少的技术,例如反射;但是现在我想使用这个库,因为它可以帮助我学习Scala类型系统.)

I'm using the Play framework's JSON library, which uses a type class to implement the Json.toJson function. (I may decide to use another technique with less static typing, like reflection; but for now I want to use this library because it's helping me learn the Scala type system.)

我有一堆需要传递给toJson的简单案例类,因此我必须为它们每个实现一个隐式的Writes[T]对象.对于每个类,初裁看起来可能都是这样.

I have a bunch of simple case classes that need to be passed to toJson, so I have to implement an implicit Writes[T] object for each of them. A first cut might look like this, for each of the classes.

// An example class case class Foo(title: String, lines: List[String]) // Make 'Foo' a member of the 'Writes' typeclass implicit object FooWrites extends Writes[Foo] { def writes(f: Foo) : JsValue = { val fields = Seq("title" -> toJson(f.title), "lines" -> toJson(f.lines)) JsObject(fields) } }

每个类都将具有相似的隐式值,因此我可以对公共部分进行抽象,如下所示.但这不能编译,因为我不确定如何声明类型.

Each class will have a similar implicit value, so I could abstract the common part, as below. But this doesn't compile, because I'm not sure how to declare the type.

def makeSimpleWrites[C](fields: (String, C => T??)*) : Writes[C] = { new Writes[C] { def writes(c: C) : JsValue = { val jsFields = fields map { case (name, get) => (name, toJson(get(c)))} JsObject(jsFields) } } } implicit val fooWrites : Writes[Foo] = makeSimpleWrites[Foo]("title" -> {_.title}, "lines" -> {_.lines}) implicit val otherWrites ...

问题是我要传递给makeSimpleWrites的类型T.它不能是普通的类型参数,因为对于fields中的每个项目,T都是不同的.这是存在类型吗?我尚未使用其中之一.语法不正确...

The issue is the type T that I want to pass to makeSimpleWrites. It can't be a normal type parameter because that T is different for each item in fields. Is this an existential type? I have yet to use one of these. Flailing at syntax...

def makeSimpleWrites[C](fields: (String, C=>T forSome { type T; implicit Writes[T] })*)

在Scala中这可能吗?如果是这样,语法是什么?

Is this possible in Scala? If so, what is the syntax?

推荐答案

由于每个字段都有不同的类型,因此每个字段需要一个类型参数.这是因为要编写这些字段,您需要(隐式地)为相应的类型(针对方法toJson)提供Writes实例,并且这些实例是静态解析的.

Because each field has a different type, you would need one type parameter per field. This is because to write these fields, you need to provide (implicitly) the Writes instances for the corresponding types (to method toJson), and those are resolved statically.

解决此问题的一种解决方案是将过程分为两部分:一种方法,您需要为每个字段调用以提取字段访问器并将其与相应的WriteS实例打包在一起(甚至可以进行隐式转换)从您已经通过的paairs)和一种方法,将整体并创建最终的WriteS实例.这样的东西(说明性的,未经测试的):

One solution to work around this is to split the process in two parts: one method that you call for each field to extract the field accessor and pack it with the corresponding WriteS instance (this can even be maed an implicit conversion from the paairs that you are already passing), and one method that takes the whole and creates the final WriteS instance. Something like this (illustrative, untested):

class WriteSFieldAccessor[C,T] private ( val title: String, val accessor: C => Any )( implicit val writes: Writes[T] ) implicit def toWriteSFieldAccessor[C,T:Writes]( titleAndAccessor: (String, C => T) ): WriteSFieldAccessor = { new WriteSFieldAccessor[C,T]( titleAndAccessor._1, titleAndAccessor._2 ) } def makeSimpleWrites[C](fields: WriteSFieldAccessor[C,_]*) : Writes[C] = { new Writes[C] { def writes(c: C) : JsValue = { val jsFields = fields map { f: WriteSFieldAccessor => val jsField = toJson[Any](f.accessor(c))(f.writes.asInstanceOf[Writes[Any]]) (f.title, jsField) } JsObject(jsFields) } } } // Each pair below is implicitly converted to a WriteSFieldAccessor instance, capturing the required information and passing it to makeSimpleWrites implicit val fooWrites : Writes[Foo] = makeSimpleWrites[Foo]("title" -> {_.title}, "lines" -> {_.lines})

有趣的部分是toJson[Any](f.accessor(c))(f.writes..asInstanceOf[Writes[Any]]).您只需将Any作为静态类型传递,但会显式传递(通常是隐式的)Writes实例.

The interesting part is toJson[Any](f.accessor(c))(f.writes..asInstanceOf[Writes[Any]]). You just pass Any as a the static type but explicitly pass the (normally implicit) Writes instance.

更多推荐

如何在Scala中表达这种类型?存在类型类(即隐式)限制吗?

本文发布于:2023-07-14 10:14:39,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1104076.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:类型   隐式   如何在   Scala

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!