字段符号FIELD-SYMBOLS

时间:2023-12-23 10:27:32
字段符号FIELD-SYMBOLS
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4293262.html

解除分配UNASSIGN

在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

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 逻辑表达式来判断静态分配是否成功

) 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:可以访问主调程序中的数据

) ) 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.

子子程序:

.
  "这里还可以定义名为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整型,则表示结构体中要访问的成员的索引。

)  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):

 OF STRUCTURE itab TO  <fs>.
WRITE: <fs>.

11

动态访问类(对象)(静态)属性

."静态属性
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 的倍数

待分配的内存区域必须要与指定的类型(不管是显示、还是隐式转换)对齐,即要满足以下规则:

ü  如果要转换为整除

ü  如果要转换为i时,待分配的内存区域的地址要能被整除

ü  如果要转换为f时,待分配的内存区域的地址要能被整除

x,c、n、d、t,i,f这四种类型之间进行转换时,需要注意对齐要求

整除),所以虽然编译能通过,但运行时会抛异常
"ASSIGN hex+0(4) TO <fs> CASTING TYPEc.
"个:
的位数
整除,因为上面分配语句不满足这个条件
整除了
) TO <fs> CASTING TYPE c.

{}隐式类型转换

CASTING后面不明确指定转换类型时,分配的内存区域将会以<fs>的类型来处理。

个非限定性类型即可以隐式也可以显示强转)

下面程序中尽管数据对象sy-datum中不存在year、month、day这些组件,但经过将sy-datum所在的内存区域看作是t_date类型时,就可以有这些组件了:

) ) ) 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为类型的名称,必须是大写。

种通用类型除外),另外也不能指定为内表类型与REFTO的类型。

) TYPE c VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs> CASTING TYPE d.
WRITE / <fs>.

06061998

LIKE dobj

) 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 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 HANDLEhandle

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相同。

) 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.

 

,
  p2 .
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 如下:

) VALUE 'Text1',
      END OF COMMON PART.
PERFORM routine(z_jzj_formpool2).
WRITE text.

ROUTINE过程所在的程序z_jzj_formpool2 如下:

) 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>=