scala 排序和已排序并比较选项

jvlzgdj9  于 2023-02-04  发布在  Scala
关注(0)|答案(6)|浏览(165)

给定:

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:* 为什么不,我如何才能让它工作?
kdfy810k

kdfy810k1#

如果你安装了对默认范围来说有点太神奇的奖励暗示,你可以这样比较选项:

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到类的隐式的中缀操作,这样就足够了,不需要另一个导入。

piwo6bdm

piwo6bdm2#

关于你的第一个问题:Ordered[T]扩展了Comparable[T]Ordering伴随对象为任何可以转换为Comparable[T]的值提供了隐式Ordering[T]

implicit def ordered[A <% Comparable[A]]: Ordering[A]

A : Ordering => Ordered[A]没有隐式转换-这就是Some(1) > Some(2)无法工作的原因。
定义这样的转换是否是一个好主意值得怀疑,因为您可能最终将对象 Package 成Ordered示例,然后再创建一个Ordering示例(依此类推...)。您可以创建两个Ordered示例,在作用域中具有不同的Ordering示例,这当然不是您想要的。

mwkjh3gx

mwkjh3gx3#

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
h5qlskok

h5qlskok4#

回答你的第二个问题,为什么你不能这样做: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],所以它不会那么难看,你也不需要显式的向上转换。

uhry853o

uhry853o5#

我假设你理解为什么当你没有传入一个Ordering并且在作用域中没有一个可用的时候sorted不起作用。至于为什么当你从Ordered trait扩展你的类的时候sorted函数起作用。答案是当你从Ordered trait扩展的时候,代码类型检查trait包含像〈,〉等。因此不需要进行隐式转换,因此不会抱怨缺少隐式排序。
至于您的第二个问题,Some(2) > Some(1)将不起作用,因为Some没有扩展特征Ordered,作用域中似乎也没有任何隐式函数将Some隐式转换为具有函数>的对象

vvppvyoh

vvppvyoh6#

感谢您提供详细的问题和示例。
我的答案是基于我从一个伟大的文章在这里学习: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.scalaOrdered的伴随对象在此处提供了所需的转换:
/** Lens fromOrdering[T]toOrdered[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) }
然而,反向转换没有定义,我不知道为什么?

相关问题