假设:
case class Person(name: String)
并尝试做:
scala> List(Person("Tom"), Person("Bob")).sorted
导致对丢失订购的投诉。
<console>:8: error: could not find implicit value for parameter ord: Ordering[Person]
List(Person("Tom"), Person("Bob")).sorted
但是这个:
case class Person(name: String) extends Ordered[Person] {
def compare(that: Person) = this.name compare that.name }
按预期正常工作:
scala> List(Person("Tom"), Person("Bob")).sorted
res12: List[Person] = List(Person(Bob), Person(Tom))
虽然没有涉及订购或暗示。
问题#1:这里发生了什么? (我的钱是隐含的......)
然而,考虑到上述事实,这个:
scala> Person("Tom") > Person("Bob")
res15: Boolean = true
有效,也是这样:
scala> List(Some(2), None, Some(1)).sorted
开箱即用:
res13: List[Option[Int]] = List(None, Some(1), Some(2))
我希望如此:
scala> Some(2) > Some(1)
也可以,但不会:
<console>:6: error: value > is not a member of Some[Int]
Some(2) > Some(1)
问题#2:为什么不呢,我怎样才能让它发挥作用?
答案 0 :(得分:26)
如果您安装稍微过于神奇的默认范围内的奖励,则可以比较以下选项:
scala> import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
scala> def cmpSome[T: Ordering](x: Option[T], y: Option[T]) = x < y
cmpSome: [T](x: Option[T], y: Option[T])(implicit evidence$1: Ordering[T])Boolean
导入为您提供了一个隐含的从订购到具有中缀操作的类,因此它足以让Ordering不再导入。
答案 1 :(得分:10)
关于您的第一个问题:Ordered[T]
延伸Comparable[T]
。 Ordering
随播广告对象为可以转换为Ordering[T]
的任何值提供隐式Comparable[T]
:
implicit def ordered[A <% Comparable[A]]: Ordering[A]
没有隐式转化A : Ordering => Ordered[A]
- 这就是Some(1) > Some(2)
无效的原因。
定义这样的转换是否是个好主意,因为您可能最终将对象包装到Ordered
个实例中,然后再次创建Ordering
个实例(依此类推...... )。更糟糕的是:您可以在范围内创建两个Ordered
个实例,但这些实例当然不是您想要的。
答案 2 :(得分:2)
List的sorted
方法的定义是:
def sorted [B >: A] (implicit ord: Ordering[B]): List[A]
所以是的,隐式事情正在发生,但标准库中的许多类都有与之关联的隐式对象,而不必先导入它们。
Ordering伴侣对象定义了一堆隐式排序。其中包括OptionOrdering和IntOrdering,它有助于解释列表调用sorted
的能力。
要获得在可用隐式转换时使用运算符的功能,您需要导入该对象,例如:
def cmpSome(l:Option[Int], r:Option[Int])(implicit ord:Ordering[Option[Int]]) = {
import ord._
l < r
}
scala> cmpSome(Some(0), Some(1))
res2: Boolean = true
答案 3 :(得分:2)
要回答第二个问题,为什么不能这样做:Some(2) > Some(1)
您可以导入并使用Option[Int]
而不是Some[Int]
。
@ import scala.math.Ordering.Implicits._
import scala.math.Ordering.Implicits._
@ Some(2) > Some(1) // doesn't work
cmd11.sc:1: value > is not a member of Some[Int]
val res11 = Some(2) > Some(1)
^
Compilation Failed
@ (Some(2): Option[Int]) > (Some(1): Option[Int]) // Option[Int] works fine
res11: Boolean = true
@ Option(2) > Option(1)
res12: Boolean = true
@ (None: Option[Int]) > (Some(1): Option[Int])
res13: Boolean = false
在实践中,您的类型可能是Option[Int]
而不是Some[Int]
,所以它不会那么难看,您也不需要明确的向上转换。
答案 4 :(得分:0)
我假设你理解为什么当你没有传递一个Ordering并且在范围内没有可用时,sort不起作用。 至于为什么在从Ordered trait扩展类时,排序函数的工作原理。答案是当你从Ordered trait扩展时,代码类型检查trait包含的函数如&lt;,&gt;因此,没有必要进行隐式转换,因此没有抱怨缺少隐式订购。
关于你的第二个问题,Some(2) > Some(1)
将不起作用,因为有些不扩展特征Ordered,在范围内似乎没有任何隐式函数隐式地将Some转换为具有函数{{ 1}}
答案 5 :(得分:0)
感谢您提供带有示例的详细问题。
我的答案基于我从这里的一篇出色文章中学到的知识:http://like-a-boss.net/2012/07/30/ordering-and-ordered-in-scala.html
在此归功于作者。
引用该文章:
Coming back to our Box example - the scala library defines an implicit conversion between Ordered[T] and Ordering[T] and vice-versa.
https://github.com/scala/scala/blob/2.12.x/src/library/scala/math/Ordered.scala中Ordered
的伴随对象在此处提供了所需的转换:
/** Lens from `Ordering[T]` to `Ordered[T]` */
implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
但是反向转换没有定义,我不确定为什么吗?