Los constructores de expresiones CONV y CAST permiten conversiones de tipo inline. CONV convierte tipos de datos elementales, mientras que CAST se utiliza para el casting de referencias a objetos.
CONV – Conversión de tipos
El operador CONV convierte un valor a otro tipo de datos.
Sintaxis
CONV <tipo_destino>( <expresion> )CONV #( <expresion> ) " El tipo se deriva del contextoEjemplos de CONV
1. Conversión de tipos básica
" String a IntegerDATA(lv_int) = CONV i( '42' ).WRITE: / lv_int. " 42
" Integer a StringDATA(lv_str) = CONV string( 123 ).WRITE: / lv_str. " 123
" Packed a FloatDATA: lv_packed TYPE p DECIMALS 2 VALUE '123.45'.DATA(lv_float) = CONV f( lv_packed ).WRITE: / lv_float. " 1.2345E+022. Comparación: CONV vs. conversión clásica
" === CLÁSICO ===DATA: lv_string TYPE string VALUE '100', lv_number TYPE i.
lv_number = lv_string. " Conversión implícita
" O con MOVEMOVE lv_string TO lv_number.
" === MODERNO CON CONV ===DATA(lv_number2) = CONV i( '100' ).
" Inline en expresionesDATA(lv_result) = CONV i( '50' ) + CONV i( '30' ).WRITE: / lv_result. " 803. CONV para números decimales
" String a Packed DecimalDATA(lv_amount) = CONV p DECIMALS 2( '1234.56' ).WRITE: / lv_amount. " 1234.56
" División con resultado correctoDATA: lv_a TYPE i VALUE 10, lv_b TYPE i VALUE 3.
" Sin CONV: División enteraDATA(lv_div1) = lv_a / lv_b.WRITE: / lv_div1. " 3 (truncado)
" Con CONV: Resultado decimalDATA(lv_div2) = CONV decfloat34( lv_a ) / lv_b.WRITE: / lv_div2. " 3.333...4. CONV en cálculos
DATA: lv_quantity TYPE i VALUE 7, lv_total TYPE i VALUE 100.
" Cálculo de porcentaje con resultado decimalDATA(lv_percentage) = CONV decfloat16( lv_quantity * 100 / lv_total ).WRITE: / lv_percentage, '%'. " 7%
" Cálculo precisoDATA(lv_price) = CONV p DECIMALS 2( 100 / 3 ).WRITE: / lv_price. " 33.335. CONV para cadenas de caracteres
" Char a StringDATA: lv_char TYPE c LENGTH 10 VALUE 'Test'.DATA(lv_string) = CONV string( lv_char ).
" Numérico a String formateadoDATA: lv_num TYPE i VALUE 42.DATA(lv_formatted) = |Número: { CONV string( lv_num ) }|.
" NUMC a IntegerDATA: lv_numc TYPE n LENGTH 10 VALUE '0000000123'.DATA(lv_int_from_numc) = CONV i( lv_numc ).WRITE: / lv_int_from_numc. " 1236. CONV con notación # (derivación de tipo)
METHODS: process_amount IMPORTING iv_amount TYPE p DECIMALS 2.
" El tipo se deriva del parámetroprocess_amount( iv_amount = CONV #( '99.99' ) ).
" En asignacionesDATA: lv_target TYPE p DECIMALS 2.lv_target = CONV #( '123.45' ). " Tipo derivado de lv_target7. CONV para fecha y hora
" String a FechaDATA(lv_date) = CONV d( '20241115' ).WRITE: / lv_date. " 20241115
" TimestampDATA(lv_ts) = CONV timestamp( '20241115143000' ).
" Componer fecha de partesDATA: lv_year TYPE n LENGTH 4 VALUE '2024', lv_month TYPE n LENGTH 2 VALUE '11', lv_day TYPE n LENGTH 2 VALUE '15'.
DATA(lv_date2) = CONV d( |{ lv_year }{ lv_month }{ lv_day }| ).8. CONV en llamadas a métodos
METHODS: get_discount IMPORTING iv_amount TYPE p DECIMALS 2 RETURNING VALUE(rv_discount) TYPE p DECIMALS 2.
" Conversión directa en la llamadaDATA(lv_discount) = get_discount( iv_amount = CONV #( 100 ) ).
" Con múltiples parámetroscalculate( iv_quantity = CONV i( '5' ) iv_price = CONV p DECIMALS 2( '19.99' )).9. CONV con Built-in Types
" Varios tiposDATA(lv_i) = CONV i( '42' ). " IntegerDATA(lv_i8) = CONV int8( '9999999999' ). " 8-Byte IntegerDATA(lv_f) = CONV f( '3.14159' ). " Floating PointDATA(lv_p) = CONV p DECIMALS 4( '123.4567' ). " PackedDATA(lv_df16) = CONV decfloat16( '123.456789' ). " Decimal Float 16DATA(lv_df34) = CONV decfloat34( '123.456789' ). " Decimal Float 34DATA(lv_c10) = CONV c LENGTH 10( 'Test' ). " Char 10DATA(lv_n5) = CONV n LENGTH 5( 42 ). " NUMC 510. CONV para evitar errores en tiempo de ejecución
" Potencialmente erróneo sin verificaciónDATA: lv_input TYPE string VALUE 'abc'.
" Capturar con TRY-CATCHTRY. DATA(lv_number) = CONV i( lv_input ). CATCH cx_sy_conversion_no_number. WRITE: / 'No es un número válido'.ENDTRY.CAST – Casting de referencias a objetos
El operador CAST realiza un Downcast o Crosscast de referencias a objetos.
Sintaxis
CAST <tipo_destino>( <referencia_objeto> )CAST #( <referencia_objeto> ) " El tipo se deriva del contextoEjemplos de CAST
1. Downcast (Clase base -> Subclase)
CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. METHODS: get_type RETURNING VALUE(rv_type) TYPE string.ENDCLASS.
CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle. PUBLIC SECTION. METHODS: get_brand RETURNING VALUE(rv_brand) TYPE string. DATA: mv_brand TYPE string.ENDCLASS.
" Upcast: Car -> Vehicle (implícito)DATA: lo_vehicle TYPE REF TO lcl_vehicle.lo_vehicle = NEW lcl_car( ).
" Downcast: Vehicle -> Car (explícito con CAST)DATA(lo_car) = CAST lcl_car( lo_vehicle ).DATA(lv_brand) = lo_car->get_brand( ).2. Comparación: CAST vs. casting clásico
" === CLÁSICO ===DATA: lo_car_classic TYPE REF TO lcl_car.lo_car_classic ?= lo_vehicle. " Downcast con ?=
" === MODERNO CON CAST ===DATA(lo_car_modern) = CAST lcl_car( lo_vehicle ).
" O con derivación de tipoDATA: lo_target TYPE REF TO lcl_car.lo_target = CAST #( lo_vehicle ).3. CAST con Interface
INTERFACE lif_printable. METHODS: print.ENDINTERFACE.
CLASS lcl_document DEFINITION. PUBLIC SECTION. INTERFACES: lif_printable.ENDCLASS.
" Crear objetoDATA: lo_doc TYPE REF TO lcl_document.lo_doc = NEW #( ).
" Upcast a InterfaceDATA: lo_printable TYPE REF TO lif_printable.lo_printable = lo_doc.
" Downcast de vuelta a la claseDATA(lo_doc_back) = CAST lcl_document( lo_printable ).4. CAST para encadenamiento de métodos
" Sin CAST: Necesita variable intermediaDATA: lo_base TYPE REF TO lcl_vehicle.lo_base = get_vehicle( ).DATA: lo_car TYPE REF TO lcl_car.lo_car ?= lo_base.lo_car->start_engine( ).
" Con CAST: Casting inlineCAST lcl_car( get_vehicle( ) )->start_engine( ).5. CAST en expresiones
" Acceso directo a atributos de subclaseDATA(lv_brand) = CAST lcl_car( lo_vehicle )->mv_brand.
" En String TemplatesDATA(lv_info) = |Marca: { CAST lcl_car( lo_vehicle )->mv_brand }|.
" En condicionesIF CAST lcl_car( lo_vehicle )->mv_brand = 'BMW'. WRITE: / 'BMW encontrado'.ENDIF.6. Casting seguro con IS INSTANCE OF
" Primero verificar, luego castearIF lo_vehicle IS INSTANCE OF lcl_car. DATA(lo_safe_car) = CAST lcl_car( lo_vehicle ). lo_safe_car->start_engine( ).ENDIF.
" Con CASE TYPE OFCASE TYPE OF lo_vehicle. WHEN TYPE lcl_car. CAST lcl_car( lo_vehicle )->start_engine( ). WHEN TYPE lcl_truck. CAST lcl_truck( lo_vehicle )->load_cargo( ). WHEN OTHERS. WRITE: / 'Tipo de vehículo desconocido'.ENDCASE.7. CAST con tipos genéricos
" Con DATA como referencia genéricaDATA: lr_any TYPE REF TO data.DATA: lt_table TYPE TABLE OF string.
lr_any = REF #( lt_table ).
" Cast a tipo de tabla concretoFIELD-SYMBOLS: <lt_strings> TYPE TABLE OF string.ASSIGN CAST #( lr_any )->* TO <lt_strings>.8. CAST con RTTS (Runtime Type Services)
DATA: lo_type TYPE REF TO cl_abap_typedescr.
lo_type = cl_abap_typedescr=>describe_by_data( lv_string ).
" Cast a Descriptor específicoIF lo_type->kind = cl_abap_typedescr=>kind_elem. DATA(lo_elem) = CAST cl_abap_elemdescr( lo_type ). WRITE: / 'Longitud:', lo_elem->output_length.ENDIF.9. CAST para patrón Factory
CLASS lcl_vehicle_factory DEFINITION. PUBLIC SECTION. CLASS-METHODS: create IMPORTING iv_type TYPE string RETURNING VALUE(ro_vehicle) TYPE REF TO lcl_vehicle.ENDCLASS.
CLASS lcl_vehicle_factory IMPLEMENTATION. METHOD create. ro_vehicle = SWITCH #( iv_type WHEN 'CAR' THEN NEW lcl_car( ) WHEN 'TRUCK' THEN NEW lcl_truck( ) ELSE NEW lcl_vehicle( ) ). ENDMETHOD.ENDCLASS.
" Uso con CASTDATA(lo_my_car) = CAST lcl_car( lcl_vehicle_factory=>create( 'CAR' )).10. Capturar CX_SY_MOVE_CAST_ERROR
TRY. " Cast erróneo (Vehicle no es un Car) DATA: lo_plain TYPE REF TO lcl_vehicle. lo_plain = NEW lcl_vehicle( ).
DATA(lo_wrong) = CAST lcl_car( lo_plain ). " ¡ERROR!
CATCH cx_sy_move_cast_error INTO DATA(lx_error). WRITE: / 'Cast fallido:', lx_error->get_text( ).ENDTRY.CONV vs. CAST
| Aspecto | CONV | CAST |
|---|---|---|
| Propósito | Conversión de tipos de datos | Casting de referencias a objetos |
| Aplicación | Tipos elementales, estructuras | Referencias a clases, Interfaces |
| Ejemplo | CONV i( '42' ) | CAST lcl_car( lo_vehicle ) |
| Error | CX_SY_CONVERSION_* | CX_SY_MOVE_CAST_ERROR |
| Clásico | Conversión implícita | Operador ?= |
Funciones de conversión integradas
Además de CONV, hay funciones integradas:
" Conversión booleanaDATA(lv_bool) = xsdbool( lv_age >= 18 ). " abap_true/abap_false
" Boolean condicionalDATA(lv_cond) = boolc( lv_status = 'A' ).
" Conversión Alpha (en String Templates)DATA(lv_matnr) = |{ lv_material ALPHA = OUT }|.
" Valor absolutoDATA(lv_abs) = abs( -42 ). " 42
" SignoDATA(lv_sign) = sign( -5 ). " -1
" RedondeoDATA(lv_round) = round( val = '3.7' dec = 0 ). " 4
" Mínimo/MáximoDATA(lv_min) = nmin( val1 = 10 val2 = 5 ). " 5DATA(lv_max) = nmax( val1 = 10 val2 = 5 ). " 10Notas importantes / Mejores prácticas
CONVpara conversiones de tipos de datos – reemplaza conversiones implícitas de forma explícita.CASTpara casting de referencias a objetos – reemplaza el operador?=.- Verifique con
IS INSTANCE OFantes de unCASTpara evitar errores en tiempo de ejecución. CONV #()yCAST #()derivan el tipo destino del contexto.- Use
TRY-CATCHpara conversiones inciertas. CONVpermite conversiones inline en expresiones y llamadas a métodos.CASTpermite encadenamiento de métodos sin variables intermedias.- Combine con
VALUE,CONDySWITCH. - En cálculos decimales: Convierta antes de la división para resultados precisos.
- Use Built-in Functions como
xsdbool(),abs(),round()para conversiones frecuentes.