I have a simple example trait, which has a value of some generic type descended from Ordered. I can't find any way to actually use the value though as I get "Could not find implicit value for parameter ord: scala.math.Ordering[T]". Here's the code:
trait Example[T <: Ordered[_]] {
val key: T
def before(that: Example[T]): Boolean = (key < that.ke开发者_开发百科y)
}
Any ideas why this doesn't compile?
looks to me like it should be
trait Example[T <: Ordered[T]] {
I believe, I does not compile, because you saying that T
should be Ordered on any type. We can write an equivalent trait like this (please, correct me, if I'm wrong - I'm not sure whether it can be considered equivalent, but at least you will receive the same error from compiler):
trait Example1[A, T <: Ordered[A]] {
val key: T
def before(that: Example1[A, T]): Boolean = (key < that.key)
}
If you look in the Ordered
trait definition you will find something like this:
trait Ordered[A] extends java.lang.Comparable[A] {
...
def < (that: A): Boolean = (this compare that) < 0
...
}
object 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) }
}
When we will think in terms of this definition - if key
is Ordered[A]
than that.key
should be of type A
(according to <
method signature). So compiler can't actually use it on Ordered[A]
or in other words T
. And if I'm not mistaking it tries to find some Ordering[T]
(according to implicit definition in companion object) that can be used as last resort (but it fails).
So if you will define type parameter T
like T <: Ordered[T]
it will compile.
As another solution to this problem you can use context bound like in this example:
abstract class Example[T: Ordering] {
val key: T
val ord = implicitly[Ordering[T]]
import Ordered._
def before(that: Example[T]): Boolean = key < that.key
}
var one = new Example[Int] {val key = 1}
var two = new Example[Int] {val key = 2}
println(one.before(two)) // prints: true
println(two.before(one)) // prints: false
In this case implicit conversion would actually be used because we have evidence, that Ordering[T]
exists (traits can't have context or view bound, so I created abstract class)
Does it makes sense? If you find flaws in my logic - please comment! (I will appreciate this)
精彩评论