Разименование ->* и приведение типов ?= в ABAP

Posted under ABAP On By Plank

Функциональный консультант иногда изучает код программы, чтобы понять в деталях как работает функционал. Курсы, help.sap.com, F1 не всегда помогают и приходится читать листинг программы или смотреть, что происходит в отладчике. Если с конструкциями SELECT, LOOP AT, READ TABLE и т.д. еще более или менее понятно, помогает изучение программирования в школе или институте, элементарная логика или примерное знание функционала и структуры данных, то с конструкциями типа ->* или ?= могут возникнуть сложности (как минимум у меня). в продолжении статьи Полиморфизм в ABAP решил разобраться что такое разименование ->* и приведение типов ?= в ABAP.

Ссылочная переменная

Прежде всего нужно понять что такое ссылочная переменная. Обычная переменная – это именованный объект данных, используемый для хранения значения в выделенной области памяти программы. Ссылочная переменная не хранит значение, как обычная переменная, или указывает, как field-symbol, на конкретную переменную. Она указывает на область памяти и содержат внутри себя адрес в памяти. При этом объект в памяти может быть, как явно связан с какой-либо переменной, так и создан анонимно и привязан только к ссылочной переменной.

Сразу нужно разобраться с field-symbols. Я считал это ссылкой и называл ссылкой, но это не так, это псевдоним (alias) для переменной, который можно определить родовыми типами (any, data, csequence, simple, any table и т.д.) и потом присвоить все что угодно, даже если типы данных не совпадают, но при этом они совместимы (ASSIGN COMPONENT ‘…’ OF STRUCTURE … TO <>, ASSIGN … TO <…> или ASSIGN … TO <…> CASTING TYPE …). Псевдоним не хранит в себе ссылку (указатель) на область памяти, а лишь является указателем на переменную или объект данных, которые уже есть в текущем коде. Изменение одного – изменяет другое.

Настоящая ссылочная переменная хранит ссылку (указатель) на блок памяти, где хранится значение. Изменение значения не изменяет адрес и соответственно ссылочную переменную. Поэтому field-symbols постараюсь не называть по привычке ссылкой, это будет псевдоним.

Объявление ссылочных переменных: DATA … TYPE REF TO … Чтобы получить адрес относительно переменной, необходимо воспользоваться оператором GET REFERENCE OF … INTO … (или по-новому … = REF #( … )).

Если ссылочная переменная ссылается на структуру, доступ к её компонентам осуществляется через -><имя компонента>.
С помощью оператора CREATE DATA … можно динамически создать анонимный объект в памяти, привязав его к ссылочной переменной, время жизни такого объекта равносильно времени жизни ссылочной переменной. У оператора CREATE DATA есть возможность указать тип динамически CREATE DATA … TYPE (…). Для динамически создаваемых объектов данных разыменование является единственным способом получения их содержимого.
Возвращаясь к примеру с котиками и собачками получаем следующий код:
Объявляем класс и метод, который возвращает ссылку
определяем метод:
и определяем как это будет использоваться:
Листинг программы

Приведение типов

При присваивании между ссылочными переменными общий оператор присваивания = может использоваться только для приведений вверх, в которых статический тип source_ref более специфичен или совпадает со статическим типом destination_ref. Иными словами, если есть класс-родитель и класс-наследник, то ссылочную переменную на класс-наследник можно присвоить ссылочной переменной класса-родителя.
Специальный оператор приведения ?= (или по-новому … = CAST #( … )) может использоваться только для присваивания между ссылочными переменными. Если статический тип source_ref является более общим, чем статический тип destination_ref, ?= должен использоваться для создания приведения вниз. Если это известно статически, оно проверяется с помощью проверки синтаксиса, в противном случае оно проверяется во время выполнения. Фактическое приведение вниз, то есть проверка того, возможны ли назначения в соответствии с правилами назначения для ссылочных переменных, выполняется только во время выполнения.
На примере собак. Есть абстрактный класс собак c методами которые умет что-то делать, например, определяют как собака говорит:
Есть более специфичные классы наследники, которые определяют подкласс служебных и домашних собак через специализированные методы:
И есть метод, который все это выводит:
Что бы метод более общего класса class_dog_general можно было использовать для объектов, созданных для подклассов, нужно передать ссылку на общий класс через ?=
Выигрыш будет в том, что метод общего для всех класса определен один раз, а потом используется для объектов специализированных классов.
Если статический тип целевой переменной более специфичен, чем статический тип исходной переменной, во время выполнения, перед выполнением присваивания, необходимо проверить, является ли он менее специфичным или таким же, как динамический тип исходной переменной. Название down cast происходит от того факта, что движение в пространстве наследования происходит вниз. Поскольку целевая переменная может принимать меньшее количество динамических типов по сравнению с исходной переменной, это присвоение также называется сужающим приведением. Приведение вниз всегда должно выполняться явно.
Листинг программы
Подробнее про разименование ->* и приведение типов ?= в ABAP тут и тут.

Leave a comment

Ваш адрес email не будет опубликован.