Domanda

Ho una classe astratta:

abstract class Foo(...){
   def bar1(f : Foo) : Boolean
   def bar2(f : Foo) : Foo
}

più classi estendono Foo e sostituiscono i metodi

class FooImpl(...) extends Foo{
    override def bar1(f : Foo) : Boolean {
        ...
    }
    override def bar2(f : Foo) : Foo {
        ...
    }
} 

E 'possibile, utilizzando farmaci generici (o qualcosa del genere) per rendere i metodi imperativi hanno il tipoParametro della sottoclasse sua attuazione? In questo modo:

class FooImpl(...) extends Foo{
    override def bar1(f : FooImpl) : Boolean {
        ...
    }
    override def bar2(f : FooImpl) : FooImpl {
        ...
    }
}

Stavo pensando qualcosa lungo la linea dei seguenti, ma che non sembra funzionare ...

abstract class Foo(...){
    def bar1[T <: Foo](f : T) : Boolean
    def bar2[T <: Foo](f : T) : T
}

class FooImpl(...) extends Foo{
    override def bar1[FooImpl](f : FooImpl) : Boolean {
       ...
    }
    override def bar2[FooImpl](f : FooImpl) : FooImpl{
       ...
    }
}

Ogni aiuto è molto apprezzato!

Grazie.

È stato utile?

Soluzione

abstract class Foo{
   type T <: Foo
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo{
   type T = FooImpl
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

In questa versione, diverse sottoclassi di Foo condividono Foo come una superclasse, ma per mantenere il valore di ritorno di bar2 (oi parametri per bar1 o bar2) in un ambiente dove tutto quello che sai del tuo oggetto (diciamo prende il nome obj) è che si tratta di un Foo, è necessario utilizzare il tipo di obj.T come il tipo di variabile.

Altri suggerimenti

Per rendere seconda versione di Ken Blum un po 'più bello è possibile utilizzare i tipi di auto:

abstract class Foo[T] { self:T =>
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

esigenze T di essere un parametro di tipo sulla classe Foo che si eredita dalla, non sui metodi stessi.

abstract class Foo[T <: Foo[T]]{
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

Diverse sottoclassi di Foo non in realtà hanno un supertipo comune in questa versione del codice, perché si estendono da diverse parametrizzazioni di Foo. È possibile utilizzare i metodi con parametri che fanno riferimento a Foo[T] quando si ha bisogno di lavorare con il supertipo comune, ma io tendo a preferire la soluzione di tipo astratto ho pubblicato nella mia altra risposta, becuase non perde i dettagli dei farmaci generici a tutte le altre funzioni che hanno a che fare con i Foos.

Idealmente si combinano le cose di cui sopra, cioè.

trait Foo[T <: Foo[T]] { self:T =>

"[T <: Foo [T]]" significa T è sottoclasse di Foo [T], E "auto: T =>". Significa che Foo [T] è sottoclasse di T, ed insieme è un po 'strano modo di dire che Foo [T] è esattamente uguale a T

Solo con che avrei potuto fare seguente codice di compilazione e di lavoro come previsto:

trait Field[T <: Field[T]] { self:T =>

  def x2:T

  def +(that:T):T

  def *(n:BigInt) : T = {
    if(n == 1)
      this
    else if(n == 2)
      this.x2
    else if(n == 3)
      this + this.x2
    else {
      val p = (this * (n/2)).x2
      if (n%2==0)
        p
      else
        p + this
    }        
  }

}

È possibile parametrizzare Foo per realizzare alcuni degli effetti facilmente:

abstract class Foo[F <: Foo[F]] { def f: F }
class Food extends Foo[Food] { def f = this }  // Yay!
class Fool extends Foo[Food] { def f = new Food }  // Uh-oh...

Se si vuole escludere la seconda ipotesi, non c'è modo semplice per farlo con le caratteristiche attuali in Scala.

Inoltre, alcune delle cose che ti sembra di volere non ha senso se si dà un'implementazione reale Foo. Se promesse Foo di prendere qualsiasi Foo ma conferiscono un metodo che insiste solo su un Food, si romperà se si passa una diversa sottoclasse di Foo (ad esempio Fool). Quindi il compilatore non ti consente di farlo.

abstract class Foo { def bar(f: Foo) : Foo }
class Foot extends Foo { def bar(f: Foo) = this }   // Fine!
class Fool extends Foo { def bar(f: Fool) = this }   // No good!
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top