2011-01-13 10 views
7

Sto cercando di usare> =,>, ecc DateTime (Joda), e l'unico modo ho potuto farlo funzionare stava usando questa implicita conversionein grado di fornire conversione implicita da DateTime a ordinato tramite conversione implicita a Paragonabile

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

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

avrei preferito una forma più generica, come

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

Ma il compilatore non riesco a trovare questa conversione, e dopo aver tentato di richiamare direttamente, ho ottenuto il seguente messaggio sostenendo che DateTime non è di tipo Comparable [A]. Dopo aver controllato l'origine per DateTime, ho visto che implementa solo Paragonabile come tipo non elaborato.

sono stato in grado di farlo funzionare utilizzando

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

La mia domanda è: È questo il corretto trattamento Scala di questo problema, o sarebbe il tipo jolly legato causa problemi futuri con il controllo di tipo?

risposta

2

Vedi, il fatto è che questo esiste già. Beh, un po '... Se si guarda dentro oggetto Ordered, dove le conversioni implicite sono guardati per, troverete questo:

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

Quindi, fintanto che c'è un Ordering[T] a disposizione, si può produrre un Ordered[T]. Ora, per cercare un Ordering[T] dentro l'oggetto Ordering:

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

Quindi, se si passa un comparable: A with Comparable[A] a qualcosa in attesa di un Ordered[A], lo farà:

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

Ora, per quanto riguarda la tua domanda : l'uso di tipi esistenziali è il modo corretto di gestire i tipi di Java non elaborati. È teoricamente possibile che ciò si traduca in un ordine errato, ma, in pratica, estremamente improbabile. Si può avere problemi con l'ambiguità implicita, però, dal momento Scala hanno già una Comparable => Ordered conversione implicita, come visto sopra.

6

ci siamo imbattuti in questa domanda perché anch'io cercavo per confrontare gli oggetti Joda DateTime utilizzando gli operatori relazionali.

risposta di Daniel mi ha segnalato nella giusta direzione: i impliciti presenti in scala.math.Ordered convertiranno un'istanza di A extends java.lang.Comparable[A] a un Ordered[A] - hanno solo bisogno di essere portato in ambito.Il modo più semplice per fare questo (che ho imparato here, btw) è con il metodo implicitly:

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

Il problema è che non si estende org.joda.time.DateTime o implementare Comparable sé, eredita (indirettamente) da org.joda.time.ReadableInstant, che fa estende Comparable. Quindi questo:

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

non verrà compilato, perché il DateTime non si estende Comparable[DateTime]. Per utilizzare gli operatori relazionali Ordered s' su un DateTime, devi fare questo, invece:

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

che funziona perché ReadableInstant estende Comparable[ReadableInstant], e le conversioni implicite in Ordered può convertirlo in un Ordered[ReadableInstant].

Finora, tutto bene. Tuttavia, ci sono situazioni in cui uno Ordered[ReadableInstant] non è abbastanza buono. (Quello che ho incontrato è con ScalaTest di greater and less than Matchers.) Per ottenere una Ordered[DateTime], sono stato costretto a fare questo:

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

Sembra che ci dovrebbe essere un modo più semplice, ma non riuscivo a capire uno fuori.

+0

Penso che funzioni: 'import com.github.nscala_time.time.Imports._' – Chris

+0

Sì, funziona, ma solo se si sta utilizzando la libreria nscala-time. ;) –

+0

Mi piace la soluzione "Estendi ordini": breve e pulita e mantiene al minimo la "magia" – Integrator

Problemi correlati