動態訪問結構成員COMPONENT … OF STRUCTURE
在ABAP中,字段符號(Field Symbol)是現有數據對象的占位符或符號名。字段符號本身不直接為數據保留物理空間,而只是指向一個分配了內存空間的數據對象。字段符號概念有點像C語言中的指針,但又不完全是指針,而是一種已解引用的指針,即用內容操作符“*”引用的指針,可以直接操作字段符號就像真正數據對象一樣。如在C語言中的語句:
int a = 10;
int * p;
p = &a;
*p = 20;
其中p是C語言定義的一個指針,ABAP中的字段符號則相當於此處的 *p ,也相當於ABAP中的REF TO引用類型變量的->*解引用
字段符號可以看作僅是已經被解除引用的指針(類似於C語言中帶有解引用操作符 * 的指針),但更像是C++中的引用類型(int i ;&ii= i;),即某個變量的別名,它與真真的指針還是有很大的區別的,在ABAP中引用變量則就是C語言中的指針。
FIELD-SYMBOLS <fs> { TYPE generic_type }|{ LIKE <generic_fs>|generic_para }
| {TYPE{[LINE OF] complete_type}|{REF TO type}}
| {LIKE{[LINE OF] dobj}|{REF TO dobj}}
<generic_fs>、generic_para、complete_type的說明請參考Form形式參數說明
<generic_fs>:
代指具有通用類型的FIELD-SYMBOLS
generic_para:
代指具有通用類型的形式參數(如FORM、類方法中的形參)
字段符號的分配ASSIGN
ASSIGN
{dobj[+off][(len)]}
|{ {(name)}|{dref->*}|{dobj INCREMENT inc }|{COMPONENT comp OF STRUCTURE struc} }
|{ {cref->(attr_name) }|{iref->(attr_name)}|{(class_name)=>(attr_name)}|{(class_name)=>attr }|{class=>(attr_name)} }
TO <fs>
{ }
| {CASTING { {}|{TYPE type|(name)}|{LIKE dobj} | {[TYPE p] DECIMALS dec} | {TYPE HANDLE handle} }}
| { { TYPE name } | { [TYPE name] DECIMALS dec } }
{ } | {RANGE range}.
被分配的數據dobj的長度要大小或等於<fs>的長度
只有在使用動態分配 ASSIGN (name)… 時,才會修改sy-subrc系統變量(成功時sy-subrc為0,否則為4),而靜態分配 ASSIGN dobj… 時后不會修改系統變量,所以在判斷靜態分配方式是否成功時,只能使用 <fs> IS [NOT] ASSIGNED 語句來判斷。
如果是動態分配ASSIGN (name)…不成功時,<fs>保持上一次的狀態;如果是靜態分配不成功時,則<fs>將會處於未分配內存的狀態,這時可以使用可以使用邏輯表達式 <fs>IS [NOT] ASSIGNED 語句來判斷某個字段符號是否已分配
靜態分配
dobj[+off][(len)]
在指定了off的情況下,一定要指定len的長度,且區域不能超過dobj所在的數據區,否則編譯不通過;
len可以是“*”來阻止分配dobj限制之外的區域給<fs>,這樣就會從指定的off位置一直到dobj數據區末尾。
注:偏移量能用於固定長度的字符類型如C、D、N、T、或者是由這些類型組件組成的結構,不用於其他類型。
只能使用 <fs> IS ASSIGNED 邏輯表達式來判斷靜態分配是否成功
DATA text TYPE c LENGTH 4 VALUE '0123'.
FIELD-SYMBOLS <char> TYPE c.
DATA off TYPE i.
DO 4 TIMES.
off = sy-index - 1.
ASSIGN text+off(1) TO <char>.
WRITE / <char>.
ENDDO.
0
1
2
3
動態分配
只能通過sy-subrc來判斷動態分配是否成功
(name)
name不一定要大寫
name可以是以下這些格式:
ü dobj+offset(len)
ü struct-field
ü obj->attr
ü class=>static_attr
ü (ProgramName)DOBJ:可以訪問主調程序中的數據
FIELD-SYMBOLS:<fs>.
DATA : str(20) TYPE c VALUE 'Output String',
name(20) TYPE c VALUE 'str'.
*靜態分配:編譯時就知道要分配的對象名
ASSIGN name TO <fs>."結果是<fs>與name變量等同
WRITE / <fs>.
*動態分配:直到運行時才知道要分配的對象名
ASSIGN (name) TO <fs>."<fs>與str變量等同
WRITE / <fs>.
<fs> = 'aaa'."由於<fs>與str是同一東西,所以只要其中一個發生變化,則另一個也會發現變化,<fs>像C++中引用類型變量,是一個別名而已
WRITE / str.
str
Output String
aaa
如果動態引用的數據對象為table work areas,則可以使用TABLE FIELD選項:
ASSIGN TABLE FIELD(<f>) TO<FS>.
其中<f>可以是普通變量的名稱,也可以是某個字段符號變量名稱。
主調程序:
REPORT zjdemo.
TABLES sbook.
sbook-fldate = sy-datum.
sbook-bookid = '111'.
"非TABLES定義的數據對象在子程序中是不能訪問的
DATA: c TYPE c VALUE 'a'.
"(zjform1)表示調zjform1程序的form1過程
PERFORM form1(zjform1).
子程序:
REPORT zjform1.
FORM form1.
PERFORM form2(zjform2).
ENDFORM.
子子程序:
FORM form2.
"注:主調程序中也同樣聲明了sbook表工作區,這里並沒有覆蓋主調程序中的定義,但不能去掉TABLES語句
TABLES sbook.
WRITE: / 'sbook-fldate修改前:',sbook-fldate.
"這里實質上是共用主調程序中的sbook表工作區對象
sbook-fldate = sy-datum + 1.
"這里還可以定義名為sbook的變量,因為與上面不在一個命名空間
DATA: sbook TYPE c VALUE 'X'.
FIELD-SYMBOLS <fs>.
ASSIGN ('SBOOK-FLDATE') TO <fs>."這里引用到了局部變量sbook但sbook非結構,沒有FLDATE字段,所以分配失敗
WRITE: / sy-subrc, '動態引用全局sbook-fldate1但失敗:', <fs>.
"這里引用到的是局部定義的sbook,而不是全局的
ASSIGN ('SBOOK') TO <fs>.
WRITE: / sy-subrc, '動態引用局部sbook:', <fs>.
FIELD-SYMBOLS <result>.
"可以明確的使用TABLE FIELD選項去搜索使用TABLE定義的變量,所以這個與上面不一樣,引用的是全局的而非局部的SBOOK
ASSIGN TABLE FIELD ('SBOOK') TO <fs>.
WRITE: / sy-subrc, '分配全局的SBOOK成功'.
ASSIGN COMPONENT 'FLDATE' OF STRUCTURE <fs> TO <result>."組件名一定要大寫
WRITE: / sy-subrc, '動態訪問全局結構SBOOK-FLDATE成功:',<result>.
"這里不能使用上面這個語句,因為在該程序中已經有sbook
ASSIGN TABLE FIELD ('SBOOK-FLDATE') TO <fs>.
WRITE: / sy-subrc, '動態引用全局sbook-fldate2:',<fs>.
"還可以直接使用以下的語法訪問其他程序中的變量
ASSIGN ('(ZJDEMO)SBOOK-FLDATE') TO <fs>.
WRITE: / sy-subrc, '動態引用全局sbook-fldate3:', <fs>.
"主調程序中的非TABLES定義的對象訪問不到,因為不是使用TABLES定義的,所以不能在不同程序中共享
ASSIGN ('C') TO <fs>.
WRITE: / sy-subrc,'嘗試引用全局的C,但失敗,所以<fs>顯示的還是上一次成功分配的值:',<fs>.
"雖然這里訪問的是當前程序中SBOOK,但該SBOOK還是共享的主調程序中的SBOOK
ASSIGN TABLE FIELD ('(ZJFORM2)SBOOK-bookid') TO <fs>.
WRITE: / sy-subrc,'引用全局的SBOOK-bookid:',<fs>.
ENDFORM.
sbook-fldate修改前: 12.09.2013
4 動態引用全局sbook-fldate1但失敗:
0 動態引用局部sbook: X
0 分配全局的SBOOK成功
0 動態訪問全局結構SBOOK-FLDATE成功: 13.09.2013
0 動態引用全局sbook-fldate2: 13.09.2013
0 動態引用全局sbook-fldate3: 13.09.2013
4 嘗試引用全局的C,但失敗,所以<fs>顯示的還是上一次成功分配的值: 13.09.2013
0 引用全局的SBOOK-bookid: 00000111
*">動態訪問數據對象dref->*
對數據對象解引用后,讓<fs>指向它
DATA g_dat TYPE string.
DATA dref TYPE REF TO data.
FIELD-SYMBOLS <l_dat> TYPE any.
CREATE DATA dref LIKE g_dat.
ASSIGN dref->* TO <l_dat>.
WRITE <l_dat> .
動態訪問結構成員COMPONENT … OF STRUCTURE
COMPONENT comp OF STRUCTURE struc
struc為結構對象。如果comp屬於類型 C 或字段串,則它表示要訪問的結構體中的組件名;如果comp為i整型,則表示結構體中要訪問的成員的索引。
DATA: BEGIN OF line,
col1 TYPE i VALUE '11',
col2 TYPE i VALUE '22',
col3 TYPE i VALUE '33',
END OF line.
DATA comp(5) VALUE 'COL3'.
FIELD-SYMBOLS: <f1>, <f2>, <f3>.
ASSIGN line TO <f1>.
ASSIGN comp TO <f2>.
DO 3 TIMES.
"通過索引動態的訪問結構成員
ASSIGN COMPONENT sy-index OF STRUCTURE <f1> TO <f3>.
WRITE <f3>.
ENDDO.
"通過成員名動態的訪問結構成員
ASSIGN COMPONENT <f2> OF STRUCTURE <f1> TO <f3>.
WRITE / <f3>.
11 22 33
33
如果定義的內表沒有組件名時,可以使用索引為0的組件來訪問這個無名字段(注:不是1):
DATA : itab TYPE TABLE OF string WITH HEADER LINE.
itab = '11'.
FIELD-SYMBOLS <fs>.
ASSIGN COMPONENT 0 OF STRUCTURE itab TO <fs>.
WRITE: <fs>.
11
動態訪問類(對象)(靜態)屬性
CLASS c1 DEFINITION.
PUBLIC SECTION.
DATA: attr TYPE i VALUE 11.
CLASS-DATA: static_attr TYPE i VALUE 22."靜態屬性
ENDCLASS.
DATA: oref TYPE REF TO c1.
CREATE OBJECT oref.
FIELD-SYMBOLS <attr> TYPE any.
ASSIGN oref->('attr') TO <attr>.
WRITE:/ <attr>."11
ASSIGN oref->('static_attr') TO <attr>.
WRITE:/ <attr>."22
ASSIGN ('c1')=>('static_attr') TO <attr>.
WRITE:/ <attr>."22
ASSIGN c1=>('static_attr') TO <attr>.
WRITE:/ <attr>."22
ASSIGN ('c1')=>static_attr TO <attr>.
WRITE:/ <attr>."22
{ }
此表示分配時不指定數據類型。
此時被分配源數據類型需要與<fs>的類型匹配
CASTING
將<fs>指向的內存區域內容以何種類型(視圖)來看待
如果要將待分配的內存區域轉換為C、N類型時,待分配的內存區域的字節數要是4 的倍數
待分配的內存區域必須要與指定的類型(不管是顯示、還是隱式轉換)對齊,即要滿足以下規則:
ü 如果要轉換為c、n、d、t時,待分配的內存區域的地址要能被2整除
ü 如果要轉換為i時,待分配的內存區域的地址要能被4整除
ü 如果要轉換為f時,待分配的內存區域的地址要能被8整除
x,c、n、d、t,i,f這四種類型之間進行轉換時,需要注意對齊要求
DATA hex TYPE x LENGTH 10.
FIELD-SYMBOLS <fs> TYPE any.
"由於X類型與C類型不能對齊(X的地址不能被2整除),所以雖然編譯能通過,但運行時會拋異常
"ASSIGN hex+0(4) TO <fs> CASTING TYPEc.
"能成功分配的前提有2個:
"一是要求待分配的內存的字節數為4的位數
"二是要求待分配的內存的地址要能被2整除,因為上面分配語句不滿足這個條件
",所以運行進拋異常了,所以偏移一位時就肯定能被2整除了
ASSIGN hex+1(8) TO <fs> CASTING TYPE c.
{}隱式類型轉換
CASTING后面不明確指定轉換類型時,分配的內存區域將會以<fs>的類型來處理。
此情況下,定義的<fs>必須是完全限定類型,或者是ABAP中預定義的通用類型c, n, p, x(這4個非限定性類型即可以隱式也可以顯示強轉)
下面程序中盡管數據對象sy-datum中不存在year、month、day這些組件,但經過將sy-datum所在的內存區域看作是t_date類型時,就可以有這些組件了:
TYPES: BEGIN OF t_date,
year(4) TYPE n,
month(2) TYPE n,
day(2) TYPE n,
END OF t_date.
FIELD-SYMBOLS <fs> TYPE t_date."將<fs>定義成了具體限定類型
ASSIGN sy-datum TO <fs> CASTING."sy-datum變量的類型與<fs>的類型實質上是完全不兼容的,雖不兼容但可以隱式強制轉換
*ASSIGN sy-datum TO <fs> CASTING TYPE t_date."完全限定類型不能進行顯示的強制類型轉換
WRITE: / <fs>-year, / <fs>-month, / <fs>-day.
2011
05
26
顯示類型轉換
顯示類型情況下<fs>定義時只能是通用類型,而不能是完全限定類型。
TYPE type|(name)
type 可以是類型的字面常量,但要大小;name為類型的名稱,必須是大寫。
此情況下type、name不能是通用類型(但c, n, p,x這4種通用類型除外),另外也不能指定為內表類型與REFTO的類型。
DATA txt(8) TYPE c VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs> CASTING TYPE d.
WRITE / <fs>.
06061998
LIKE dobj
DATA txt(8) TYPE c VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs> CASTING TYPE d.
WRITE / <fs>.
06061998
[TYPE p] DECIMALS dec
會將待分配的內存區域轉換為P類型,小位數由dec決定。可以省略TYPE,如果一定要指定TYPE,則類型只能指定為P
DATA factor TYPE p LENGTH 8 DECIMALS 0.
DATA pack TYPE p LENGTH 8 DECIMALS 0 VALUE '12345678'.
FIELD-SYMBOLS <pack> TYPE p.
DO 8 TIMES.
ASSIGN pack TO <pack> CASTING DECIMALS sy-index.
factor = pack / <pack>.
WRITE / factor.
ENDDO.
10
100
1.000
10.000
100.000
1.000.000
10.000.000
100.000.000
TYPE HANDLE handle
handle只能是CL_ABAP_DATADESCR或其子類的引用變量
DATA: dref TYPE REF TO data,
c20type TYPE REF TO cl_abap_elemdescr.
c20type = cl_abap_elemdescr=>get_c( 10 ).
CREATE DATA dref TYPE HANDLE c20type.
DATA: x20type TYPE REF TO cl_abap_elemdescr.
x20type = cl_abap_elemdescr=>get_x( 20 ).
FIELD-SYMBOLS: <fs> TYPE any.
ASSIGN dref->* TO <fs> CASTING TYPE HANDLE x20type.
已過時語法
TYPE name
[TYPE name] DECIMALS dec
name只能是"C", "D", "F", "I", "N", "P", "T", "X", "b", or "s"這些字面常量類型,大小寫敏感
如果<fs>指定了完全限定類型,則一定要與Name相同。
DATA txt(8) VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs>.
WRITE / <fs>.
"注:分配時 txt 不能比<fs>指定的類型所需空間短
ASSIGN txt TO <fs> TYPE 'D'.
WRITE / <fs>.
"類型一定要大寫
ASSIGN txt TO <fs> TYPE 'X'.
WRITE / <fs>.
19980606
19980606
31003900390038003000360030003600
分配程序公共區域局部副本
程序公共區域
定義全局的工作區域接口,它能被程序組共同使用,在這之間定義的所有對象都屬於公共的區域。
DATA BEGIN OF COMMON PART [name].
...
DATA END OF COMMON PART [name].
注,該定義只能寫在程序的全局區域,而不能寫在某個過程的里。在只定義一個這樣的公共區域時,可以省略 name,否則需要一個唯一的名字。在所有需要進行訪問的程序中需要進行同樣的定義這個公共區域才能使用。
include文件:part
* INCLUDE part.
DATA: BEGIN OF COMMON PART struc,
f1 TYPE i,
f2 TYPE i,
s TYPE i,
END OF COMMON PART struc.
主程序文件:param
PROGRAM param.
INCLUDE part." 每個程序都需要INCLUDE一下這個公共區
PARAMETERS:
p1 TYPE i DEFAULT 20,
p2 TYPE i DEFAULT 90.
f1 = p1.
f2 = p2.
PERFORM sum IN PROGRAM sum." 調用另一程序的過程
子程序文件:sum
PROGRAM sum.
INCLUDE part.
FORM summing.
s = f1 + f2.
PERFORM display IN PROGRAM disp.
ENDFORM.
子程序文件:disp
PROGRAM disp.
INCLUDE part.
FORM display.
WRITE: / f1, f2, s.
ENDFORM.
以上三個不同的程序共用同一個公共區域,不需要使用特殊的語法來進行訪問。
公共區域局部副本
ASSIGN LOCAL COPY OF ........ TO <FS>.
假設主程序 z_jzj_sapmztst 如下:
REPORT z_jzj_sapmztst.
DATA: BEGIN OF COMMON PART,
text(5) VALUE 'Text1',
END OF COMMON PART.
PERFORM routine(z_jzj_formpool2).
WRITE text.
ROUTINE過程所在的程序z_jzj_formpool2 如下:
PROGRAM z_jzj_formpool2.
DATA: BEGIN OF COMMON PART,
text(5) VALUE 'Text1',
END OF COMMON PART.
FORM routine.
FIELD-SYMBOLS <fs>.
" 現在是拷貝一份,而不是直接指向原公共區域中的對象
ASSIGN LOCAL COPY OF text TO <fs>.
WRITE <fs>.
<fs> = 'Text2'."不會修改原公共區域中的對象,而只會局部對象
WRITE <fs>.
ASSIGN text TO <fs>.
WRITE <fs>.
<fs> = 'Text3'."修改公共區域中的對象
ENDFORM.
Text1 Text2 Text1 Text3
解除分配UNASSIGN
UNASSIGN <FS>.
該語句是初始化<FS>字段符號,語句執行后,字段符號將不再引用內存區域(它指向的內存區域不會受影響),邏輯表達式<fs> IS ASSIGNED將會返回假。
CLEAR<fs>
與UNASSIGN不同的是,只有一個作用就是初始化它所指向的內存區域,而字段符號本身並沒有被解除分配
DATA: c VALUE 'a'.
FIELD-SYMBOLS: <fs1>,<fs2>.
ASSIGN c TO <fs1>.
ASSIGN c TO <fs2>.
WRITE: / <fs1>,<fs2>.
UNASSIGN <fs1>.
IF NOT <fs1> IS ASSIGNED.
WRITE: / 'fs1 is unassigned'.
ENDIF.
WRITE: / '<fs2>=',<fs2>.
CLEAR: <fs2>.
IF <fs2> IS ASSIGNED.
WRITE: / 'fs2 is assigned'.
ENDIF.
WRITE: / '<fs2>=',<fs2>.
a a
fs1 is unassigned
<fs2>= a
fs2 is assigned
<fs2>=