我想这样做如下:如何给Scala编译器证明集合具有正确类型的元素?
val foo = List[B <% JValue] = 42 :: "hello" : Nil
编译器知道我的列表的成员可以转换为JValue
秒。
然而,这并不编译。我不能满足于一个List[Any]
因为我有利用其成员在那里可以转换成JValues值预计,在说:
def fun[A <% JValue](x: List[A]) = ...
有什么办法解决?
我想这样做如下:如何给Scala编译器证明集合具有正确类型的元素?
val foo = List[B <% JValue] = 42 :: "hello" : Nil
编译器知道我的列表的成员可以转换为JValue
秒。
然而,这并不编译。我不能满足于一个List[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]
(我尝试参数化它,以便它可以推断出最具体的通用类型,如::
所做的那样,但编译器的上限不想玩球 - see here。也许有更多Scala-fu的人可以修复它,如果它是poss IBLE。)
是[这个答案](http://stackoverflow.com/a/17519454/406435)斯卡拉足够了吗? – senia
您可以使用一组简单的含义来启用转换。
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来提出更优雅/复杂的解决方案。
从|:
的方法稍加改进Luigi Plinge的answer:
你可以写
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))
HLists? (https://github.com/milessabin/shapeless) – adelbertc
什么是错误信息?你试过吗?(42:JValue)::(“hello”:JValue):: Nil'? – huynhjl