2012-01-12 17 views
5

voglio definire un tratto Swappable con due valori x,y e un metodo swap tale che chiamare swap su un oggetto che eredita dalla Swappable rendimenti un'altra oggetto dello stesso tipo con x,y acceso. Il mio migliore finora è:Trait swap a Scala

trait Swappable[T] { 
    val x: T 
    val y: T 
    def swap: Swappable[T] = { 
    val (a,b) = (x,y) 
    new Swappable[T] { val x=b; val y=a } 
    } 
} 

Ma questo non è quello che voglio, perché il tipo di ritorno di swap è una certa classe anonima, al posto della classe originale ho iniziato con, in modo da ottenere gli errori come:

def direct[S<:Swappable[Int]](s: S): S = if (s.x > s.y) s else s.swap 
<console>:32: error: type mismatch; 
found : Swappable[Int] 
required: S 
     def direct[S<:Swappable[Int]](s: S): S = if (s.x > s.y) s else s.swap 
                     ^

È possibile fare ciò che sto cercando di fare? Qual è la firma del tipo corretto per lo swap?

risposta

7

Non so come farlo, ma penso che forse sarebbe di aiuto avere un'idea migliore di cosa esattamente vuoi che succeda. Prendere in considerazione una classe come

case class Foo(x: Int, y: Int) extends Swappable[Int] { 
    val z = x 
} 

Ora, se avete f = Foo(1, 2), dovrebbe f.swap dare un Foo dove x != z? Se è così, non c'è modo in Scala di creare un Foo così. In caso contrario, cosa significa "scambiare xe y"?

Forse quello che stai veramente cercando è qualcosa di simile:

trait Swappable[A,T] { 
    this: A => 

    val x: T 
    val y: T 
    def cons(x: T, y: T): A 

    def swap = cons(y, x) 
} 

case class Foo(x: Int, y: Int) extends Swappable[Foo,Int] { 
    val z = x 

    def cons(x: Int, y: Int) = copy(x=x, y=y) 
} 

ma non ne sono sicuro.

+0

Very nice! Fai un buon punto che la nozione di scambio non è chiara in generale. Nella mia situazione, estenderò solo "Scambiabile" con le classi caso "Foo (x: T, y: T)" che non contengono valori aggiuntivi, ma non c'è molto altro modo per Scala di saperlo. Quindi penso che lascerò l'implementazione del metodo 'swap' a ciascuna classe ereditaria (che è fondamentalmente ciò che fai, attraverso il metodo extra' cons'). La chiave per fare ciò (che non avevo pensato) sta passando nel parametro di tipo extra 'A' a' Swappable', che consente alle classi ereditarie di dettare quale dovrebbe essere il tipo di ritorno. Grazie! – davidsd

3

Che dire qualcosa di simile:

trait Swappable[T] { 
    type A 
    val x: T 
    val y: T 

    def create(a: T, b: T): A 
    def swap = create(y, x) 
} 

case MySwappable[T](x: T, y: T) extends Swappable[T] { 
    type A = MySwappable 
    def create(a: T, b: T) = MySwappable(a, b) 
} 
+0

Giusto, questo è molto simile alla soluzione di Owen. – davidsd

+1

Solo per il riferimento, questa domanda è indicata come "MyType": http://www.scala-lang.org/node/6649 (e non c'è ancora una risposta senza etichetta in Scala) – Eric