본문 바로가기

ABAP 프로그래밍 개념/ABAP Dynamic Programming(동적 프로그래밍)

3.ABAP 동적 프로그래밍 : Data References

객체 참조(Object Referece)와 마찬가지로, Data Reference(이하 데이터 참조) 또한, 메모리의 Data Object를 가르키고 있다. 데이터 참조는핌드 심볼과 유사하게 기존 Data Object에 대한 대체 액서스 참조(altenate access reference)로 사용할 수 있습니다. 그러나, 데이터 참조를 사용하면, 익명의 Data Object를 정의하는 것이 가능합니다. 데이터 참조는 DATA 구문을 사용하고 TYPE REF TO 라는 addition을 사용하여 정의된 데이터 참조 변수에 저장됩니다.


참조 변수 정의


데이터 참조 변수를 정의하는 문법은 아래와 같습니다.

DATA data_ref1 TYPE REF TO dtype. "Data Type"
DATA data_ref2 LIKE REF TP dobj. " Data Object"
DATA data_ref3 TYPE REF TO DATA. "Data"

첫 번째 예시는 Data Type Reference(데이터 타입 참조)를 사용한 것이고, 두 번째 예시는 Data Object Reference(데이터 객체 참조)를 사용한 것입니다. 이러한 경우들에는, 데이터 참조 객체는 Fully Typed이고 이 유형의 Data Object를 Pointer 처럼 바라볼 수 있습니다.

세 번째 예시는 Generic Type인 DATA로 정의된 것이며, 어떠한 Data Obejct를 바라볼 수 있습니다.

객체 참조(Object Reference)과 유사하게, 데이터 참조는 정적인 유형과 동적인 유형이 될 수 있습니다. 데이터 참조의 정적인 유형(Static Type)은 Fully Type이거나 Fully Generic Type 이어야 합니다. 동적인 유형은 Static Type이거나 도는 Static Type보다 더 특별해야합니다.

데이터 참조 변수가 정의될 때에는, 다른말로하면 데이터 참조 변수는 어떠한 Data Object를 가르키기 있지 않다는 것이다. Data Object에 대한 참조는 데이터 객체 참조에 지원되어야 합니다.

데이터 참조가 지원되고나면, 참조된 Data Object의 값이 아닌 그것의 메모리 위치를 지니게 됩니다. 참조된 Data Object의 값에 접근하기 위해서는, 참조 변수는 ->*(dereference selector)를 사용하여 역참조를 사용하여야 합니다.

DATA v_matnr TYPE matnr VALUE '100'.
DATA data_ref1 TYPE REF TO matnr.

GET REFERENCE OF v_matnr INTO data_ref1.

WRITE data_ref1->*.

위 예시를 보면, dara_ref1는 v_matnr라는 Data Object에 대한 참조만 유지할 뿐, 실제 그 값을 접근하여 사용 혹은 출력하기 위해서는 ->*(역참조 셀렉터) 변수를 사용하여 역참조를 통해 접근하여야 합니다.


데이터 참조 Get 하기


GET REFERENCE OF라는 구문은 존재하는 Data Object에 대해 참조를 얻기 위해 사용합니다. 이 구문을 통해서 프로그램에 존재하는 Data Object 뿐만 아니라, Assigned된 필드심볼과 역참조된 데이터 참조 변수( ->* dref )로부터 참조를 가져올 수 있습니다.

DATA v_matnr type matnr VALUE '100'.
DATA dref TYPE REF TO matnr.
DATA dref1 TYPE REF TO matnr.
FIELD-SYMBOLS <fs> TYPE matnr.
ASSIGN v_matnr TO <fs>.

"1.Data Object로 부터 참조 가져오기"
GET REFERENCE OF v_matnr into dref.

"2. 역참조된 data reference 변수로 부터 참조 가져오기"
GET REFERENCE OF dref->* INTO dref1.

"3. 필드 심볼로 부터 참조 가져오기"
GET REFERENCE OF <fs> INTO dref1.

WRITE dref->*.

