当结构包含字符串字段时,将结构转换为字符串失败

Casting of structure to string fails when structure contains a String field

我有一个动态内部 table <ft_dyn_tab>。我想通过字段符号 <lf_string>:

将内部 table 的每一行转换为类型 string
LOOP AT <ft_dyn_tab> ASSIGNING <fs_dyn_wa>.
  ASSIGN <fs_dyn_wa> to <lf_string> CASTING.
  ...
  "other logic
  ...
ENDLOOP.

通常,当结构的所有字段都是字符类型时,CASTING 工作正常。但是当一个字段的类型为 string 时,它会给出一个运行时错误。谁能解释为什么?以及如何解决这个问题?

我刚刚对此进行了测试,当结构没有任何字符串类型的字段时,它也会给出运行时错误。

我将 ASSIGN 更改为简单的 MOVE 到字符串变量 g_string,它在运行时失败。如果失败,则意味着这样的分配是不可能的,因此也不会进行转换。

REPORT ZZZ.

TYPES BEGIN OF t_test.
  TYPES: f1 TYPE c LENGTH 2,
  f2 TYPE n LENGTH 4,
  f3 TYPE string.
TYPEs END OF t_test.

TYPES BEGIN OF t_test2.
  TYPES: f1 TYPE c LENGTH 2,
  f2 TYPE n LENGTH 4,
  f3 TYPE c LENGTH 80.
TYPES END OF t_test2.

TYPES: tt_test TYPE STANDARD TABLE OF t_test WITH EMPTY KEY,
tt_test2 TYPE STANDARD TABLE OF t_test2 WITH EMPTY KEY.

DATA(gt_test) = VALUE tt_test( ( f1 = '01' f2 = '1234' f3 = `Test`) ).
DATA(gt_test2) = VALUE tt_test2( ( f1 = '01' f2 = '1234' f3 = 'Test') ).
DATA: g_string TYPE string.

FIELD-SYMBOLS: <g_any_table> TYPE ANY TABLE,
  <g_string> TYPE string.

ASSIGN gt_test2 TO <g_any_table>.
ASSERT <g_any_table> IS ASSIGNED.
LOOP AT <g_any_table> ASSIGNING FIELD-SYMBOL(<g_any_wa2>).
*  ASSIGN <g_any_wa2> TO <g_string> CASTING.
  g_string = <g_any_wa2>.
ENDLOOP.
UNASSIGN <g_any_table>.

ASSIGN gt_test TO <g_any_table>.
ASSERT <g_any_table> IS ASSIGNED.
LOOP AT <g_any_table> ASSIGNING FIELD-SYMBOL(<g_any_wa>).
*  ASSIGN <g_any_wa> TO <g_string> CASTING.
  g_string = <g_any_wa>.
ENDLOOP.

听起来您想将完整的结构化行分配给纯字符串字段符号。这是行不通的。您只能将结构化行的各个类型兼容组件分配给字符串字段符号。

否则,这种分配工作正常。对于具有字符串类型的单列的 table:

TYPES table_type TYPE STANDARD TABLE OF string WITH EMPTY KEY.
DATA(filled_table) = VALUE table_type( ( `Test` ) ).
ASSIGN filled_table TO FIELD-SYMBOL(<dynamic_table>).
FIELD-SYMBOLS <string> TYPE string.

LOOP AT <dynamic_table> ASSIGNING FIELD-SYMBOL(<row>).
  ASSIGN <row> TO FIELD-SYMBOL(<string>).
ENDLOOP.

对于具有结构化行类型的 table:

TYPES:
  BEGIN OF row_type,
    some_character_field TYPE char80,
    the_string_field     TYPE string,
  END OF row_type.
TYPES table_type TYPE STANDARD TABLE OF row_type WITH EMPTY KEY.
DATA(filled_table) = VALUE table_type( ( some_character_field = 'ABC'
                                         the_string_field     = `Test` ) ).
ASSIGN filled_table TO FIELD-SYMBOL(<dynamic_table>).
FIELD-SYMBOLS <string> TYPE string.

LOOP AT <dynamic_table> ASSIGNING FIELD-SYMBOL(<row>).
  ASSIGN <row>-the_string_field TO <string>.
ENDLOOP.

为什么只有字符类和 String 组件的结构不能 "casted" 作为文本变量

原因由Strings的ABAP文档给出:

"A structure that contains a string is a deep structure and cannot be used as a character-like field in the same way as a flat structure.".

Deep

"Deep: [...] the content [...] is addressed internally using references ([...], strings..."

Memory Requirement for Deep Data Objects的:

"The memory requirement for the reference is 8 byte. [...] In strings, [...] an implicit reference is created internally."

ASSIGN - casting_spec的:

"If the data type determined by CASTING is deep or if deep data objects are stored in the assigned memory area, the deep components must appear with exactly the same type and position in the assigned memory area. In particular, this means that individual reference variables can be assigned to only one field symbol that is typed as a reference variable by the same static type."

现在,编译器和 运行 时间不允许你这样做的原因是,如果你转换整个深层结构,你可以更改 8 字节引用以访问任何地方在记忆中,这可能是危险的 (How dangerous is it to access an array out of bounds?) and very difficult to analyze the subsequent bugs. In all programming languages, as far as possible, the compiler prevents out-of-bounds accesses or the checks are done at run time (Bounds checking)。

解决方法

您的问题发生在 运行 时间,因为您使用了动态创建的数据对象,但在编译时使用静态定义的数据对象会遇到完全相同的问题。下面是一个具有静态定义结构的简单解决方案。

您可以访问结构的每个字段并将其连接成一个字符串:

DATA: BEGIN OF dyn_wa,
         country TYPE c LENGTH 3,
         city    TYPE string,
       END OF dyn_wa,
       lf_string TYPE string.
FIELD-SYMBOLS: <lf_field> TYPE clike.

dyn_wa = VALUE #( country = 'FR' city = 'Paris' ).

DO.
  ASSIGN COMPONENT sy-index OF STRUCTURE dyn_wa TO <lf_field>.
  IF sy-subrc <> 0.
    EXIT.
  ENDIF.
  CONCATENATE lf_string <lf_field> INTO lf_string RESPECTING BLANKS.
ENDDO.

ASSERT lf_string = 'FR Paris'. " one space because country is 3 characters

RESPECTING BLANKS 保留尾随空格,以模仿 ASSIGN ... CASTING.