Почему / Как работает эта функция расширения? Как это назвать без `с`? - PullRequest
1 голос
/ 13 апреля 2020

Проходя курс "Kotlin для Java Developers" Coursera , я натолкнулся на эту конструкцию, в которой функция расширения для отдельного экземпляра, похоже, имеет доступ к закрытым полям содержащего класса. , Обратите внимание, как класс Data реализован вне Container и не имеет доступа к полям Container, но функция расширения Data.printMe() может получить доступ к приватному Container containerVal member:

data class Data (val data: String)

class Container (private val containerVal: String, val data: Data){
    fun Data.printMe() {
        println("data: $data - in container: ${this@Container.containerVal}")
    }
}

fun main() {
    val c = Container("mycontainer", Data("mydata"))
    // Can I call Data.printMe without using `with`?
    // val d = c.data.printMe();
    with (c) {
        // Prints: data: mydata - in container: mycontainer
        data.printMe();
    }
}

Довольно круто, что Data.printMe может получить доступ к Container приватным пользователям. with(c), по-видимому, это позволяет. Я вижу множество вариантов использования для этого, например, как в примере примера функции расширения для Cell s игры могут получить доступ к содержащему Board без того, чтобы сам класс Cell был загрязнен и тесно связан с Board .

У этого "подхода" есть имя? И есть ли синтаксис для вызова c.data.printMe "напрямую" без использования with? с документацией не упоминает этот вариант использования.

1 Ответ

1 голос
/ 13 апреля 2020

Метод printMe() имеет два приемника: диспетчерский приемник и дополнительный приемник . диспетчер отправки является экземпляром класса, в котором объявлено расширение, а приемник расширения является экземпляром типа получателя метода расширения. Вы получаете доступ к contaiverVal в контексте Container экземпляра (получателя отправки), а не Data экземпляра (получателя расширения).

Если вы попытаетесь сделать обратное и получить доступ к частному свойству класс Data внутри printMe(), вы получите ошибку компилятора.

когда вы определите функцию расширения как член класса, она будет использоваться только в контексте этого класса. Вы можете получить к нему доступ внутри класса или с помощью функции области видимости, где объект контекста доступен как лямбда-приемник (это). Эти функции run, with и apply.

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