Las referencias de datos en ABAP son punteros tipados que apuntan a objetos de datos en memoria. A diferencia de los Field-Symbols, que apuntan directamente a memoria, las referencias de datos son variables independientes que almacenan una direccion.
Concepto basico
- Una referencia de datos es una variable que contiene la direccion de memoria de un objeto de datos
- Puede ser pasada, almacenada y comparada
- El acceso a los datos se realiza mediante desreferenciacion (
->*) - Las referencias de datos pueden estar iniciales (NULL)
Sintaxis
Declarar referencia de datos
" Referencia tipadaDATA: lr_data TYPE REF TO <tipo_datos>.
" Referencia generica (a cualquier dato)DATA: lr_any TYPE REF TO data.
" Declaracion inlineDATA(lr_inline) = REF #( variable ).Crear referencia
" Moderno (desde 7.40): REF #()lr_data = REF #( variable ).
" Clasico: GET REFERENCEGET REFERENCE OF variable INTO lr_data.
" Crear nuevo objeto de datosCREATE DATA lr_data TYPE <tipo>.lr_data = NEW #( ). " Desde 7.40Desreferenciacion
" Acceso a los datos<valor> = lr_data->*.
" En estructuras: acceso a componentes<valor> = lr_struct->comp_name.
" En tablas: acceso a filasLOOP AT lr_table->* INTO DATA(ls_line). ...ENDLOOP.Campos del sistema
Despues de operaciones con referencias de datos:
- Referencia
IS BOUND: Apunta a datos validos - Referencia
IS INITIAL: No apunta a nada (NULL)
Ejemplos
1. Uso basico
DATA: lv_number TYPE i VALUE 42.DATA: lr_number TYPE REF TO i.
" Crear referencia a variablelr_number = REF #( lv_number ).
" Desreferenciacion: leer valorWRITE: / 'Valor:', lr_number->*. " 42
" Desreferenciacion: cambiar valorlr_number->* = 100.WRITE: / 'Original:', lv_number. " 100 (cambiado!)2. Verificar referencia
DATA: lr_data TYPE REF TO string.
" Verificar si la referencia es validaIF lr_data IS BOUND. WRITE: / 'La referencia apunta a:', lr_data->*.ELSE. WRITE: / 'La referencia es NULL'.ENDIF.
IF lr_data IS INITIAL. WRITE: / 'Referencia no inicializada'.ENDIF.
" Liberar referenciaFREE lr_data.3. GET REFERENCE (sintaxis clasica)
DATA: lv_text TYPE string VALUE 'Hola Mundo'.DATA: lr_text TYPE REF TO string.
" Sintaxis clasicaGET REFERENCE OF lv_text INTO lr_text.
WRITE: / lr_text->*. " Hola Mundo4. Crear nuevo objeto de datos
DATA: lr_number TYPE REF TO i.
" Clasico: CREATE DATACREATE DATA lr_number.lr_number->* = 42.
" Moderno: NEW #()DATA(lr_string) = NEW string( 'Nuevo String' ).WRITE: / lr_string->*.
" Con tipoDATA: lr_any TYPE REF TO data.CREATE DATA lr_any TYPE i.
" Generico con tipo dinamicoDATA: lv_typename TYPE string VALUE 'STRING'.CREATE DATA lr_any TYPE (lv_typename).5. Referencias con tablas internas
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, END OF ty_customer.
DATA: lt_customers TYPE TABLE OF ty_customer, lr_table TYPE REF TO ty_customer.
lt_customers = VALUE #( ( id = 1 name = 'Muller' ) ( id = 2 name = 'Schmidt' )).
" REFERENCE INTO en el LOOPLOOP AT lt_customers REFERENCE INTO lr_table. WRITE: / lr_table->id, lr_table->name.
" Cambio via referencia lr_table->name = to_upper( lr_table->name ).ENDLOOP.
" READ TABLE con REFERENCE INTOREAD TABLE lt_customers REFERENCE INTO lr_table WITH KEY id = 1.
IF sy-subrc = 0. lr_table->name = 'Cambiado'.ENDIF.6. Almacenar referencias en tablas
DATA: lt_refs TYPE TABLE OF REF TO string.DATA: lv_str1 TYPE string VALUE 'Uno', lv_str2 TYPE string VALUE 'Dos', lv_str3 TYPE string VALUE 'Tres'.
" Recolectar referenciasAPPEND REF #( lv_str1 ) TO lt_refs.APPEND REF #( lv_str2 ) TO lt_refs.APPEND REF #( lv_str3 ) TO lt_refs.
" Recorrer referenciasLOOP AT lt_refs INTO DATA(lr_str). WRITE: / lr_str->*.ENDLOOP.
" Cambiar valores originales via referenciasREAD TABLE lt_refs INTO lr_str INDEX 1.lr_str->* = 'CAMBIADO'.WRITE: / lv_str1. " CAMBIADO7. Pasar referencias a metodos
CLASS lcl_processor DEFINITION. PUBLIC SECTION. METHODS: process_data IMPORTING ir_data TYPE REF TO i.ENDCLASS.
CLASS lcl_processor IMPLEMENTATION. METHOD process_data. IF ir_data IS BOUND. ir_data->* = ir_data->* * 2. ENDIF. ENDMETHOD.ENDCLASS.
" UsoDATA: lv_value TYPE i VALUE 50, lo_proc TYPE REF TO lcl_processor.
lo_proc = NEW #( ).lo_proc->process_data( REF #( lv_value ) ).
WRITE: / lv_value. " 1008. Referencias genericas (REF TO data)
DATA: lr_any TYPE REF TO data.FIELD-SYMBOLS: <fs_data> TYPE any.
" Referencia a IntegerDATA(lv_int) = 42.lr_any = REF #( lv_int ).
" Para el acceso: asignar Field-SymbolASSIGN lr_any->* TO <fs_data>.WRITE: / <fs_data>.
" Referencia a StringDATA(lv_str) = |Hola|.lr_any = REF #( lv_str ).
ASSIGN lr_any->* TO <fs_data>.WRITE: / <fs_data>.9. Creacion dinamica de objetos
DATA: lr_data TYPE REF TO data, lv_type TYPE string VALUE 'STRING'.
" Crear objeto de datos dinamicamenteCREATE DATA lr_data TYPE (lv_type).
" Asignar valor via Field-SymbolFIELD-SYMBOLS: <fs> TYPE any.ASSIGN lr_data->* TO <fs>.<fs> = 'Creado dinamicamente'.
WRITE: / <fs>.
" Para estructurasDATA: lv_struct_name TYPE string VALUE 'SFLIGHT'.CREATE DATA lr_data TYPE (lv_struct_name).ASSIGN lr_data->* TO <fs>.10. Comparacion de referencias
DATA: lv_data TYPE string VALUE 'Test'.DATA: lr_ref1 TYPE REF TO string, lr_ref2 TYPE REF TO string, lr_ref3 TYPE REF TO string.
lr_ref1 = REF #( lv_data ).lr_ref2 = REF #( lv_data ).lr_ref3 = lr_ref1.
" Comparacion de referencias (apuntan a la misma direccion?)IF lr_ref1 = lr_ref3. WRITE: / 'ref1 y ref3 son identicas'. " SiENDIF.
IF lr_ref1 = lr_ref2. WRITE: / 'ref1 y ref2 son identicas'. " No! (referencias diferentes)ENDIF.
" Comparacion de valoresIF lr_ref1->* = lr_ref2->*. WRITE: / 'Los valores son iguales'. " SiENDIF.Referencia de datos vs. Field-Symbol
| Aspecto | Referencia de datos | Field-Symbol |
|---|---|---|
| Tipo | Variable (REF TO) | Marcador de posicion |
| Almacenar | Si, puede almacenarse | No, solo temporal |
| Pasar | Puede pasarse como parametro | Solo uso local |
| Estado NULL | Puede estar inicial/sin vincular | No asignado |
| Sintaxis | lr_data->* | <fs> |
| Rendimiento | Ligeramente mas lento | Ligeramente mas rapido |
| Aplicacion | Almacenar, pasar | Acceso local rapido |
" Field-Symbol: Acceso local rapidoLOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>). <fs>-field = 'X'.ENDLOOP.
" Referencia de datos: Cuando la referencia debe almacenarseLOOP AT lt_data REFERENCE INTO DATA(lr_line). APPEND lr_line TO lt_references. " Almacenar referenciaENDLOOP.Casos de uso tipicos
1. Parametros opcionales
METHODS: process IMPORTING ir_config TYPE REF TO ty_config OPTIONAL.
METHOD process. IF ir_config IS BOUND. " Usar configuracion ELSE. " Valores por defecto ENDIF.ENDMETHOD.2. Retorno de referencias
METHODS: get_instance RETURNING VALUE(rr_instance) TYPE REF TO lcl_singleton.
METHOD get_instance. IF gr_instance IS NOT BOUND. gr_instance = NEW #( ). ENDIF. rr_instance = gr_instance.ENDMETHOD.3. Estructuras de datos dinamicas
" Estructura de arbol con referenciasTYPES: BEGIN OF ty_node, value TYPE string, children TYPE TABLE OF REF TO ty_node WITH EMPTY KEY, END OF ty_node.
DATA: lr_root TYPE REF TO ty_node.lr_root = NEW #( value = 'Root' ).APPEND NEW ty_node( value = 'Child 1' ) TO lr_root->children.Notas importantes / Mejores practicas
- Verifica siempre
IS BOUNDantes de desreferenciar. - Usa
REF #()en lugar deGET REFERENCEen ABAP moderno. - Field-Symbols son mas eficientes para acceso local.
- Referencias de datos son necesarias cuando las referencias deben almacenarse o pasarse.
CREATE DATApara determinacion dinamica de tipos en tiempo de ejecucion.- Cuidado con referencias genericas (
REF TO data) - se pierde la seguridad de tipos. - Combina con
LOOP AT ... REFERENCE INTOpara acceso eficiente a tablas. - Usa referencias en atributos de
CLASSpara relaciones entre objetos.