我想做类似以下的事情:
val foo = List[B <% JValue] = 42 :: "hello" : Nil
让编译器知道我的列表的成员可以转换为JValue
s。
但是,这不会编译。我不能满足于 aList[Any]
因为我必须使用它的成员,其中可以转换为 JValues 的值是预期的,比如:
def fun[A <% JValue](x: List[A]) = ...
有没有办法解决这个问题?
我想做类似以下的事情:
val foo = List[B <% JValue] = 42 :: "hello" : Nil
让编译器知道我的列表的成员可以转换为JValue
s。
但是,这不会编译。我不能满足于 aList[Any]
因为我必须使用它的成员,其中可以转换为 JValues 的值是预期的,比如:
def fun[A <% JValue](x: List[A]) = ...
有没有办法解决这个问题?
你可以写
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 的人可以修复它,如果它是可能的。)
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))
您可以使用一组简单的隐式启用转换。
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 的方式提出更优雅/复杂的解决方案。