这其实不是太难写一个版本sschaef提出,将用于任意嵌套列表的工作类型的类方法:在我们rev
方法
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def rev[A](implicit ev: Reverser[A] = null) = new Reverser[List[A]] {
def reverse(xs: List[A]) =
Option(ev).map(r => xs map r.reverse).getOrElse(xs).reverse
}
def deepReverse[A](xs: A)(implicit ev: Reverser[A]): A = ev.reverse(xs)
的隐含参数ev
证据表明A
本身可逆的,并且如果ev
为空,则意味着它不是。如果我们有证据表明A
是可逆的,我们用它来反转我们的List[A]
的元素(这就是map
正在做的),然后我们反转列表本身。如果我们没有这个证据(getOrElse
的情况),我们可以颠倒这个列表。
我们可以写rev
少一点简洁(但可能更performantly)是这样的:
implicit def rev[A](implicit ev: Reverser[A] = null) = if (ev == null) {
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
} else {
new Reverser[List[A]] {
def reverse(xs: List[A]) = (xs map ev.reverse).reverse
}
}
为了测试这两种版本,我们可以写出如下:
scala> deepReverse(List.tabulate(3)(identity))
res0: List[Int] = List(2, 1, 0)
scala> deepReverse(List.tabulate(2,3) { case (a, b) => a + b })
res1: List[List[Int]] = List(List(3, 2, 1), List(2, 1, 0))
scala> deepReverse(List.tabulate(2, 3, 4, 5, 6) {
| case (a, b, c, d, e) => a + b + c + d + e
| }).head.head.head.head
res2: List[Int] = List(15, 14, 13, 12, 11, 10)
由于预期。
我要补充一点,下面是一个比较常见的成语用于获取implicits就在这样的情况下:
trait ReverserLow {
implicit def listReverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
}
object ReverserHigh extends ReverserLow {
implicit def nestedListReverser[A](implicit ev: Reverser[A]) =
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.map(ev.reverse).reverse
}
}
import ReverserHigh._
如果我们刚刚写listReverser
和nestedListReverser
在同一水平,当我们尝试反转列表清单时,我们会收到以下错误:
scala> deepReverse(List.tabulate(2, 3)(_ + _))
<console>:12: error: ambiguous implicit values:
both method listReverser...
and method nestedListReverser...
match expected type Reverser[List[List[Int]]]
deepReverse(List.tabulate(2, 3)(_ + _))
优先化两者的标准方法是将较低优先级的imp (WhateverLow
)的合法性,另一个在延伸该特征的对象(WhateverHigh
)中。在这样一个相当简单的例子中,尽管如此,在我的rev
方法中使用默认参数技巧更简洁(在我眼中更清晰)。但是你更有可能在其他人的代码中看到其他版本。
该死!我没有想过将类型类型注入自己。大把戏! – sschaef
太棒了!那么,如果没有地图返回,getOrElse会自己返回值?非常感激。 –
@GrittyKitty:谢谢!请参阅我的更新,了解更多关于此技巧的解释。 –