Frage

Bei einem Merkmal MyTrait:

trait MyTrait {
  def doSomething = println("boo")
}

es kann mit extends oder with in eine Klasse gemischt werden

class MyClass extends MyTrait

Es kann auch bei der Instanziierung eine neue Instanz gemischt werden:

var o = new MyOtherClass with MyTrait
o.doSomething

Aber ... kann das Merkmal (oder eine andere, wenn das einen Unterschied macht) zu einer vorhandenen Instanz hinzugefügt werden?

Ich bin Laden von Objekten unter Verwendung von JPA in Java, und ich möchte einige Funktionen, um sie hinzuzufügen Eigenschaften verwenden. Ist es möglich?

Ich möchte in der Lage sein, in einem Zug zu mischen, wie folgt:

var o = DBHelper.loadMyEntityFromDB(primaryKey);
o = o with MyTrait //adding trait here, rather than during construction
o.doSomething
War es hilfreich?

Lösung

Ich habe eine Idee für diese Nutzung:

//if I had a class like this
final class Test {
  def f = println("foo")
}
trait MyTrait {
  def doSomething = {
    println("boo")
  }
}
object MyTrait {
  implicit def innerObj(o:MixTest) = o.obj

  def ::(o:Test) = new MixTest(o)
  final class MixTest private[MyTrait](val obj:Test) extends MyTrait
}

Sie können diese Eigenschaft verwenden, wie unten:

import MyTrait._

val a = new Test
val b = a :: MyTrait
b.doSomething
b.f

für Ihren Beispielcode:

val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething

Ich hoffe, das Ihnen helfen kann.

AKTUALISIERT

object AnyTrait {
  implicit def innerObj[T](o: MixTest[T]):T = o.obj

  def ::[T](o: T) = new MixTest(o)
  final class MixTest[T] private[AnyTrait](val obj: T) extends MyTrait
}

aber dieses Muster einige beschränken hat, kann man nicht einige implizite Hilfsmethode verwenden, die bereits definiert.

val a = new Test
a.f
val b = a :: AnyTrait
b.f1
b.f
val c = "say hello to %s" :: AnyTrait
println(c.intern)  // you can invoke String's method 
println(c.format("MyTrait"))  //WRONG. you can't invoke StringLike's method, though there defined a implicit method in Predef can transform String to StringLike, but implicit restrict one level transform, you can't transform MixTest to String then to StringLike.
c.f1
val d = 1 :: AnyTrait
println(d.toLong)
d.toHexString // WRONG, the same as above
d.f1

Andere Tipps

Ein bestehendes Laufzeitobjekt in der JVM hat eine bestimmte Größe auf dem Heap. Hinzufügen einer Eigenschaft zu es bedeuten würde, seine Größe auf dem Heap zu verändern und das Ändern seiner Unterschrift.

So ist der einzige Weg wäre, zu gehen, eine Art von Transformation bei der Kompilierung zu tun.

Mixin Zusammensetzung in Scala tritt bei der Kompilierung. Was für Compiler könnte möglicherweise tun, ist ein Wrapper-B um ein vorhandenes Objekt A mit der gleichen Art zu erstellen, die einfach leitet alle Anrufe an das bestehende Objekt A, und dann in einem Zug T auf B. Das aber mischen, ist nicht implementiert. Es ist fraglich, wenn dies möglich wäre, da das Objekt A eine Instanz einer endgültigen Klasse sein könnte, die nicht verlängert werden können.

Insgesamt mixin Zusammensetzung ist nicht möglich, auf bestehende Objektinstanzen.

AKTUALISIERT:

Bezogen auf die intelligente Lösung von Googol Shan vorgeschlagen, und es an die Arbeit mit jedem Zug zu verallgemeinern, ist dies so weit wie ich habe. Die Idee ist es, die gemeinsame mixin Funktionalität im DynamicMixinCompanion Merkmale zu extrahieren. Der Kunde sollte dann ein Begleitobjekt erstreckt DynamicMixinCompanion für jedes Merkmal erstellen will er für die dynamische mixin Funktionalität haben. Dieser Begleiter Objekt erfordert die Definition des anonyme Merkmal Objekt wird (::) erstellt.

trait DynamicMixinCompanion[TT] {                                                                    
  implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj                                              

  def ::[OT](o: OT): Mixin[OT] with TT                                                               
  class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)                                      
}                                                                                                    

trait OtherTrait {                                                                                   
  def traitOperation = println("any trait")                                                          
}                                                                                                    

