1

我想做类似以下的事情:

val foo = List[B <% JValue] = 42 :: "hello" : Nil

让编译器知道我的列表的成员可以转换为JValues。

但是,这不会编译。我不能满足于 aList[Any]因为我必须使用它的成员,其中可以转换为 JValues 的值是预期的,比如:

def fun[A <% JValue](x: List[A]) = ...

有没有办法解决这个问题?

4

3 回答 3

5

你可以写

val foo: List[JValue] = List(42, "hello")

如果没有从这些类型到的隐式转换,JValue则不会进行类型检查。

不幸的是,您无法编写它,42 :: "hello" :: Nil因为编译器不够聪明,无法知道您要对每个术语应用转换(您可以在每个术语上添加类型注释,但这很麻烦)。每个::方法都必须以某种方式一直向前看直到表达式的末尾,以检查以后的某个方法是否使其适合类型参数。

但是,如果您想添加自己的时髦运算符,您可以限制允许的类型::

implicit class pimp(xs: List[JValue]) {
  def |: (x: JValue) = x :: xs
}

之后你可以写这样的东西:

val foo = 42 |: "hello" |: Nil
  // type is List[JValue]

(我尝试对其进行参数化,以便它可以推断出最具体的常见类型,::但是如果有上限,编译器不想玩球 -请参见此处。也许有更多 Scala-fu 的人可以修复它,如果它是可能的。)

于 2013-07-08T03:51:53.173 回答
2

Luigi Plinge回答|:对方法进行了一点改进:

你可以写

val foo: List[JValue] = 42 :: "hello" :: HNil

使用适当的隐式转换(使用shapeless):

import shapeless._

trait HListTConv[H <: HList, T] {
  def apply(l: List[T], hl: H): List[T]
}

object HListTConv {
  implicit def apply0[T] = new HListTConv[HNil, T] {
    def apply(l: List[T], hl: HNil): List[T] = l
  }

  implicit def applyN[Head, Tail <: HList, T](implicit c: HListTConv[Tail, T], conv: Head => T) =
    new HListTConv[Head :: Tail, T] {
      def apply(l: List[T], hl: Head :: Tail): List[T] = (hl.head: T) :: c(l, hl.tail)
    }
}

implicit def hListToJValueList[H <: HList](hl: H)(implicit c: HListTConv[H, JValue]): List[JValue] = c(Nil, hl)

测试:

case class Test(s: String)
implicit def intToTest(i: Int): Test = Test(i.toString)
implicit def strToTest(s: String): Test = Test(s)

implicit def hListToListTest[H <: HList](hl: H)(implicit c: HListTConv[H, Test]): List[Test] = c(Nil, hl)

scala> val foo: List[Test] = 42 :: "hello" :: HNil
foo: List[Test] = List(Test(42), Test(hello))
于 2013-07-08T05:00:08.020 回答
0

您可以使用一组简单的隐式启用转换。

class JValue
implicit intToJValue(x: Int) = new JValue
implicit stringToJValue(x: String) = new JValue

val xs: List[JValue] = List(1, "hello")

对于您的第二个问题,您可以通过以下方式启用批发列表转换:

implicit def listToJList[A <% JValue](xs: List[A]): List[JValue] = xs
def foo[A <% JValue](x: List[A]): List[JValue] = x

上面的示例仅在您具有统一类型时才有效,否则您将需要采用更复杂的方法,在大多数情况下,异构类型的列表将统一为 List[Any]。

您可以使用无形的,大多数采用 shapless.Poly 和 HList 的方式提出更优雅/复杂的解决方案。

于 2013-07-08T02:20:51.677 回答