필드 심볼(Field Symbol)이란?
: abap에서 메모리의 특정위치를 가리키는 이름 없는 변수
- 변수에 직접 접근 x
- 참조 형태로 데이터에 접근
- 필드심볼은 ABAP 프로그램 내에서 변수에 동적인 접근이 가능하게 함
- 필드심볼은 자기 자신을 위한 메모리 공간을 점유하지 않는다.
- 필드심볼의 데이터 이름과 속성은 실행 시점에 결정된다.
- 필드 심볼은 모든 데이터 오브젝트에 지정될 수 있다.
- 필드심볼이 할당되면 데이터 오브젝트와 필드심볼간에는 차이가 없다.
- Move와 같은 Abap명령어도 같이 사용할 수 있다.
- 필드 심볼을 명시하여 선언하거나 타입 없이 생성할 수 있다. 타입이 명시되지 않으면 할당되는 필드(오브젝트)의 타입을 그대로 상속받는다.
- gv_var의 변수의 값은 'A'였지만, write결과 'B'가 된것을 확인할 수 있다.
- 이는 gv_var 변수를 필드 심볼에 Assign했고, 필드 심볼의 값을 'B'로 변경했기 때문이다.
Generic TYPE Field Symbol
- 필드심볼을 선언할 때 타입을 지정하지 않고 할당되는 데이터 오브젝트 유형에 따라 기술적인 속성을 상속받게 된다.
- Field-symbols <f2> type any tablr을 사용하려면 assign 구문에서 할당할 오브젝트가 인터널 테이블 타입으로 선언되어야 한다.
- 이렇게 선언된 필드 심볼은 그 자체가 인터널 테이블이 되어 READ와 같은 구문을 사용할 수 있다.
- TABLE키워드를 삭제하고 TYPE ANY만 사용하면 LINE 타입의 구조체로 활용할 수 있다.
gv_var is B, fs is B. 이다.
- TYPE ANY는 정확한 데이터 타입을 모를 때 쓰는 가변 타입
- 필드 심볼이나, DATA ... FIELD-SYMBOLS선언 시,
- 동적으로 구조체의 필드를 참조할 때,
- Assign문과 함께 쓸 떄 사용함
- 단점으로는 정적 타입체크가 안된다는 점이 있음
Fully Type Field Symbol
- 필드 심볼을 정의할 때부터 타입이 완전히 정해진 형태로 선언
- 필드 심볼의 기술적인 속성은 할당되는 데이터 오브젝트와 같아야함
FIELD-SYMBOLS <fs3> TYPE SFLIGHT.
FIELD-SYMBOLS <fs4> LIKE LINE OF gt_tab.
- 필드심볼 <fs3>은 Sflight 테이블과 같은 구조를 가지는 구조체 타이블로 선언됨
- fs4는 인터널 테이블 Gt_tab과 같은 구조를 가지는 LINE타입의 필드심볼을 선언함
- 변수 이름은 메모리 정적인 주소를 가리키고 있다 (변수이름 = 메모리주소)
- fully type을 이용하면 명시적으로 구조체의 필드명을 호출해 사용할 수 있다
MOVE <fs3>-carrid TO <fs4>-carrid.
필드 심볼 할당
TYPES : BEGIN OF t_line,
col1 TYPE c,
col2 TYPE c,
END OF t_line.
DATA : gs_wa TYPE t_line,
gt_itab TYPE HASHED TABLE OF line WITH UNIQUE KEY col1,
key(4) TYPE c VALUE 'COL1'.
FILED-SYMBOLS <fs> TYPE ANY TABLE.
ASSIGN gt_itab TO <fs>.
- 필드 심볼에 오브젝트를 할당하려면 ASSIGN구문을 활용한다.
- ASSIGN구문 3가지 기능 분류
- - assign 구문의 기본 구조
- - 구조체 필드를 필드 심볼에 assign
- - 필드심볼과 casting
Assign 구문의 기본구조
1. static assign
ASSIGN dobj TO <fs>.
- ASSIGN이 성공하면 시스템 변수 sy-subrc는 0, 실패하면 4를 반환함
Offset을 이용한 static assign
- 문자열의 특정위치(인덱스)부터 일부만 참조하거나 대입하는 방식 => 위치와 길이가 고정되어있기 때문에 정적 assign이라고 함
- 인덱스 기반으로 잘라서 사용하는 방법
변수+시작오프셋(길이)
1. 문자열 일부 출력
DATA lv_text TYPE string VALUE 'ABCDEFGHIJ'.
WRITE: / lv_text+0(3). " 결과: ABC
WRITE: / lv_text+3(2). " 결과: DE
WRITE: / lv_text+5(5). " 결과: FGHIJ
lv_text+3(2) -> 4번째 문자부터 2글자 출력(인덱스는 0부터 시작)
2. 일부대입(Static assign)
DATA lv_text TYPE c LENGTH 10 VALUE 'ABCDEFGHIJ'.
lv_text+2(3) = 'XYZ'.
WRITE: / lv_text. " 결과: ABXYZFGHIJ
lv_text+2(3) : 3번째 문자부터 3글자를 XYZ로 교체
3. 동적 offset
DATA lv_offset TYPE i VALUE 2.
DATA lv_len TYPE i VALUE 3.
WRITE: / lv_text+lv_offset(lv_len). " 동적으로 접근, 결과: XYZ
- runtime에 계산이 되므로 offset에 대한 동적 Offset
오프셋을 초과하면 에러가 발생하고 컴파일되지 않는다.
=> ghijkl ghijkl ghijk 가 출력
offset이 0보다 큰 값이 할당된 경우에는 애스터리스크(*)문자를 사용해야한다. => 필드 심볼이 오브젝트 길이를 넘는 것을 방지함
Assign구문의 동적인 사용
- 필드 심볼에 할당하는 필드명을 알 수 없는 경우(프포그램 내에서 동적으로 할당되는 경우) => 동적 assign구문을 이용함
ASSIGN (dobj) TO <fs>.
-> 이와 같이 답이 나온다
- assign table field to <fs>구문에서 sflight-carrid라는 필드가 존재하므로 sy-subrc = 0값을 반한함
- name1이라는 테이블 필드가 존재지 않으므로 시스템 변수 sy-subrc가 4를 반환함
구조체의 필드를 필드 심볼에 Assign
ASSIGN COMPONENT comp of STURCUTURE struc TO <fs>.
- 구조체의 개별 필드를 필드 심볼에 assign할 수 있다.
- 구조체 struc의 comp(필드)를 필드심볼 <fs>에 할당한다.
항목 | 첫코드 | 두번째 코드 |
접근 방법 | 필드의 순서(index) | 필드의 이름(name) |
유연성 | 구조체 필드명 변경돼도 잘 작동함 | 필드명 규칙이 바뀌면 코드도 수정 필요 |
용도 | 필드 순서 기반 처리 | 명명 규칙이 있는 필드에 유용 |
필드심볼과 casting
- 데이터 오브젝트를 필드심볼에 assign할 경우, cast를 이용해 모든 데이터 타입을 필드심볼에 Assign할 수 있다.
CAST는 암묵적 형 변환과 명시적 형 변환 2가지로 분류되어 사용됨
암묵적 형 변환(Implicit Casting)
- 필드 심볼의 data type : fully type으로 선언되어 있거나 기본 데이터 타입 -c, -n, p, x-를 사용한 경우에 암묵적 형 변환을 사용함
DATA: num TYPE i VALUE 10,
text TYPE c LENGTH 5.
text = num. " 정수 10이 문자 '10'으로 자동 변환됨
- 타입이 정해진 필드 심볼과 데이터 오브젝트 타입이 다른 경우에는 cating구문을 사용해 assign해야함
ASSIGN <var> TO <fs> CASTING.
구조체 변환
DATA: gv_addr(30) TYPE c VALUE 'Korea Seoul Twin Building'.
FIELD-SYMBOLS: <fs> TYPE t_line.
ASSIGN gv_addr TO <fs>. " ❌ 오류 발생!
gv_addr은 단순 문자형_c이고, <fs>는 구조체 t_line이기에 전혀 호환이 안된다. -> 개발자가 명확히 casting한 것으로 알려줘야함!!
명시적 형 변환(Explict Casting)
FIELD-SYMBOLS : <f1> TYPE ANY.
=>
ASSIGN ADDR TO <F1> CASTING TYPE line.
casting type구문을 이용해 정해진 타입으로 형 변환을 수행하는 것을 명시적 형 변환이라고 한다.
필드심볼과 인터널 테이블
- 변수와 같이 인터널 테이블도 같은 과정으로 필드 심볼에 할당하여 사용할 수 있다.
- 필드 심볼을 이용해 인터널 테이블을 변경하면, Work Area로 복사하는 과정이 생략되기에 성능이 향상된다
- FIELD-SYMBOLS를 쓸 때 generic하게 써야하기 때문에 type any table로 써야한다.
필드 심볼과 구조체
DATA : BEGIN OF gs_line,
col1(1) TYPE c,
col2(1) TYPE c VALUE 'X',
END OF gs_line.
FIELD-SYMBOLS <fs> LIKE gs_line.
ASSIGN gs_line TO <fs>.
MOVE <fs>-col2 TO <fs>-col1.
- 필드심볼을 구조체처럼 사용할 경우에는 필드 심볼 선언 시에 LIKE or TYPE을 선언해야함
- 필드 심볼 타입이 이미 정의되어 있다면, 필드 심볼과 기술적 속성이 같은 데이터 오브젝트만이 필드 심볼에 할당될 수 있음을 의미한다.
여기서 갑자기 드는 의문
field-symbols와 like line of등과 같은 Work area는 어떻게 다른걸까? 거의 비슷한 역할을 한다고 생각이 들었다.
구분 | FIELD-SYMOLS | LIKE LINE OF로 선언한 Work Area |
개념 | “참조 (reference)” | “복사된 값 (copy of a row)” |
메모리 방식 | 원본 데이터를 직접 가리킴 | 내부 테이블의 한 줄 값을 복사해서 저장 |
수정 시 영향 | 원본 내부 테이블이 직접 변경됨 | Work area만 바뀌고 원본은 변하지 않음 |
성능 | 빠름 (복사 없음) | 복사 발생 → 약간 느릴 수 있음 |
유연성 | 유연하고 동적 처리에 적합 | 정적이고 단순한 구조에 적합 |
LIKE LINE OF 예시
DATA: gt_itab TYPE STANDARD TABLE OF sflight,
gs_line LIKE LINE OF gt_itab.
LOOP AT gt_itab INTO gs_line.
gs_line-price = gs_line-price * 2. " 원본에는 영향 X
ENDLOOP.
- gs_line은 복사된 값이기 때문에, gt_itab의 실제 데이터는 수정되지 않는다.
FIELD-SYMBOLS 예시
FIELD-SYMBOLS <fs> TYPE sflight.
LOOP AT gt_itab ASSIGNING <fs>.
<fs>-price = <fs>-price * 2. " 원본 데이터가 직접 바뀜
ENDLOOP.
- <fs>는 원본의 참조이므로 gt_itab의 내용이 직접 변경된다.
- 필드심볼 사용
- 참조처럼 작동해서 메모리를 직접 다룰 수 있음
- ASSIGNING을 써서 자동으로 원본 데이터를 수정할 수 있음
- 복사 없이 데이터를 바로 다를 수 있음
- 워크에어리어 사용
- 안정성이 높고, 복사한 구조체기 때문에 실수 방지에 좋음
- 코드가 명확함
- Modify, append, insert사용
- 매번 복사/복원하기에 성능이 떨어질 수도 있음
데이터 참조
PARAMETERS p_tname(30) DEFAULT 'sflight'.
- 사용자가 테이블 이름을 입력할 수 있게 함
- 기본값은 'sflight'. 아무것도 안넣으면 sflight 테이블 기준으로 실행됨
DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <fsl> TYPE any, <fs2> TYPE any.
- dref : 데이터 객체를 참조(포인터)할 수 있는 변수
- <fs1> : 테이블 구조 전체를 가르키는 필드 심볼
- <fs2> : 한 컬럼의 값을 기키는 필드 심볼
CREATE DATA dref TYPE (p_tname).
ASSIGN dref->* TO <fsl>.
- p_tname에 들어온 테이블명을 기반으로 그 테이블 구조를 동적으로 생성
- 구조를 <fs1> 필드 심볼에 연결(포인터 연결)
SELECT * FROM (p_tname) INTO <fsl> UP TO 3 ROWS.
- 사용자가 입력한 테이블에서 최대 3개의 레코드만 읽어서 <fs1>에 담는다.
- p_tname은 동적 SQL.
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE <fsl> TO <fs2>.
- <fs1> 구조의 각 필드 컬럼을 순서대로 <fs2>에 할당함
- sy-index는 do루프의 반복번호다.
- 데이터 참조는 데이터 오브젝트를 가리키는 포인터, 필드 심볼을 통해 데이터 오브젝트의 값에 접근한다.
- 프로그램 실행 시점에 데이터 오브젝트는 동적으로 생성되기에 메모리 주소도 동적으로 할당됨
🔑 1. 참조 변수 (Reference Variable)
DATA dref TYPE REF TO data.
- 어떤 데이터 오브젝트(객체, 구조체, 테이블 등)의 주소를 저장하는 변수
- dref는 참조 변수
- 어떤 데이터 오브젝트의 주소를 저장하는 변수
- 자체는 데이터를 갖지 않고 있고, 어떤 오브젝트를 가르키는 역할만 함
- 아무것도 가르키지 않은 상태(dref = null 상태)
오브젝트연결
1) CREATE DATA 또는 GET REFERENCE 등으로 명시적 연결
CREATE DATA dref. " dref가 가리킬 메모리 공간 동적 생성
2) GET REFERENCE OF로 기존 변수 연결
DATA val TYPE i VALUE 100.
GET REFERENCE OF val INTO dref.
- 기존 변수 val의 주소를 dref가 가리킴
연결 가능한 오브젝트들
타입 | 예시 | 설명 |
데이터 객체 | DATA val TYPE i. | 기본형 값, 구조, 내부 테이블 등 |
클래스 인스턴스 | REF TO zcl_my_class | 객체지향에서 클래스 인스턴스를 가리킴 |
동적 타입 객체 | REF TO data, FIELD-SYMBOLS TYPE ANY | 실제 타입은 나중에 결정됨 |
필드심볼 | <fs> | 간접접근이 가능함 |
- 참조가 연결되지 않은 상태에서 dref->* 접근 시 → Dump
- 반드시 IS BOUND 체크하는 습관:
IF dref IS BOUND.
ASSIGN dref->* TO <fs>.
ENDIF.
🔁 2. 역참조 (Dereferencing)
ASSIGN dref->* TO <fs>.
- 역참조는 포인터가 가르키는 주소에 저장된 데이터에 접근하는 것으로 정의됨
- 참조변수는 단지 데이터 오브젝트의 주소만 알고 있고, 실제 데이터를 사용하려면 해당 주소에 접근해야하는데 이걸 역참조라고함
- 즉, 데이터 참조가 가리키는 데이터 오브젝트의 변숫값에 접근하려면 Dereference과정을 거쳐야 한다.
- 필드 심볼에서의 casting 기능도 동일하게 사용할 수 있다.
DATA dref TYPE REF TO i. " 참조변수 선언
CREATE DATA dref. " 메모리 생성
dref->* = 100. " 역참조로 값 설정
WRITE: dref->*. " 역참조로 값 읽기
1. 구조(structure) 역참조
TYPES: BEGIN OF ty_line,
name TYPE string,
age TYPE i,
END OF ty_line.
DATA dref TYPE REF TO ty_line.
CREATE DATA dref.
dref->* = VALUE #( name = 'Wonie' age = 25 ). " 구조에 값 대입
WRITE: dref->name, dref->age. " 각 필드 직접 접근 가능
- 구조는 ->* 없이도 필드에 직접 접근이 가능함
2. 내부 테이블 참조와 역참조
TYPES: BEGIN OF ty_line,
id TYPE i,
text TYPE string,
END OF ty_line.
DATA: itab TYPE STANDARD TABLE OF ty_line,
dref TYPE REF TO data,
<itab> TYPE STANDARD TABLE.
CREATE DATA dref TYPE STANDARD TABLE OF ty_line.
ASSIGN dref->* TO <itab>.
APPEND VALUE #( id = 1 text = 'Hi' ) TO <itab>.
LOOP AT <itab> ASSIGNING FIELD-SYMBOL(<wa>).
WRITE: / <wa>-id, <wa>-text.
ENDLOOP.
- 여기서 dref->*를 통해 참조 대상 테이블 전체를 itab으로 할당
- <itab>에서 다시 한 줄씩 <wa>로 역참조하여 값 출력
->와 ->* 차이
연산자 | 용도 |
-> | 클래스 인스턴스의 메서드나 속성 접근 (객체지향용) |
->* | 데이터 오브젝트(기본형, 구조형 등) 에 대한 일반 |
TYPES: BEGIN OF t_struct,
col1 TYPE char15,
col2 TYPE char15,
END OF t_struct.
DATA: dref1 TYPE REF TO data,
dref2 TYPE REF TO data.
FIELD-SYMBOLS: <fs1> TYPE t_struct,
<fs2> TYPE char15.
CREATE DATA dref1 TYPE t_struct.
ASSIGN dref1->* TO <fs1>.
- t_struct 라는 구조체를 정의함
- dref1, dref2는 어떤 데이터는 가리킬 수 있는 Generic참조변수
- <fs1>은 구조체 타입 필드 심볼(포인터같은 역할)
- <fs2>는 char15필드를 가리킬 수 있는 필드 심볼
<fs1>-col1 = 'Enjoy abap'.
<fs1>-col2 = 'Abap Programming'.
- 생성된 구조체 인스턴스 필드에 값 저장 (dref1이 가르키는 구조체의 co1, col2)
dref2 = dref1 => dref2도 이제 같은 구조체 인스턴스를 같이 가리키게 됨(얕은 복사)
ASSIGN dref2->* TO <fs2> CASTING.
WRITE / <fs2>.
- dref2 -> *는 구조체 전체
- <fs2>는 char15 -> 타입이 달라서 casting 덕분에 첫 필드(col1)만 퉁엳
GET REFERENCE OF <fs1>-col2 INTO dref2.
- col2 필드의 참조를 dref2에 저장
- dref2 -> *는 col2 하나만 가리키는 참조
ASSIGN dref2->* TO <fs2>.
WRITE / <fs2>.
- dref2->*는 이제 col2이므로 문제없이 fs2에 연결되고 출력됨
'SAP' 카테고리의 다른 글
easy abap 40. Report Program - 이벤트 (0) | 2025.05.16 |
---|---|
easy abap 39. Report Program - 프로그램 및 데이터 선언 (0) | 2025.05.16 |
easy abap 37. VIEW_뷰, 도메인 (0) | 2025.05.14 |
easy abap 36. strucutre (0) | 2025.05.14 |
easy abap 35. Table Enhancement (0) | 2025.05.14 |