2011-09-29 63 views
18

考慮:訂購和有序和比較選項

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)) 

雖然沒有參與排序或implicits。

問題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:爲什麼不呢,我怎麼能得到它的工作?

回答

9

關於你的第一個問題: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)將無法​​正常工作。

定義這樣一個轉換是個好主意,因爲您最終可能會將對象包裝到Ordered實例中,然後再創建一個Ordering(等等......)。更糟的是:你可以在範圍內創建兩個Ordered實例,其中不同的Ordering實例的範圍當然不是你想要的。

2

名單的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 
+0

這並沒有真正回答爲什麼實現Ordered [T]神奇地帶來Ordering [T]的一個實例的問題。爲什麼你必須創建一個方法才能進行最後的比較? –

+0

我做了這個方法,所以我可以訪問Ordering的實例。我導入該實例的內容,以便我可以將其隱式轉換爲定義一些比較運算符的'Ops'。使用相同的方法,我終於明白了「Ordered」的隱式轉換的位置。 http://www.scala-lang.org/api/current/index.html#scala.math.LowPriorityOrderingImplicits – Dylan

+0

但這似乎相當多的工作,只是爲了能夠比較兩個選項? –

23

如果您安裝了輕微太不可思議換默認範圍獎金implicits,你可以比較的選項,如下所示:

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 

進口爲您提供了從訂貨隱式與類中綴操作,這樣就可以在沒有其他導入的情況下完成訂單。

+0

更好...但仍然很多工作,在我可能不是很謙虛的意見。 :)我知道可能有這樣的原因,但從用戶的角度來看,您可以比較兩個選項而不用模糊,因爲您可以排除它們的列表而不會發生任何模糊,這似乎是合乎邏輯的。 ..因爲你必須在其他方面比較排序,對吧? –

+0

您可以對它們進行排序,因爲您調用了採用隱式排序的方法。這裏您正在編寫一個採用隱式排序的方法。在某個地方,訂購必須輸入圖片,因爲任意選項[T]不具有可比性。 – extempore

0

我假設你明白爲什麼排序不起作用,當你不通過一個訂單,沒有範圍可用。 至於爲什麼當你從有序特徵擴展你的類時,排序後的函數會起作用。答案是,當你從有序特徵擴展時,代碼類型會檢查特徵是否包含像<這樣的函數,>等。因此不需要進行隱式轉換,因此不會抱怨缺少隱式排序。

關於你的第二個問題,Some(2) > Some(1)將無法​​工作,因爲有些不延長特質有序,同樣沒有出現似乎是在範圍內的任何隱函數,隱式轉換一個部分的東西,具有的功能>

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]所以它不會那麼難看,你不會需要明確的向上轉型。