Временные таблицы в ABAP циклах

Согласно документации если мы выполняем цикл по таблице возвращаемой из функционального метода, конструкторных выражений, или табличных выражений, с последующим присвоением к символьным переменным (ASSIGNING) или ссылочным переменным REFERENCE INTO, среда создаёт временную таблицу для данного цикла.

If the internal table is specified as the return value or result of a functional method, a constructor expression, or a table expression, the value is persisted for the duration of the loop. Afterwards, it is no longer possible to access the internal table.

Пример:

Далее рассмотрим как это выглядит при анализе используемой памяти в отладке.

На выходе из метода get_data( ) создаётся переменная ссылающаяся на тот же объект в памяти где лежат основные данные — mt_data. Срабатывает так называемый table sharing.

Но уже после первой модификации в цикле среда понимает, что использовать одну и ту же таблицу нельзя и создаёт её копию:

Соответственно mt_data остаётся без изменений.

Данное поведение описано и не вызывает никаких вопросов, однако такое поведение может вызывать некоторый ступор и непонимание, если мы получаем доступ не просто к таблице, но делаем это через ссылку на объект:

Вы можете подумать что возвращая ссылку вы уже получаете доступ по ней, однако ABAP среда так не думает. Результат работы:

Среда понимает, что результат возвращаемый из метода будет использован для цикла и создаёт как и в первом случае временную таблицу в памяти.

На выходе из метода get_reference в памяти создаётся временная ссылочная переменная ссылающаяся на инстанцию lcl_app:

Но после первого изменения табличных данных, согласно правилам table sharing создаётся копия таблицы уже с новой ссылочной переменной:

По сути предыдущий код аналогичен следующему:

Но что делать если мы все таки хотим изменить данные и обойти механизм данной оптимизации?

Обойти это можно следующим способом:

Либо:

В первом случае мы явно сохраняем ссылку на объект и уже цикл стартуем по переменной из этого объекта.

Во втором случае после оператора CAST (который по сути ничего не преобразовывает) создаётся временная ссылочная переменная:

Которая ссылается на инстанцию lcl_app. Соответственно данные будут изменены.

Еще один «абстрактный» пример, но уже с изменением через конструкторный оператор:

С помощью CAST мы таки смогли изменить данные. Пример сделан исключительно ради демонстрации, не стоит создавать методы вроде change_value с изменением переменной и одновременным возвратом 🙂

P.S. Обратите внимание, если используете временные таблицы в циклах, после завершения цикла, обратиться к FIELD-SYMBOLS будет так же невозможно, т.к. присвоение пропадёт вместе в временной таблицей:

Дополнительный пример с неочевидным поведением, где происходит принудительная передача параметра по значению:

Passing Parameters

When binding a function, a calculation expression, a constructor expression, or a table expression, the parameters are always passed by value, even if the formal parameter is defined as to be passed by reference.

Но как передать table expression по значению, я так и не понял. Возможно ошибка в документации, либо я её неверно истолковал. Если есть идеи на данный счёт просьба прокомментировать.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *