字段符号FIELD-SYMBOLS

时间:2021-03-03 12:17:40

字段符号的分配ASSIGN.. 131

静态分配... 132

动态分配... 132

(name)132

动态访问数据对象dref->*. 134

动态访问结构成员COMPONENT … OF STRUCTURE. 134

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

{ }135

CASTING.. 135

{}隐式类型转换... 136

显示类型转换... 136

已过时语法... 137

分配程序公共区域局部副本... 138

程序公共区域... 138

公共区域局部副本... 139

解除分配UNASSIGN

 

ABAP字段符号Field Symbol是现有数据对象的占位符或符号名。字段符号本身不直接为数据保留物理空间,而只是指向一个分配了内存空间的数据对象。字段符号概念有点C语言中的指针,但又不完全是指针,而是一种已解引用的指针,即用内容操作符“*”引用的指针,可以直接操作字段符号就像真正数据对象一样。如在C语言中的语句:

int a = 10;

int * p;

p = &a;

*p = 20;

其中pC语言定义的一个指针,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_paracomplete_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数据区末尾。

 

注:偏移量能用于固定长度的字符类型如CDNT、或者是由这些类型组件组成的结构,不用于其他类型。

 

只能使用 <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>."这里引用到了局部变量sbooksbook非结构,没有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 或字段串,则它表示要访问的结构体中的组件名;如果compi整型,则表示结构体中要访问的成员的索引。

 

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>指向的内存区域内容以何种类型(视图)来看待

 

如果要将待分配的内存区域转换为CN类型时,待分配的内存区域的字节数要是4 的倍数

 

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

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

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

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

 

xcndtif这四种类型之间进行转换时,需要注意对齐要求

 

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, x4个非限定性类型即可以隐式也可以显示强转

 

下面程序中尽管数据对象sy-datum中不存在yearmonthday这些组件,但经过将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为类型的名称,必须是大写。

此情况下typename不能是通用类型(但c, n, p,x4种通用类型除外),另外也不能指定为内表类型与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>=