Это не относится к исходному объекту с использованием делегирования класса Kotlins - PullRequest
0 голосов
/ 12 октября 2018

Я запутался, как делегирование работает в Котлине. Википедия говорит:

При поддержке делегирования на уровне языка это делается неявно, когда self в делегате ссылается на исходный (отправляющий) объект, а не на делегат (принимающий)объект).

Учитывая следующий код:

interface BaseInterface {
    fun print()
}

open class Base() : BaseInterface {
    override fun print() { println(this) }
}

class Forwarded()  {
    private val base = Base()

    fun print() { base.print() }
}

class Inherited() : Base() {}

class Delegated(delegate: BaseInterface) : BaseInterface by delegate

fun main(args: Array<String>) {
    print("Forwarded: ")
    Forwarded().print();
    print("Inherited: ")
    Inherited().print();
    print("Delegated: ")
    Delegated(Base()).print();
}

Я получаю этот вывод:

Forwarded: Base@7440e464
Inherited: Inherited@49476842
Delegated: Base@78308db1

Я ожидаю, что Делегат вернет Delegatedпотому что сам / это должно относиться к исходному объекту.Я правильно понял или делегация Котлинса отличается?

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Я думаю, что это легче всего понять, если мы посмотрим на декомпилированный байт-код Java, в который он компилируется:

Вы можете сделать это, перейдя к Tools > Kotlin > Show Kotlin Bytecode и затем нажав Decompile

public final class Delegated implements BaseInterface {
   // $FF: synthetic field
   private final BaseInterface $$delegate_0;

   public Delegated(@NotNull BaseInterface delegate) {
      Intrinsics.checkParameterIsNotNull(delegate, "delegate");
      super();
      this.$$delegate_0 = delegate;
   }

   public void print() {
      this.$$delegate_0.print();
   }
}

Таким образом, когда вы выполняете делегирование интерфейса , происходит то, что Kotlin создает поле для делегата с именем $$delegate_0 и добавляет методы в ваш делегирующий класс , которыйбудет работать на $$delegate_0.У вас также может быть несколько делегатов, они получат свои собственные поля.Однако есть одно предупреждение: вы не можете получить доступ к $$delegate_0 напрямую, даже если вы сделаете его var следующим образом:

class Delegated(var delegate: BaseInterface) : BaseInterface by delegate

Это скомпилируется в:

public final class Delegated implements BaseInterface {
   @NotNull
   private BaseInterface delegate;
   // $FF: synthetic field
   private final BaseInterface $$delegate_0;

   @NotNull
   public final BaseInterface getDelegate() {
      return this.delegate;
   }

   public final void setDelegate(@NotNull BaseInterface var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.delegate = var1;
   }

   public Delegated(@NotNull BaseInterface delegate) {
      Intrinsics.checkParameterIsNotNull(delegate, "delegate");
      super();
      this.$$delegate_0 = delegate;
      this.delegate = delegate;
   }

   public void print() {
      this.$$delegate_0.print();
   }
}

печально.Я написал об этой теме здесь .

0 голосов
/ 12 октября 2018

Kotlin делегирование очень просто - оно генерирует все методы интерфейса и неявно вызывает его для делегированного объекта, за исключением методов, явно переопределенных пользователем.

Ваш пример функционально такой же, как:

class Delegated(delegate: BaseInterface) : BaseInterface{
    // when generating bytecode kotlin assigns delegate object to internal final variable
    // that is not visible at compile time
    private val d = delegate

    override fun print(){
        d.print()
    }
}

Так что довольно ясно, почему он печатает Base.

...