Data Object 참조가 된 이후에, 참조 변수는 참조된 Data Object의 값에 접근하기 위해서는 ->* 를 사용하여 역참조를 통해 다가가야 합니다. 예를 들어, 위 구문의 예시에서 dref 값을 출력하기 위해서 ->* 기호를 통해 dref의 실제 값을 출력하였습니다.

참조 변수가 역참조되고 나면, 참조 변수는 참조된 Data Object( 참조 변수가 바라보고 있는 Data Object)로 수행할 수 있는 행동이나 구문들은 다 수행가능합니다. 다만, 데이터 참조 변수가 Fully Type 일 때만, 바로 역참조할 수 있습니다. 만약, 데이터 참조 변수가 Generic Type이라면, 반드시 데이터 참조 변수를 필드 심볼에 할당하여, 참조된 Data Obect의 값에 접근해야 합니다.

DATA v_matnr type matnr VALUE '100'.
DATA dref TYPE REF TO data.

FIELD-SYMBOLS <fs> TYPE any.

GET REFERENCE OF v_matnr into dref.

ASSIGN dref->* TO <fs>.
* WRITE dref->*. " 에러 발생됨 "
WRITE <fs>.

dref라는 참조 변수는 Generic Type으로 선언되었습니다. Data Object인 V_MATNR에 대한 참조는 GET_REFERENCE 구문을 통해 획득됩니다. 그러나, dref 참조 변수는 generic type이기 때문에, dref 참조 변수에 역참조함으로써는 바로 V_MATNR의 값에 접근하지 못합니다. 그렇기 때문에, WRITE 구문을 통해 dref->*을 나타내도 값을 표현할 수 없습니다. 

SAP Syntax 적으로도 generic type을 역참조하는 것은 에러를 발생시킵니다.

이런 genenric type을 역참조하려면, 위 예치처럼 참조변수의 역참조를 필드 심볼에 할당해야합니다. 

만약, 참조 변수가 어떠한 것도 참조하고 있지 않은 경우에은, 필 드심볼은 할당되지 않을 것입니다. 이전 필드심볼 글에서 말했듯이, 필드 심볼에 대한 접근 전에는 할당되었는지를 확인해야지 예외 상황을 피할 수 있습니다.


  Anonymous Data Obejct


Anonymous Data Obejcts는 데이터의 유형을 정적으로 알 수 없을 때 사용합니다. 우리가 Data Object를 DATA 구문을 통해 정의할 때, 모든 Data Object들은 프로그램이 실행할 때, 런타임 환경에서 만들어집니다. 모든 이러한 Data Object들은 Data Object의 이름들 사용하여 정적으로 프로그램에서 접근 가능합니다. 이러한 것들은 named data objects라고 불리웁니다.

Anonymous Data Objects는 프로그램안에서 필요에 따라 만들어지며 요구사항에 맞은 적합한 유형에 할당될 수 있습니다. 이 땐 CREATE DATA 구문을 사용하여 아래 구문과 같이 Anonymous Data Object를 만듭니다.

CREATE DATA dref TYPE|LIKE dtype.

CREATE DATA 구문은 Anonymous Data Object를 만들고 Data Object의 참조를 참조변수에 할당합니다. Anonymous Data Ojbects 그것의 이름을 통해 바로 접근되지는 않습니다. Data Objects 그것의 값에 접근하기 위해서는 역참조되어야합니다. 아래 구문은 예시입니다.

FIELD-SYMBOLS <fs> TYPE DATA.
DATA dref TYPE REF TO DATA.
CREATE DATA dref TYPE i.
ASSIGN dref->* TO <fs>.
<fs> = 5.

 

예를 들어, CREATE DATA  dref TYPE (name) 이라는 구문을 통해 보면, 데이터 유형은 괄호( )안의 필드를 사용하여 동적으로 구체화됩니다. 여기서 name은 데이터 유형을 포함하고 있는 Data Object입니다.

 SAP NetWeaver 7.4의 출시 이후에, 새로운 인스턴스화 오퍼레이션인, NEW가 등장하여, CREATE DATA 대신에 NEW를 사용하여 데이터 참조와 객체 참조를 둘 다 가능하게 하였습니다. NEW 구문은, 아래 예시와 같이 자바와 같은 타 언어와 유사합니다.

FIELD-SYMBOLS <fs> TYPE DATA.
DATA dref TYPE REF TO data.
dref = NEW i( 5 ).
ASSIGN dref->* TO <fs>.

참조 객체(Reference Objects)에 접근하는 것과  유사하게,  -> Selector을 사용하여 데이터 참조의 구성요소에 접근 할수 있습니다. 단, 만약 CREATE DATA 구문에서 TYPE을 구체화 하지 않았다면, Anonymous Data Object는 데이터 참조 변수의 정적인 타입(Static Type)으로 만들어질 것입니다. 

아래 예시는 Anonymous Data Object의 구성요소에 접근하는 코드입니다.

TYPES: BEGIN OF ty_mara,
	matnr TYPE matnr,
	mtart TYPE mtart,
END OF ty_mara.

DATA dref TYPE REF TO ty_mara.
CREATE DATA dref.
dref->matnr = '100'.

IS BOUND 구문을 사용하여 데이터 참조 변수가 유요한 참조와 역참조가 가능한지에 대해서 체크할 수 있을 것입니다.

IF dref IS BOUND.

ENDIF.

Assignment between Reference Variables


객체 참조(Object Reference)와 함께, 데이터 참조 사이에 할당을 수행할 수 있습니다. 데이터 참조가 할당되었으면, 대상 참조 변수(target)은 원천 참조 변수(Source)와 동일한 데이터 객체를 가리킵니다.

참조 변수는 오직 다른 참조 변수에 할당될 수 있습니다. 다른 말로 하면, 참조 변수를 Data Object 혹은 참조 객체(Reference Object)에 할당할 수 없고, 그 반대도 마찬가지입니다.

객체 참조와 같이, 데이터 참조 또한 Upcasting와 Downcasting을 지원합니다. 참조객체를 할당할 때, 만약 원천 참조객체의 정적인 유형이 대상 참조 변수와 유사하거나 더 특별하다면, Upcast는 수행될 것입니다. 이런 경우에 = 할당 Operator을 사용하거나 MOVE 구문을 써서 할당을 수행하면 됩니다.

Upcast는 대상 참조 변수가 Generic Type이고 원천 참조 변수가 Fully Type일 때 수행됩니다. 예시는 아래와 같습니다.

TYPES: BEGIN OF ty_mara,
	matnr TYPE matnr,
	mtart TYPE mtart,
END OF ty_mara.

DATA : dref TYPE REF TO ty_mara, " Fully Typed"
dref1 TYPE REF TO DATA. " Generic type"

CREATE DATA dref.
dref1 = dref. " Upcast

만약, 원천 참조 변수의 Static Type이 대상 참조 변수보다 더 일반적이라면, Downcast가 진행됩니다. 원천 참조 변수의 유형은 오직 실행시에만 알 수 있기 때문에 할당은 실행시에만(런타임시에만) 유효합니다.

이러한 할당을 위해서, Syntax Checker는 일반적으로 유효함을 판단할 수 없고, = 할당연산자나 MOVE 구문을 사용하면 Syntax Error을 발생시킵니다.

이러한 할당을 위해서, ?=라는 Casting 할당자나 MOVE ?TO라는 구문을 사용해야 합니다. Downcast는 원천 참조변수가 Generic Type이고 대상 참조 변수가 Fully Type일 때 가능합니다.

TYPES: BEGIN OF ty_mara,
	matnr TYPE matnr,
	mtart TYPE mtart,
END OF ty_mara.

DATA : s_mara TYPE ty_mara,
	   dref TYPE REF TO ty_mara, " Fully Typed"
       dref1 TYPE REF TO DATA. " Generic type"
CREATE DATA dref.

GET REFERENCE OF s_mara INTO dref1.

TRY,
 dref ?= dref1. " Down Cast"
 CATCH cx_sy_move_cast_error.
ENDTRY.

 

반응형