ABAP FIELD-SYMBOLS y ASSIGN: Acceso dinamico a campos

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

Los Field-Symbols son un concepto central en ABAP para el acceso dinamico a areas de memoria. A diferencia de las variables normales que copian datos, un Field-Symbol apunta directamente al area de memoria de otra variable, similar a los punteros en otros lenguajes de programacion.

Concepto basico

  • Un Field-Symbol es un marcador de posicion que apunta a un area de memoria
  • Se “asigna” a una variable concreta con ASSIGN
  • Los cambios en el Field-Symbol modifican directamente la variable original
  • Sin copia de datos = mejor rendimiento

Sintaxis

Declarar Field-Symbol

" Con tipo concreto
FIELD-SYMBOLS: <fs_name> TYPE <tipo>.
" Con tipo generico
FIELD-SYMBOLS: <fs_any> TYPE any.
FIELD-SYMBOLS: <fs_data> TYPE data.
FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_structure> TYPE any.
" Declaracion inline (desde 7.40)
ASSIGN variable TO FIELD-SYMBOL(<fs_inline>).

Variantes de ASSIGN

" Asignacion estatica
ASSIGN <variable> TO <fs>.
" Asignacion dinamica (nombre de campo como string)
ASSIGN (lv_fieldname) TO <fs>.
" Componente de una estructura
ASSIGN COMPONENT <nombre_o_indice> OF STRUCTURE <estructura> TO <fs>.
" Con Type-Casting
ASSIGN <variable> TO <fs> CASTING TYPE <tipo>.

Campos del sistema

Despues de ASSIGN:

  • sy-subrc:
    • 0: Asignacion exitosa
    • 4: Asignacion fallida (variable no existe o tipo incompatible)

Ejemplos

1. Uso basico

DATA: lv_number TYPE i VALUE 100.
FIELD-SYMBOLS: <fs_num> TYPE i.
" Asignar Field-Symbol a variable
ASSIGN lv_number TO <fs_num>.
IF sy-subrc = 0.
" Modificacion via Field-Symbol
<fs_num> = 200.
WRITE: / 'Original:', lv_number. " Salida: 200
ENDIF.

2. Verificar Field-Symbol

FIELD-SYMBOLS: <fs> TYPE any.
" Verificar antes de usar!
IF <fs> IS ASSIGNED.
" Field-Symbol apunta a datos validos
WRITE: / <fs>.
ELSE.
" Field-Symbol no esta asignado
WRITE: / 'Field-Symbol no asignado!'.
ENDIF.
" Liberar asignacion
UNASSIGN <fs>.

3. Field-Symbols con tablas internas (LOOP)

El caso de uso mas frecuente - acceso directo a filas de tabla:

TYPES: BEGIN OF ty_material,
matnr TYPE matnr,
menge TYPE i,
preis TYPE p DECIMALS 2,
END OF ty_material.
DATA: lt_materials TYPE TABLE OF ty_material.
lt_materials = VALUE #(
( matnr = 'MAT001' menge = 100 preis = '10.00' )
( matnr = 'MAT002' menge = 200 preis = '20.00' )
( matnr = 'MAT003' menge = 150 preis = '15.00' )
).
" Con Field-Symbol: Acceso directo, sin copia
FIELD-SYMBOLS: <fs_mat> TYPE ty_material.
LOOP AT lt_materials ASSIGNING <fs_mat>.
" Cambio afecta directamente la tabla
<fs_mat>-preis = <fs_mat>-preis * '1.1'. " 10% de aumento
ENDLOOP.
" La tabla ahora esta modificada!

4. Declaracion inline de Field-Symbol

" Moderno (desde 7.40): Declaracion inline
LOOP AT lt_materials ASSIGNING FIELD-SYMBOL(<fs_inline>).
<fs_inline>-menge = <fs_inline>-menge + 50.
ENDLOOP.
" Tambien con READ TABLE
READ TABLE lt_materials ASSIGNING FIELD-SYMBOL(<fs_read>)
WITH KEY matnr = 'MAT001'.
IF sy-subrc = 0.
<fs_read>-preis = 99.
ENDIF.

5. Acceso dinamico a componentes de estructura

TYPES: BEGIN OF ty_person,
nombre TYPE string,
apellido TYPE string,
edad TYPE i,
END OF ty_person.
DATA: ls_person TYPE ty_person.
FIELD-SYMBOLS: <fs_field> TYPE any.
ls_person = VALUE #( nombre = 'Juan' apellido = 'Garcia' edad = 30 ).
" Acceso por indice de componente
DO 3 TIMES.
ASSIGN COMPONENT sy-index OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Campo', sy-index, ':', <fs_field>.
ENDIF.
ENDDO.
" Acceso por nombre de componente (como string)
DATA: lv_fieldname TYPE string VALUE 'APELLIDO'.
ASSIGN COMPONENT lv_fieldname OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Apellido:', <fs_field>.
ENDIF.

6. Acceso dinamico a variables

DATA: lv_var1 TYPE string VALUE 'Valor 1',
lv_var2 TYPE string VALUE 'Valor 2',
lv_name TYPE string.
FIELD-SYMBOLS: <fs_dynamic> TYPE any.
" Nombre de variable dinamico desde string
lv_name = 'LV_VAR1'.
ASSIGN (lv_name) TO <fs_dynamic>.
IF sy-subrc = 0.
WRITE: / 'Dinamico:', <fs_dynamic>. " Valor 1
ENDIF.
" Tambien para variables globales con ruta completa
" ASSIGN ('(PROGRAMA)GLOBALVAR') TO <fs>.

7. CASTING - Conversion de tipo

DATA: lv_hex TYPE x LENGTH 4 VALUE '41424344'.
FIELD-SYMBOLS: <fs_char> TYPE c.
" Interpretar datos hex como caracteres
ASSIGN lv_hex TO <fs_char> CASTING TYPE c.
WRITE: / <fs_char>. " Salida: ABCD
" Casting con estructuras
DATA: lv_raw TYPE x LENGTH 8.
FIELD-SYMBOLS: <fs_struct> TYPE ty_small_struct.
ASSIGN lv_raw TO <fs_struct> CASTING.

8. Field-Symbols genericos

FIELD-SYMBOLS: <fs_any> TYPE any, " Cualquier tipo de datos
<fs_data> TYPE data, " Cualquier dato (no objetos)
<fs_table> TYPE ANY TABLE. " Cualquier tabla interna
DATA: lt_any TYPE TABLE OF string.
" Field-Symbol generico para tablas
ASSIGN lt_any TO <fs_table>.
IF <fs_table> IS ASSIGNED.
LOOP AT <fs_table> ASSIGNING <fs_any>.
WRITE: / <fs_any>.
ENDLOOP.
ENDIF.

9. Field-Symbol a fila de tabla con indice

DATA: lt_data TYPE TABLE OF string.
lt_data = VALUE #( ( `Uno` ) ( `Dos` ) ( `Tres` ) ).
FIELD-SYMBOLS: <fs_line> TYPE string.
" Acceso directo a fila 2
ASSIGN lt_data[ 2 ] TO <fs_line>.
IF sy-subrc = 0.
<fs_line> = 'MODIFICADO'.
ENDIF.
" lt_data ahora contiene: Uno, MODIFICADO, Tres

10. Recorrer estructuras anidadas dinamicamente

DATA: lo_struct_descr TYPE REF TO cl_abap_structdescr,
lt_components TYPE abap_compdescr_tab.
FIELD-SYMBOLS: <fs_comp> TYPE abap_compdescr,
<fs_val> TYPE any.
" Obtener descriptor de estructura
lo_struct_descr ?= cl_abap_typedescr=>describe_by_data( ls_person ).
lt_components = lo_struct_descr->components.
" Recorrer todos los componentes
LOOP AT lt_components ASSIGNING <fs_comp>.
ASSIGN COMPONENT <fs_comp>-name OF STRUCTURE ls_person TO <fs_val>.
IF sy-subrc = 0.
WRITE: / <fs_comp>-name, '=', <fs_val>.
ENDIF.
ENDLOOP.

Field-Symbol vs. INTO (Rendimiento)

AspectoASSIGNING (Field-Symbol)INTO (Area de trabajo)
Copia de datosNoSi
RendimientoMas rapidoMas lento
ModificacionesDirecto en tablaRequiere MODIFY
MemoriaMinimaMemoria adicional
" LENTO: Copiar y escribir de vuelta
LOOP AT lt_materials INTO ls_material.
ls_material-preis = ls_material-preis * 2.
MODIFY lt_materials FROM ls_material.
ENDLOOP.
" RAPIDO: Acceso directo
LOOP AT lt_materials ASSIGNING <fs_mat>.
<fs_mat>-preis = <fs_mat>-preis * 2.
ENDLOOP.

Errores frecuentes

1. Usar Field-Symbol no asignado

FIELD-SYMBOLS: <fs> TYPE any.
" ERROR: Field-Symbol no asignado!
" WRITE: / <fs>. " Error en tiempo de ejecucion!
" CORRECTO: Siempre verificar
IF <fs> IS ASSIGNED.
WRITE: / <fs>.
ENDIF.

2. Field-Symbol invalido despues de modificar tabla

LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
" CUIDADO: DELETE puede invalidar el Field-Symbol!
IF <fs>-status = 'X'.
DELETE lt_data. " <fs> ahora apunta a nada!
ENDIF.
ENDLOOP.

3. Incompatibilidad de tipos

DATA: lv_string TYPE string VALUE 'Test'.
FIELD-SYMBOLS: <fs_int> TYPE i.
" ERROR: Tipos incompatibles
ASSIGN lv_string TO <fs_int>.
IF sy-subrc <> 0.
WRITE: / 'Asignacion fallida!'.
ENDIF.

Notas importantes / Mejores practicas

  • Verificar siempre sy-subrc despues de ASSIGN o IS ASSIGNED antes de usar.
  • Usar ASSIGNING en LOOP AT en lugar de INTO para mejor rendimiento.
  • Los Field-Symbols son ideales para programacion dinamica.
  • Usar la declaracion inline (FIELD-SYMBOL(<fs>)) para codigo mas corto.
  • Con tipos genericos (TYPE any) a menudo se requiere CASTING.
  • Los Field-Symbols pueden invalidarse si los datos originales se eliminan.
  • Para referencias a objetos usar Referencias de datos.
  • Combinar con READ TABLE para acceso eficiente a registros individuales.