数据引用与字段符号 (★★★)
#data-reference #internal-tables
概述
| 特性 |
数据引用 |
字段符号 |
| 声明 |
TYPE REF TO DATA |
FIELD-SYMBOLS <fs> TYPE ... |
| 赋值 |
GET REFERENCE OF ... INTO dref |
ASSIGN ... TO <fs> |
| 访问 |
dref->*(解引用) |
<fs>(直接使用) |
| 检查有效性 |
IS BOUND |
IS ASSIGNED |
| 取消 |
CLEAR dref |
UNASSIGN <fs> |
| 内存模型 |
指向数据对象的指针 |
数据对象的别名 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 数据引用 vs 字段符号: +-------------------------------------------------+ | | | 数据对象 dref (TYPE REF TO DATA) | | +-----------+ +-----------+ | | | 值:42 | <----| 地址 | | | +-----------+ +-----------+ | | ^ | | | | | dref->* | | +-------------------+ (解引用) | | | | 数据对象 <fs> (FIELD-SYMBOL) | | +-----------+ +-----------+ | | | 值:42 | <----| 别名 | | | +-----------+ +-----------+ | | ^ | | | | | <fs> | | +-------------------+ (直接访问) | | | +-------------------------------------------------+
|
数据引用
声明和创建
1 2 3 4 5 6 7 8 9 10
| " 声明 DATA: lr_data TYPE REF TO DATA.
" 获取已有数据对象的引用 DATA: lv_value TYPE i VALUE 42. GET REFERENCE OF lv_value INTO lr_data.
" 在运行时创建匿名数据对象 CREATE DATA lr_data TYPE i. CREATE DATA lr_data TYPE (lv_type_name). " 动态类型
|
解引用
1 2 3
| " 通过解引用访问值 lr_data->* = 100. WRITE: / lr_data->*.
|
IS BOUND vs IS INITIAL
| 检查 |
含义 |
lr_data IS BOUND |
引用指向一个数据对象 |
lr_data IS INITIAL |
引用是初始的(空指针) |
lr_data IS NOT BOUND |
引用不指向任何对象 |
1 2 3 4 5
| IF lr_data IS BOUND. WRITE: / lr_data->*. ELSE. WRITE: / '引用未绑定'. ENDIF.
|
字段符号
声明和赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| " 声明 FIELD-SYMBOLS: <fs> TYPE i, <fs_any> TYPE any, " 泛型 <fs_struc> TYPE struc. " 结构化
" 赋值数据对象 ASSIGN lv_value TO <fs>.
" 带类型转换的赋值 ASSIGN lv_hex TO <fs> TYPE c. " 将字节解释为字符
" 取消赋值 UNASSIGN <fs>.
" 检查赋值 IF <fs> IS ASSIGNED. WRITE: / <fs>. ENDIF.
|
| 检查 |
含义 |
<fs> IS ASSIGNED |
字段符号指向一个数据对象 |
<fs> IS NOT ASSIGNED |
字段符号未赋值 |
与内表配合使用
访问方法概述
| 语句 |
使用字段符号 |
使用数据引用 |
LOOP AT |
ASSIGNING <fs> |
REFERENCE INTO dref |
READ TABLE |
ASSIGNING <fs> |
REFERENCE INTO dref |
INSERT |
ASSIGNING <fs> |
REFERENCE INTO dref |
MODIFY |
隐式(无额外语法) |
不适用 |
LOOP AT … ASSIGNING
1 2 3 4
| " 通过字段符号直接修改 - 无数据复制 LOOP AT lt_itab ASSIGNING FIELD-SYMBOL(<fs_row>). <fs_row>-amount = <fs_row>-amount * 2. " 直接修改表 ENDLOOP.
|
LOOP AT … REFERENCE INTO
1 2 3 4
| " 每行的引用 LOOP AT lt_itab REFERENCE INTO DATA(lr_row). lr_row->*-amount = lr_row->*-amount * 2. " 通过解引用修改表 ENDLOOP.
|
READ TABLE … ASSIGNING
1 2 3 4 5 6 7
| " 读取到字段符号 READ TABLE lt_itab ASSIGNING FIELD-SYMBOL(<fs_row>) WITH TABLE KEY id = '123'.
IF sy-subrc = 0. <fs_row>-status = 'X'. " 直接修改 ENDIF.
|
READ TABLE … REFERENCE INTO
1 2 3 4 5 6 7
| " 读取到引用 READ TABLE lt_itab REFERENCE INTO DATA(lr_row) WITH TABLE KEY id = '123'.
IF sy-subrc = 0. lr_row->*-status = 'X'. " 通过解引用修改 ENDIF.
|
INSERT … ASSIGNING / REFERENCE INTO
1 2 3 4 5 6
| " 插入并获取新行的引用/字段符号 INSERT ls_wa INTO TABLE lt_itab ASSIGNING FIELD-SYMBOL(<fs_new>). INSERT ls_wa INTO TABLE lt_itab REFERENCE INTO DATA(lr_new).
" 继续操作新行 <fs_new>-created_at = sy-uzeit.
|
使用字段符号的 MODIFY
1 2 3 4 5
| " 字段符号直接修改表行 - 不需要 MODIFY 语句! LOOP AT lt_itab ASSIGNING FIELD-SYMBOL(<fs_row>). <fs_row>-processed = abap_true. " 不需要 MODIFY;<fs_row> 已经指向表行 ENDLOOP.
|
性能优势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| +----------------------------------------------------------+ | 数据复制比较 | +----------------------------------------------------------+ | | | INTO wa: 将行数据复制到工作区 | | +---------+ +---------+ 必须使用 MODIFY | | | 表 | --> | WA 副本 | 写回到表 | | +---------+ +---------+ (双重复制) | | | | ASSIGNING <fs>:无复制 - 直接指针 | | +---------+ +---------+ 通过 <fs> 的更改 | | | 表 | <-- | <fs> | 直接写入表 | | +---------+ +---------+ (零复制) | | | | REFERENCE INTO:无复制 - 引用指针 | | +---------+ +---------+ 通过 dref->* 的更改 | | | 表 | <-- | dref | 直接写入表 | | +---------+ +---------+ (零复制) | | | +----------------------------------------------------------+
|
| 方法 |
数据复制 |
修改方式 |
性能 |
INTO wa |
是(复制进 + 复制回) |
需要 MODIFY |
最慢 |
ASSIGNING <fs> |
无复制 |
通过 <fs> 直接 |
最快 |
REFERENCE INTO dref |
无复制 |
通过 dref->* |
快 |
完整方法比较
1 2 3 4 5 6 7 8 9
| 操作 INTO wa ASSIGNING <fs> REFERENCE INTO dref ---------------- ----------- -------------- ------------------- LOOP AT itab 复制行 无复制 无复制 READ TABLE 复制行 无复制 无复制 INSERT 不适用 获取新行 <fs> 获取新行 dref MODIFY 需要 不需要 不适用
数据访问 wa-field <fs>-field dref->*-field 检查有效性 sy-subrc IS ASSIGNED IS BOUND
|
考试/测试模式
| 关键词/模式 |
答案 |
| “ASSIGNING vs INTO” |
ASSIGNING = 无复制,直接修改;INTO = 数据复制 |
| “REFERENCE INTO” |
到行的数据引用;通过 dref->* 访问 |
| “IS BOUND” |
引用变量指向一个数据对象 |
| “IS ASSIGNED” |
字段符号指向一个数据对象 |
| “用 ->* 解引用” |
dref->* 访问被引用的数据对象 |
| “泛型引用解引用” |
TYPE REF TO DATA 必须使用 ASSIGN dref->* TO <fs> 处理泛型 |
| “使用字段符号的 MODIFY” |
不需要;对 <fs> 的更改直接修改表 |
| “性能” |
ASSIGNING 和 REFERENCE INTO 避免数据复制 |
| “GET REFERENCE OF” |
获取已有数据对象的引用指针 |
| “CREATE DATA” |
在运行时创建匿名数据对象 |
| “UNASSIGN” |
移除字段符号的赋值 |
| “insert + assigning” |
INSERT ... INTO TABLE ... ASSIGNING <fs> 获取新行的访问 |
相关笔记