Концепция приемников была объяснена ранее, поэтому убедитесь, что вы знаете, что такое приемник, прежде чем читать дальше.

Получатель расширения - это получатель, который тесно связан с расширениями Kotlin. Получатель расширения представляет собой объект, для которого мы определяем расширение. Чтобы определить расширение, мы должны указать перед ним тип приемника (обычно имя класса или интерфейса). Получатель расширения - это экземпляр объекта, для которого вызывается расширение. Давайте посмотрим на функцию расширения Ball.bounce:

fun String.firstChar(): Char = this.get(this.length — 1)
fun String.lastCharacter() {
   println(“Receiver type is ${this.javaClass}, Reciver object is ${this.name}”)
}
val ball = Ball(“Golf ball”)
ball.bounce() 
// prints: Receiver type is Ball, Receiver object is Golf ball

Вышеупомянутый экземпляр класса Ball доступен как приемник расширения внутри тела расширения bounce. Тип получателя указывает тип объекта-получателя (Ball), а объект Receiver - это экземпляр класса, который является получателем (мяч для гольфа / теннисный мяч). Обратите внимание, что в случае с расширениями объект-получатель ведет себя как любой другой объект, поэтому мы не можем получить доступ к членам с частной или защищенной видимостью.

Получатель отправки - это особый вид получателя, существующий, когда расширение объявлено членом. Он представляет собой экземпляр класса, в котором объявлено расширение. Представьте, что мы определим расширение uploadToBackend для класса Person. Обратите внимание, что мы определим этот приемник внутри класса Network:

class Person {
   fun move() {}
}
class NetworkRepository {
   fun loadData() {}
   fun Person.uploadToBackend() {
      move() //method from extension receiver
      loadData() //method from extension dispatch receiver
   }
}

В теле метода расширения uploadToBackend мы можем вызывать методы из классов Person и NetworkRepository. Причина в том, что наш метод uploadToBackend имеет два получателя. Во-первых, это приемник расширения, представляющий экземпляр класса, для которого было вызвано расширение. Во-вторых, получатель отправки, представляющий экземпляр класса, в котором объявлено расширение. Обратите внимание, что в приведенном выше примере оба получателя являются неявными получателями - мы вызываем два разных метода для двух разных объектов без указания получателя.

Чтобы вызвать наш метод расширения для класса Person, нам понадобится приемник расширения типа Database.

class Person {
   fun move() {}
}
class Database (al person:Person) {
   fun loadData() {}
   fun doSomething() {
      person.uploadToBackend(); // We can access extension here
   }
 
   fun Person.uploadToBackend() {
      move()
      loadData()
   }
}
val person = Person()
person.uploadToBackend() // Compilation error

Компилятор сообщит об ошибке, когда мы вызовем метод uploadToBacnekd вне класса Database (в контексте, который не имеет получателя типа Database). Мы можем вызвать это расширение внутри класса Database, потому что доступен соответствующий приемник.

Но что произойдет, если у обоих методов будет одна и та же сигнатура? Давайте добавим метод перемещения в класс базы данных.

class Person {
   fun move() {}
}
class NetworkRepository (val person:Person) {
   fun loadData() {}
   fun move() {}
   fun doSomething() {
      person.uploadToBackend();
   }
   fun Person.uploadToBackend() {
     // calls method defined in Person class
     move()
     // calls method defined in NetworkRepository class         
     [email protected]()
 }
}

По умолчанию метод перемещения, определенный в классе Person, будет иметь приоритет, но если мы хотим получить доступ к методу в NetworkRepository, нам нужно использовать явный получатель (this @ NetworkRepository).

Этот пост - девятая часть Словаря программистов Kotlin. Чтобы оставаться в курсе новых деталей, просто подпишитесь на этот носитель. Чтобы оставаться на связи с моими статьями, следите за мной в Твиттере. Ключ для упоминания меня - @IgorWojda.

Если вам это нравится, не забудьте хлопать. Обратите внимание: если вы удерживаете кнопку хлопка, вы можете оставить больше хлопков.

Вот и другие части словаря программистов Kotlin: