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 concretoFIELD-SYMBOLS: <fs_name> TYPE <tipo>.
" Con tipo genericoFIELD-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 estaticaASSIGN <variable> TO <fs>.
" Asignacion dinamica (nombre de campo como string)ASSIGN (lv_fieldname) TO <fs>.
" Componente de una estructuraASSIGN COMPONENT <nombre_o_indice> OF STRUCTURE <estructura> TO <fs>.
" Con Type-CastingASSIGN <variable> TO <fs> CASTING TYPE <tipo>.Campos del sistema
Despues de ASSIGN:
sy-subrc:0: Asignacion exitosa4: 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 variableASSIGN lv_number TO <fs_num>.
IF sy-subrc = 0. " Modificacion via Field-Symbol <fs_num> = 200.
WRITE: / 'Original:', lv_number. " Salida: 200ENDIF.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 asignacionUNASSIGN <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 copiaFIELD-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 aumentoENDLOOP.
" La tabla ahora esta modificada!4. Declaracion inline de Field-Symbol
" Moderno (desde 7.40): Declaracion inlineLOOP AT lt_materials ASSIGNING FIELD-SYMBOL(<fs_inline>). <fs_inline>-menge = <fs_inline>-menge + 50.ENDLOOP.
" Tambien con READ TABLEREAD 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 componenteDO 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 stringlv_name = 'LV_VAR1'.ASSIGN (lv_name) TO <fs_dynamic>.
IF sy-subrc = 0. WRITE: / 'Dinamico:', <fs_dynamic>. " Valor 1ENDIF.
" 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 caracteresASSIGN lv_hex TO <fs_char> CASTING TYPE c.
WRITE: / <fs_char>. " Salida: ABCD
" Casting con estructurasDATA: 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 tablasASSIGN 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 2ASSIGN lt_data[ 2 ] TO <fs_line>.
IF sy-subrc = 0. <fs_line> = 'MODIFICADO'.ENDIF.
" lt_data ahora contiene: Uno, MODIFICADO, Tres10. 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 estructuralo_struct_descr ?= cl_abap_typedescr=>describe_by_data( ls_person ).lt_components = lo_struct_descr->components.
" Recorrer todos los componentesLOOP 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)
| Aspecto | ASSIGNING (Field-Symbol) | INTO (Area de trabajo) |
|---|---|---|
| Copia de datos | No | Si |
| Rendimiento | Mas rapido | Mas lento |
| Modificaciones | Directo en tabla | Requiere MODIFY |
| Memoria | Minima | Memoria adicional |
" LENTO: Copiar y escribir de vueltaLOOP AT lt_materials INTO ls_material. ls_material-preis = ls_material-preis * 2. MODIFY lt_materials FROM ls_material.ENDLOOP.
" RAPIDO: Acceso directoLOOP 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 verificarIF <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 incompatiblesASSIGN lv_string TO <fs_int>.IF sy-subrc <> 0. WRITE: / 'Asignacion fallida!'.ENDIF.Notas importantes / Mejores practicas
- Verificar siempre
sy-subrcdespues deASSIGNoIS ASSIGNEDantes de usar. - Usar ASSIGNING en
LOOP ATen 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 TABLEpara acceso eficiente a registros individuales.