数据声明相关示例
内联数据声明
在某些情况下,数据声明可以内联执行。
LOOP AT lt_sflight INTO DATA(ls_sflight).
WRITE ls_sflight-carrid.
ENDLOOP.
SELECT 语句中的内联数据声明
在 SELECT...ENDSELECT 块或 SELECT SINGLE 语句中使用内联数据声明时,必须使用 @ 字符作为 DATA(lv_cityto) 表达式的转义字符。一旦使用了转义字符,所有其他主机变量也必须转义(如下面的 lv_carrid)。
DATA lv_carrid TYPE s_carr_id VALUE 'LH'.
SELECT SINGLE cityto FROM spfli
INTO @DATA(lv_cityto)
WHERE carrid = @lv_carrid
AND connid = 2402.
WRITE: / lv_cityto.
多变量声明
DATA: begda TYPE sy-datum,
endda TYPE sy-datum.
单变量声明
DATA begda TYPE sy-datum.
变量声明选项
可以使用特殊选项声明不同类型的变量。
DATA: lv_string TYPE string, " standard declaration
lv_char TYPE c, " declares a character variable of length 1
lv_char5(5) TYPE c, " declares a character variable of length 5
l_packed TYPE p LENGTH 10 DECIMALS 5 VALUE '1234567890.123456789'. " evaluates to 1,234,567,890.12346
动态编程
数据引用
对于数据引用来说,在 TYPE 后添加 REF TO 是必不可少的。
动态创建结构
如果结构的类型应在运行时决定,我们可以将目标结构定义为对通用类型数据的引用 data。
DATA wa TYPE REF TO data.
我们使用语句 CREATE DATA 给 wa 添加类型。添加的 TYPE 可以通过以下方式指定:
引用:
CREATE DATA wa TYPE kna1
- 静态检查是有效的,因此不可能创建未知类型
命名:
CREATE DATA wa TYPE (lw_name_as_string)
- 需要使用括号,
lw_name_as_string包含字符串形式的类型名称。 - 如果未找到类型,将产生
CX_SY_CREATE_DATA_ERROR类型的异常
对于动态创建类型的实例化,可以指定 HANDLE 附加。HANDLE 接收一个继承自 CL_ABAP_DATADESCR 的对象。
CREATE DATA dref TYPE HANDLE obj
- 可使用运行时类型服务( RunTime Type Services)创建
obj - 由于
dref仍然是一个数据引用,因此必须对其进行取消引用 (->*) 才能将其用作数据容器(通常通过字段符号 Field-Symbols 完成)。
Field-Symbols
字段符号(Field-Symbols)相当于 ABAP 的指针,只是字段符号总是被取消引用(不可能更改内存中的实际地址)。
定义
要声明字段符号,必须使用关键字 FIELD-SYMBOLS。类型可以是通用类型(ANY [...... TABLE]),以处理各种变量。
FIELD-SYMBOLS: <fs_line> TYPE any, "generic
<fs_struct> TYPE kna1. "non-generic
Assigning
字段符号在声明时是未赋值的,这意味着它们什么也不指向。访问未赋值的字段符号会导致异常,如果未捕获,还会导致短转储。因此,应使用 IS ASSIGNED 检查状态:
IF <fs> IS ASSIGNED.
*... symbol is assigned
ENDIF.
由于它们只是引用,内部无法存储真实数据。因此,每次使用时都需要声明 DATA。
DATA: w_name TYPE string VALUE `Max`,
w_index TYPE i VALUE 1.
FIELD-SYMBOLS <fs_name> TYPE any.
ASSIGN w_name TO <fs_name>. "<fs_name> now gets w_name
<fs_name> = 'Manni'. "Changes to <fs_name> now also affect w_name
* As <fs_name> is generic, it can also be used for numbers
ASSIGN w_index TO <fs_name>. "<fs_name> now refers to w_index.
ADD 1 TO <fs_name>. "w_index gets incremented by one
Unassigning
有时,重置字段符号可能很有用。这可以使用 UNASSIGN(取消指定)来实现。
UNASSIGN <fs>.
* Access on <fs> now leads to an exception again
用于内表
字段符号可用于修改内部表格。
LOOP AT itab INTO DATA(wa).
* Only modifies wa_line
wa-name1 = 'Max'.
ENDLOOP.
LOOP AT itab ASSIGNING FIELD-SYMBOL(<fs>).
* Directly refers to a line of itab and modifies its values
<fs>-name1 = 'Max'.
ENDLOOP.
注意!即使离开循环后,字段符号仍会保留。如果想安全地重复使用,请立即取消分配(unassign)。
运行时类型服务
官方文档:RTTS - Runtime Type Services - ABAP Keyword Documentation (sap.com)
运行时类型服务(RunTime Type Services,简称:RTTS),通过类型描述类的层次结构实现的,其中包含
- 创建类型(RunTime Type Creation,运行时类型创建;简称:RTTC)
- 分析类型(RunTime Type Identification,运行时类型鉴定;简称:RTTI)
使用这些系统类可以:
- 在运行时确定 ABAP 类型系统中现有实例和类型名称的类型信息。
- 在运行时定义新的数据类型。
概念
types 的属性由类型描述对象(type description objects)的属性表示。每个类型都有一个类型描述对象。类型描述对象的属性包含有关类型属性的信息。每一类类型(基本类型、表、类等)都有一个类型描述类,其特殊属性用于表示特殊类型的属性。类型描述类的类层次结构与 ABAP 类型系统中类型类别的层次结构相对应。
此外,复杂类型、引用、类和接口的类型描述类还具有指定部分类型引用的特殊方法。这些方法可用于使用复合类型导航到所有部分类型。
只有使用类型描述类的方法才能创建类型描述对象。要获取对某一类型的类型描述对象的引用,可以使用 CL_ABAP_TYPEDESCR 类的静态方法或调用特殊类型描述类的方法。
笔记: 在
CREATE DATA语句中,可以在添加HANDLE之后指定类型描述对象,以动态创建数据类型来创建数据对象。
类型描述类的层次结构
CL_ABAP_TYPEDESCR
|
|--CL_ABAP_DATADESCR
| |
| |--CL_ABAP_ELEMDESCR
| |--CL_ABAP_REFDESCR
| |--CL_ABAP_COMPLEXDESCR
| |
| |--CL_ABAP_STRUCTDESCR
| |--CL_ABAP_TABLEDESCR
|
|--CL_ABAP_OBJECTDESCR
|
|--CL_ABAP_CLASSDESCR
|--CL_ABAP_INTFDESCR
CL_ABAP_TYPEDESCR 是基类,提供了四种方法来派生类型的描述对象:
DESCRIBE_BY_DATA:该方法将数据作为输入,并返回数据类型描述对象的对象引用。DESCRIBE_BY_NAME:该方法将类型名称作为输入参数,并返回相应描述对象的对象引用。DESCRIBE_BY_OBJECT_REF:此方法将对象引用作为输入,并返回一个对象引用,指向引用所指向对象类型的描述对象。DESCRIBE_BY_DATA_REF:此方法将数据引用作为输入,并返回一个对象引用,指向引用所指向数据类型的描述对象。
可以通过不同的方式(如通过名称、数据、导航等)获取类型的描述对象引用。这一点很重要--RTTI 保证每种类型都有一个描述对象。所有引用都指向同一个描述对象,无论选择哪种路径进行检索。
RTTI 示例
REPORT typedescr_test.
TYPES my_type TYPE i.
DATA: my_data TYPE my_type,
descr_ref TYPE ref to cl_abap_typedescr.
START-OF-SELECTION.
descr_ref = cl_abap_typedescr=>describe_by_data( my_data ).
WRITE: / 'type name:', descr_ref->absolute_name.
WRITE: / 'kind :', descr_ref->type_kind.
WRITE: / 'length :', descr_ref->length.
WRITE: / 'Decimals:', descr_ref->decimals.
后续将专门用一篇文章进行介绍