복붙노트

[SCALA] 어떻게 혼합 된합니다 인스턴스에 대한 특성?

SCALA

어떻게 혼합 된합니다 인스턴스에 대한 특성?

을 감안할 때 우려 MyTrait :

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

확장하거나와 함께 클래스에 혼합 할 수 있습니다 :

class MyClass extends MyTrait

또한 새로운 인스턴스를 인스턴스화에 혼합 할 수 있습니다 :

var o = new MyOtherClass with MyTrait
o.doSomething

하지만 ... 수있는 특성 (또는 그 차이가 취하면 다른) 기존 인스턴스에 추가?

나는 자바에서 JPA를 사용하여로드 객체를 그리고 난 특성을 사용하여 몇 가지 기능을 추가하고 싶습니다. 그것은 전혀 할 수 있습니까?

나는 다음과 같은 특성에 혼합 할 수 있도록하고 싶습니다 :

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

해결법

  1. ==============================

    1.나는이 사용에 대한 아이디어를 가지고 :

    나는이 사용에 대한 아이디어를 가지고 :

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

    아래로이 특성을 사용할 수 있습니다 :

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

    귀하의 예제 코드 :

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

    내가 당신을 도울 수 있기를 바랍니다.

    업데이트]

    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
    }
    

    그러나이 패턴은 이미 정의 된 몇 가지 암시 도우미 방법을 사용할 수 없습니다, 일부는 제한이있다.

    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
    
  2. ==============================

    2.JVM의 기존 런타임 객체는 힙에 특정 크기를 갖는다. 그것에 특성을 추가하면 힙 크기를 변경, 그 서명을 변경하는 것을 의미한다.

    JVM의 기존 런타임 객체는 힙에 특정 크기를 갖는다. 그것에 특성을 추가하면 힙 크기를 변경, 그 서명을 변경하는 것을 의미한다.

    갈 수있는 유일한 방법은 컴파일 타임에 변화의 어떤 종류의 일을하는 것입니다 그래서.

    스칼라의 믹스 인 구성은 컴파일시에 발생합니다. 어떤 컴파일러 수 잠재적 할 기존 객체 A를 단순히 전달 모든 호출 한 다음 B.이에 형질 T 믹스는하지만, 구현되지 않은 것과 같은 유형의 기존 개체 A를 주위에 래퍼 B를 만드는 것입니다. 객체 A는 확장 할 수 없습니다 최종 클래스의 인스턴스가 될 수 있기 때문에이 가능할 것이다 때 의문이다.

    요약하면, 믹스 인 구성은 기존 개체의 인스턴스 수 없습니다.

    업데이트 :

    어떤 특성을 가진 스마트 구골 산에 의해 제안 된 솔루션 및 작업에 일반화 관련, 이것은 지금까지 내가 가진 같습니다. 아이디어는 DynamicMixinCompanion의 특성에 공통의 믹스 인 기능을 추출하는 것입니다. 클라이언트는 자신이에 대한 동적 믹스 인 기능을 가지고 싶어 각 특성에 대한 동반자 객체 확장 DynamicMixinCompanion을 만들어야합니다. 이 동반자 객체는 익명의 특성 개체 (작성되는 정의가 필요합니다 : :).

    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)                                                                                
      }                                                                                                  
    }                                                                                                    
    
  3. ==============================

    3.나는 보통 기존 객체에 새로운 방법으로 혼합하는 암시를 사용했다.

    나는 보통 기존 객체에 새로운 방법으로 혼합하는 암시를 사용했다.

    나는 다음과 같이 몇 가지 코드가있는 경우, 참조 :

    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
    }
    

    그리고 당신은 이미 존재하는 객체 테스트와 MyTrait 방법을 사용할 수 있습니다.

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

    귀하의 예를 들어, 당신은 다음과 같이 사용할 수 있습니다 :

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

    나는이 HelperObject을 정의하기 위해 지사 구문을 생각하고있다 :

    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
    
  4. ==============================

    4.어떤 암시 클래스에 대한? 그것은 최종 내부 클래스와 "믹스 인"α- 함수와 다른 답변의 방법에 비해 나에게 쉽게 보인다.

    어떤 암시 클래스에 대한? 그것은 최종 내부 클래스와 "믹스 인"α- 함수와 다른 답변의 방법에 비해 나에게 쉽게 보인다.

    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
    
    }
    
  5. ==============================

    5.왜 스칼라의 내 라이브러리 패턴을 확장 사용하지?

    왜 스칼라의 내 라이브러리 패턴을 확장 사용하지?

    https://alvinalexander.com/scala/scala-2.10-implicit-class-example

    나는 반환 값의 무엇인지 확실하지 않다 :

    var에 O = DB (기본 키)에서 DBHelper.load 내 엔티티;

    그러나 우리의 예를 들어 DBEntity입니다, 우리가 가정 해 봅시다. 당신은 클래스 DBEntity을 그리고 그것은 당신의 특성, MyTrait를 확장하는 클래스로 변환 할 수 있습니다.

    뭔가 같은 :

    trait MyTrait {
      def doSomething = {
        println("boo")
      }
    }
    
    class MyClass() extends MyTrait
    
    // Have an implicit conversion to MyClass
    implicit def dbEntityToMyClass(in: DBEntity): MyClass = 
    new MyClass()
    

    난 당신이 또한 단지 암시 클래스를 사용하여이 작업을 단순화 할 수 있으리라 생각합니다.

    implicit class ConvertDBEntity(in: DBEntity) extends MyTrait
    

    이 혼합 된 수있는 특성 :: 연산자를 오버로드 c를 나는 특히 / 여기에 B를 허용 대답을 싫어한다.

    스칼라에서는 :: 연산자 즉 시퀀스에 사용됩니다 :

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

    조금 어색한 상속 느낌 IMHO의 수단으로 사용.

  6. from https://stackoverflow.com/questions/3893274/how-to-mix-in-a-trait-to-instance by cc-by-sa and MIT license