Nano Hash - криптовалюты, майнинг, программирование

groovy: переменная область видимости в замыканиях в суперклассе (MissingPropertyException)

У меня сложилось впечатление, что замыкания выполняются как вызываемый фактический класс (вместо реализующего суперкласса) и, таким образом, прерываются, когда некоторые переменные не видны (например, частные в суперклассе).

Например

package comp.ds.GenericTest2

import groovy.transform.CompileStatic

@CompileStatic
class ClosureScopeC {
        private List<String> list = new ArrayList<String>()
        private int accessThisPrivateVariable = 0;

        void add(String a) {
                list.add(a)
                println("before ${accessThisPrivateVariable} ${this.class.name}")
                // do something with a closure
                list.each {String it ->
                        if (it == a) {
                                // accessThisPrivateVariable belongs to ClosureScopeC
                                accessThisPrivateVariable++
                        }
                }
                println("after ${accessThisPrivateVariable}")
        }
}

// this works fine
a = new ClosureScopeC()
a.add("abc")
a.add("abc")

// child class
class ClosureScopeD extends ClosureScopeC {
        void doSomething(String obj) {
                this.add(obj)
        }
}

b = new ClosureScopeD()

// THIS THROWS groovy.lang.MissingPropertyException: No such property: accessThisPrivateVariable for class: comp.ds.GenericTest2.ClosureScopeD
b.doSomething("abc")

Последняя строка вызывает исключение MissingPropertyException: дочерний класс вызывает метод «добавить» суперкласса, который выполняет закрытие «каждого», использующего «accessThisPrivateVariable».

Я новичок в groovy, поэтому я думаю, что должен быть простой способ сделать это, потому что в противном случае кажется, что замыкания полностью нарушают инкапсуляцию частной реализации, выполненной в суперклассе... это кажется очень распространенной потребностью ( реализация суперкласса, ссылающаяся на свои собственные частные переменные)

Я использую Groovy 2.1.3


  • Как и в случае с вашим другим вопросом, его, вероятно, лучше задать в списке рассылки groovy-user. 24.04.2013
  • Хорошо, Тим, спасибо, так и сделаю. 24.04.2013

Ответы:


1

Я нашел это хорошим справочником, описывающим, как работают области переменных Groovy и применяются к вашей ситуации: -when-call-from-extending-class">Замыкание в groovy не может использовать приватное поле при вызове из класса расширения

Из приведенной выше ссылки я понял, что, поскольку вы объявили accessThisPrivateVariable закрытым, Groovy не будет автоматически генерировать геттер/сеттер для переменной. Помните, что даже в Java закрытые переменные не доступны напрямую из подклассов.

Изменение кода для явного добавления геттера/сеттера решило проблему:

package com.test
import groovy.transform.CompileStatic

@CompileStatic
class ClosureScopeC {
    private List<String> list = new ArrayList<String>()
    private int accessThisPrivateVariable = 0;

    int getAccessThisPrivateVariable() { accessThisPrivateVariable }
    void setAccessThisPrivateVariable(int value ){this.accessThisPrivateVariable = value}

    void add(String a) {
        list.add(a)
        println("before ${accessThisPrivateVariable} ${this.class.name}")
        // do something with a closure
        list.each {String it ->
            if (it == a) {
                 // accessThisPrivateVariable belongs to ClosureScopeC
                accessThisPrivateVariable++
            }
        }
        println("after ${accessThisPrivateVariable}")
    }
}

// this works fine
a = new ClosureScopeC()
a.add("abc")
a.add("abc")

// child class
class ClosureScopeD extends ClosureScopeC {
    void doSomething(String obj) {
        super.add(obj)
    }
}

b = new ClosureScopeD()
b.doSomething("abc")

Есть более простой способ: просто сделайте модификатор доступа (на самом деле он должен переименовывать свойство) в защищенный, чтобы подкласс имел доступ к свойству... проблема решена.

protected int accessThisProtectedVariable

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

Объявляя поле как приватное, Groovy сохраняет инкапсуляцию, намеренно приостанавливая автоматическую генерацию общедоступного метода получения/установки. Когда-то приватное, теперь вы несете ответственность и полностью контролируете, как и есть ли способ для подклассов (защищенных) или всех классов объектов (общедоступных) получить доступ к полю путем явного добавления методов - если это имеет смысл.

Помните, что по соглашению Groovy ВСЕГДА вызывает геттер или сеттер, когда ваши коды ссылаются на поле. Итак, заявление типа:

def f = obj.someField

фактически вызовет метод obj.getSomeField(). Так же:

obj.someField = 5

вызовет метод obj.setSomeField(5).

15.01.2016
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..