Les expressions constructeur CONV et CAST permettent des conversions de types inline. CONV convertit les types de données élémentaires, tandis que CAST est utilisé pour le casting de références d’objets.
CONV – Conversion de types
L’opérateur CONV convertit une valeur vers un autre type de données.
Syntaxe
CONV <type_cible>( <expression> )CONV #( <expression> ) " Le type est déduit du contexteExemples pour CONV
1. Conversion de type basique
" String vers IntegerDATA(lv_int) = CONV i( '42' ).WRITE: / lv_int. " 42
" Integer vers StringDATA(lv_str) = CONV string( 123 ).WRITE: / lv_str. " 123
" Packed vers FloatDATA: lv_packed TYPE p DECIMALS 2 VALUE '123.45'.DATA(lv_float) = CONV f( lv_packed ).WRITE: / lv_float. " 1.2345E+022. Comparaison : CONV vs. conversion classique
" === CLASSIQUE ===DATA: lv_string TYPE string VALUE '100', lv_number TYPE i.
lv_number = lv_string. " Conversion implicite
" Ou avec MOVEMOVE lv_string TO lv_number.
" === MODERNE AVEC CONV ===DATA(lv_number2) = CONV i( '100' ).
" Inline dans les expressionsDATA(lv_result) = CONV i( '50' ) + CONV i( '30' ).WRITE: / lv_result. " 803. CONV pour les nombres décimaux
" String vers Packed DecimalDATA(lv_amount) = CONV p DECIMALS 2( '1234.56' ).WRITE: / lv_amount. " 1234.56
" Division avec résultat correctDATA: lv_a TYPE i VALUE 10, lv_b TYPE i VALUE 3.
" Sans CONV : Division entièreDATA(lv_div1) = lv_a / lv_b.WRITE: / lv_div1. " 3 (tronqué)
" Avec CONV : Résultat décimalDATA(lv_div2) = CONV decfloat34( lv_a ) / lv_b.WRITE: / lv_div2. " 3.333...4. CONV dans les calculs
DATA: lv_quantity TYPE i VALUE 7, lv_total TYPE i VALUE 100.
" Calcul de pourcentage avec résultat décimalDATA(lv_percentage) = CONV decfloat16( lv_quantity * 100 / lv_total ).WRITE: / lv_percentage, '%'. " 7%
" Calcul précisDATA(lv_price) = CONV p DECIMALS 2( 100 / 3 ).WRITE: / lv_price. " 33.335. CONV pour les chaînes de caractères
" Char vers StringDATA: lv_char TYPE c LENGTH 10 VALUE 'Test'.DATA(lv_string) = CONV string( lv_char ).
" Numérique vers String formatéDATA: lv_num TYPE i VALUE 42.DATA(lv_formatted) = |Numéro : { CONV string( lv_num ) }|.
" NUMC vers 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 avec notation # (Déduction de type)
METHODS: process_amount IMPORTING iv_amount TYPE p DECIMALS 2.
" Le type est déduit du paramètreprocess_amount( iv_amount = CONV #( '99.99' ) ).
" Lors des affectationsDATA: lv_target TYPE p DECIMALS 2.lv_target = CONV #( '123.45' ). " Type déduit de lv_target7. CONV pour date et heure
" String vers DateDATA(lv_date) = CONV d( '20241115' ).WRITE: / lv_date. " 20241115
" TimestampDATA(lv_ts) = CONV timestamp( '20241115143000' ).
" Assembler une date à partir de partiesDATA: 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 dans les appels de méthodes
METHODS: get_discount IMPORTING iv_amount TYPE p DECIMALS 2 RETURNING VALUE(rv_discount) TYPE p DECIMALS 2.
" Conversion directe lors de l'appelDATA(lv_discount) = get_discount( iv_amount = CONV #( 100 ) ).
" Avec plusieurs paramètrescalculate( iv_quantity = CONV i( '5' ) iv_price = CONV p DECIMALS 2( '19.99' )).9. CONV avec Built-in Types
" Différents typesDATA(lv_i) = CONV i( '42' ). " IntegerDATA(lv_i8) = CONV int8( '9999999999' ). " Integer 8 octetsDATA(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 pour éviter les erreurs d’exécution
" Potentiellement erroné sans vérificationDATA: lv_input TYPE string VALUE 'abc'.
" Intercepter avec TRY-CATCHTRY. DATA(lv_number) = CONV i( lv_input ). CATCH cx_sy_conversion_no_number. WRITE: / 'Pas un nombre valide'.ENDTRY.CAST – Casting de références d’objets
L’opérateur CAST effectue un downcast ou crosscast de références d’objets.
Syntaxe
CAST <type_cible>( <reference_objet> )CAST #( <reference_objet> ) " Le type est déduit du contexteExemples pour CAST
1. Downcast (Classe de base vers sous-classe)
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 (implicite)DATA: lo_vehicle TYPE REF TO lcl_vehicle.lo_vehicle = NEW lcl_car( ).
" Downcast : Vehicle → Car (explicite avec CAST)DATA(lo_car) = CAST lcl_car( lo_vehicle ).DATA(lv_brand) = lo_car->get_brand( ).2. Comparaison : CAST vs. casting classique
" === CLASSIQUE ===DATA: lo_car_classic TYPE REF TO lcl_car.lo_car_classic ?= lo_vehicle. " Downcast avec ?=
" === MODERNE AVEC CAST ===DATA(lo_car_modern) = CAST lcl_car( lo_vehicle ).
" Ou avec déduction de typeDATA: lo_target TYPE REF TO lcl_car.lo_target = CAST #( lo_vehicle ).3. CAST avec Interface
INTERFACE lif_printable. METHODS: print.ENDINTERFACE.
CLASS lcl_document DEFINITION. PUBLIC SECTION. INTERFACES: lif_printable.ENDCLASS.
" Créer un objetDATA: lo_doc TYPE REF TO lcl_document.lo_doc = NEW #( ).
" Upcast vers interfaceDATA: lo_printable TYPE REF TO lif_printable.lo_printable = lo_doc.
" Downcast retour vers la classeDATA(lo_doc_back) = CAST lcl_document( lo_printable ).4. CAST pour chaînage de méthodes
" Sans CAST : Variable intermédiaire nécessaireDATA: 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( ).
" Avec CAST : Casting inlineCAST lcl_car( get_vehicle( ) )->start_engine( ).5. CAST dans les expressions
" Accès direct aux attributs de sous-classeDATA(lv_brand) = CAST lcl_car( lo_vehicle )->mv_brand.
" Dans les String TemplatesDATA(lv_info) = |Marque : { CAST lcl_car( lo_vehicle )->mv_brand }|.
" Dans les conditionsIF CAST lcl_car( lo_vehicle )->mv_brand = 'BMW'. WRITE: / 'BMW trouvée'.ENDIF.6. Casting sécurisé avec IS INSTANCE OF
" D'abord vérifier, puis casterIF lo_vehicle IS INSTANCE OF lcl_car. DATA(lo_safe_car) = CAST lcl_car( lo_vehicle ). lo_safe_car->start_engine( ).ENDIF.
" Avec 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: / 'Type de véhicule inconnu'.ENDCASE.7. CAST avec types génériques
" Avec DATA comme référence génériqueDATA: lr_any TYPE REF TO data.DATA: lt_table TYPE TABLE OF string.
lr_any = REF #( lt_table ).
" Cast vers type de table concretFIELD-SYMBOLS: <lt_strings> TYPE TABLE OF string.ASSIGN CAST #( lr_any )->* TO <lt_strings>.8. CAST avec RTTS (Runtime Type Services)
DATA: lo_type TYPE REF TO cl_abap_typedescr.
lo_type = cl_abap_typedescr=>describe_by_data( lv_string ).
" Cast vers Descriptor spécifiqueIF lo_type->kind = cl_abap_typedescr=>kind_elem. DATA(lo_elem) = CAST cl_abap_elemdescr( lo_type ). WRITE: / 'Longueur :', lo_elem->output_length.ENDIF.9. CAST pour le pattern 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.
" Utilisation avec CASTDATA(lo_my_car) = CAST lcl_car( lcl_vehicle_factory=>create( 'CAR' )).10. Intercepter CX_SY_MOVE_CAST_ERROR
TRY. " Cast erroné (Vehicle n'est pas un Car) DATA: lo_plain TYPE REF TO lcl_vehicle. lo_plain = NEW lcl_vehicle( ).
DATA(lo_wrong) = CAST lcl_car( lo_plain ). " ERREUR !
CATCH cx_sy_move_cast_error INTO DATA(lx_error). WRITE: / 'Cast échoué :', lx_error->get_text( ).ENDTRY.CONV vs. CAST
| Aspect | CONV | CAST |
|---|---|---|
| But | Conversion de types de données | Casting de références d’objets |
| Application | Types élémentaires, structures | Références de classes, interfaces |
| Exemple | CONV i( '42' ) | CAST lcl_car( lo_vehicle ) |
| Erreur | CX_SY_CONVERSION_* | CX_SY_MOVE_CAST_ERROR |
| Classique | Conversion implicite | Opérateur ?= |
Fonctions de conversion intégrées
En plus de CONV, il existe des fonctions intégrées :
" Conversion booléenneDATA(lv_bool) = xsdbool( lv_age >= 18 ). " abap_true/abap_false
" Booléen conditionnelDATA(lv_cond) = boolc( lv_status = 'A' ).
" Conversion Alpha (dans les String Templates)DATA(lv_matnr) = |{ lv_material ALPHA = OUT }|.
" Valeur absolueDATA(lv_abs) = abs( -42 ). " 42
" SigneDATA(lv_sign) = sign( -5 ). " -1
" ArrondiDATA(lv_round) = round( val = '3.7' dec = 0 ). " 4
" Minimum/MaximumDATA(lv_min) = nmin( val1 = 10 val2 = 5 ). " 5DATA(lv_max) = nmax( val1 = 10 val2 = 5 ). " 10Notes importantes / Bonnes pratiques
CONVpour les conversions de types de données – remplace les conversions implicites de manière explicite.CASTpour le casting de références d’objets – remplace l’opérateur?=.- Vérifiez avec
IS INSTANCE OFavant unCASTpour éviter les erreurs d’exécution. CONV #()etCAST #()déduisent le type cible du contexte.- Utilisez
TRY-CATCHpour les conversions incertaines. CONVpermet des conversions inline dans les expressions et appels de méthodes.CASTpermet le chaînage de méthodes sans variables intermédiaires.- Combinez avec
VALUE,CONDetSWITCH. - Pour les calculs décimaux : Convertissez avant la division pour des résultats précis.
- Utilisez les fonctions intégrées comme
xsdbool(),abs(),round()pour les conversions fréquentes.