2011-01-13 20 views
7

Estoy tratando de usar> =,>, etc. con DateTime (joda), y la única forma en que podría hacerlo funcionar era usando este implícito conversiónNo se puede proporcionar la conversión implícita de DateTime a Ordered usando la conversión implícita a Comparable

implicit def dateTime2ordered(x: DateTime): Ordered[DateTime] = 
new Ordered[DateTime] with Proxy { 
    val self = x 

    def compare(y: DateTime): Int = { 
    x.compareTo(y) 
    } 
} 

yo hubiera preferido una forma más genérica como

implicit def comparable2ordered[A <: Comparable[A]](x: A): Ordered[A] = 
    new Ordered[A] with Proxy { 
     val self = x 

     def compare(y: A): Int = { 
     x.compareTo(y) 
     } 
    } 

Pero el compilador no puede encontrar esta conversión, y después de intentar invocar directamente, he recibido el mensaje siguiente afirmando que DateTime no es del tipo Comparable [A]. Después de verificar el origen de DateTime, vi que solo implementa Comparable como tipo sin procesar.

que era capaz de conseguir que funcione utilizando

implicit def comparable2ordered[A <: Comparable[_]](x: A): Ordered[A] = 
    new Ordered[A] with Proxy { 
     val self = x 

     def compare(y: A): Int = { 
     x.compareTo(y) 
     } 
    } 

Mi pregunta es: ¿Es este el tratamiento Scala correcta de este problema, o sería el tipo de comodín con destino causa problemas futuros con la comprobación de tipos?

Respuesta

2

Mira, la cosa es que esto ya existe. Bueno, algo así ... Si nos fijamos en el interior de objeto Ordered, donde las conversiones implícitas se buscan, se encuentra esta:

implicit def orderingToOrdered [T] (x: T)(implicit ord: Ordering[T]) : Ordered[T] 

Por lo tanto, siempre que hay una Ordering[T] disponibles, se puede producir un Ordered[T]. Ahora, a buscar una Ordering[T] dentro del objeto Ordering:

implicit def ordered [A] (implicit arg0: (A) ⇒ Comparable[A]) : Ordering[A] 

lo tanto, si se pasa un comparable: A with Comparable[A] a algo esperando una Ordered[A], que va a hacer esto:

Ordered.orderingToOrdered(comparable)(Ordering.ordered(Predef.identity(comparable))) 

Ahora, en cuanto a su pregunta : el uso de tipos existenciales es la forma correcta de manejar tipos RAW de Java. Es teóricamente posible que esto resulte en un orden incorrecto, pero, en la práctica, extremadamente improbable. Usted puede tiene problemas con la ambigüedad implícita, sin embargo, ya que Scala ya tiene una conversión implícita Comparable => Ordered, como se ve arriba.

6

Me encontré con esta pregunta porque yo también estaba buscando comparar objetos joda DateTime utilizando operadores relacionales.

respuesta de Daniel me señaló en la dirección correcta: los implícitos presentes en scala.math.Ordered convertirán una instancia de A extends java.lang.Comparable[A] a un Ordered[A] - que sólo tiene que ser llevado a su alcance.La manera más fácil de hacer esto (que aprendí here, por cierto) es con el método implicitly:

val aOrdering = implicitly[Ordering[A]] 
import aOrdering._ 

El problema es que no se extiende org.joda.time.DateTime o implementan Comparable sí, hereda (indirectamente) de org.joda.time.ReadableInstant, que hace extiende Comparable. Así que esto:

val dateTimeOrdering = implicitly[Ordering[DateTime]] 
import dateTimeOrdering._ 

no se compilará, porque el DateTime no se extiende Comparable[DateTime]. Para utilizar operadores relacionales Ordered 's en un DateTime, que tiene que hacer esto en su lugar:

val instantOrdering = implicitly[Ordering[ReadableInstant]] 
import instantOrdering._ 

el cual funciona porque ReadableInstant extiende Comparable[ReadableInstant], y las conversiones implícitas en Ordered puede convertirlo en un Ordered[ReadableInstant].

Hasta ahora, todo bien. Sin embargo, hay situaciones en las que un Ordered[ReadableInstant] no es lo suficientemente bueno. (El que me encontré es con ScalaTest de greater and less than Matchers.) Para obtener una Ordered[DateTime], me vi obligado a hacer esto:

implicit object DateTimeOrdering extends Ordering[DateTime] { 
    def compare(d1: DateTime, d2: DateTime) = d1.compareTo(d2) 
} 

Parece que debe haber una manera más fácil, pero no podía imaginar un out.

+0

Creo que esto funciona: 'import com.github.nscala_time.time.Imports._' – Chris

+0

Sí, eso funciona, pero solo si está usando la biblioteca nscala-time. ;) –

+0

Me gusta la solución "extends orders": corta y limpia y mantiene la "magia" al mínimo – Integrator

Cuestiones relacionadas