object OtherTrait extends DynamicMixinCompanion[OtherTrait] {                                        
  def ::[T](o: T) = new Mixin(o) with OtherTrait                                                     
}                                                                                                    

object Main {                                                                                        
  def main(args: Array[String]) {                                                                    
    val a = "some string"                                                                            
    val m = a :: OtherTrait                                                                          
    m.traitOperation                                                                                 
    println(m.length)                                                                                
  }                                                                                                  
}                                                                                                    

Früher habe ich in der Regel eine implicit in einem neuen Verfahren auf ein vorhandenes Objekt zu mischen.

Siehe, wenn ich habe einige Code wie folgt:

final class Test {
  def f = "Just a Test"
  ...some other method
}
trait MyTrait {
  def doSomething = {
    println("boo")
  }
}
object HelperObject {
  implicit def innerObj(o:MixTest) = o.obj

  def mixWith(o:Test) = new MixTest(o)
  final class MixTest private[HelperObject](obj:Test) extends MyTrait
}

und dann können Sie MyTrait Methode mit einem bereits vorhandenen Objekt-Test verwenden.

val a = new Test
import HelperObject._
val b = HelperObject.mixWith(a)
println(b.f)
b.doSomething

in Ihrem Beispiel, können Sie wie folgt verwenden:

import HelperObject._
val o = mixWith(DBHelper.loadMyEntityFromDB(primaryKey));
o.doSomething

Ich denke einen Präfekten Syntax aus dieser HelperObject zu definieren:

trait MyTrait {
  ..some method
}
object MyTrait {
  implicit def innerObj(o:MixTest) = o.obj

  def ::(o:Test) = new MixTest(o)
  final class MixTest private[MyTrait](obj:Test) extends MyTrait
}
//then you can use it
val a = new Test
val b = a :: MyTrait
b.doSomething
b.f
// for your example
val o = DBHelper.loadMyEntityFromDB(primaryKey) :: MyTrait
o.doSomething

Was ist eine implizite Klasse? Es scheint einfacher zu mir im Vergleich zu der Art und Weise in den anderen Antworten mit einer abschließenden inneren Klasse und einer „mixin“ -Funktion.

trait MyTrait {

    def traitFunction = println("trait function executed")

}

class MyClass {

    /**
     * This inner class must be in scope wherever an instance of MyClass
     * should be used as an instance of MyTrait. Depending on where you place
     * and use the implicit class you must import it into scope with
     * "import mypackacke.MyImplictClassLocation" or
     * "import mypackage.MyImplicitClassLocation._" or no import at all if
     * the implicit class is already in scope.
     * 
     * Depending on the visibility and location of use this implicit class an
     * be placed inside the trait to mixin, inside the instances class,
     * inside the instances class' companion object or somewhere where you
     * use or call the class' instance with as the trait. Probably the
     * implicit class can even reside inside a package object. It also can be
     * declared private to reduce visibility. It all depends on the structure
     * of your API.
     */
    implicit class MyImplicitClass(instance: MyClass) extends MyTrait

    /**
     * Usage
     */
    new MyClass().traitFunction

}

Warum verwenden nicht Scala meiner Bibliothek Muster verlängern?

https://alvinalexander.com/scala/scala-2.10-implicit -Klasse-Beispiel

Ich bin mir nicht sicher, was ist der Rückgabewert von:

var o = DBHelper.loadMyEntityFromDB(primaryKey);

aber lassen Sie uns sagen, es DBEntity für unser Beispiel. Sie können die Klasse DBEntity nehmen und es zu einer Klasse umwandeln, die Ihre Eigenschaft erstreckt, MyTrait.

So etwas wie:

trait MyTrait {
  def doSomething = {
    println("boo")
  }
}

class MyClass() extends MyTrait

// Have an implicit conversion to MyClass
implicit def dbEntityToMyClass(in: DBEntity): MyClass = 
new MyClass()

Ich glaube, man könnte auch dies vereinfachen, indem nur eine implizite Klasse.

implicit class ConvertDBEntity(in: DBEntity) extends MyTrait

Ich mag nicht besonders die akzeptierte Antwort hier, b / c den :: Betreiber Überlastungen ein Merkmal zu in mischen.

In Scala, der :: Operator für Sequenzen verwendet wird, das heißt:.

val x = 1 :: 2 :: 3 :: Nil

Mit ihm als Mittel der Vererbung fühlt, IMHO, ein wenig umständlich.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top