ABAP中的一个持续烦恼是,无法将从未设置的变量与设置为其数据类型的初始值的变量区分开,并且无法通过itab[...]
表达式访问内部表CX_SY_ITAB_LINE_NOT_FOUND
,这在处理运行时方面非常昂贵。
对于枚举类型,可以将第一个变体定义为invalid
,以防止出现第一个混乱:
TYPES:
BEGIN OF ENUM my_bool,
invalid,
true,
false,
END OF ENUM my_bool.
(不要不实际使用此类型作为ABAP_BOOL
的替代。谓词方法调用的行为方式,方法meth
返回my_bool
会导致obj->meth( )
内的IF obj->meth( ).
仅在返回invalid
时为真,因为谓词方法调用等效于IF obj->meth( ) IS NOT INITIAL.
)
对于非枚举类型,我们很不走运。试图实现类似option type之类的方法以从尝试访问某些数据而失败的方法中返回的方法被泛型的弱类型阻止了:
CLASS zcl_option DEFINITION
FINAL.
PUBLIC SECTION.
CLASS-METHODS some
IMPORTING VALUE(val) TYPE any
RETURNING VALUE(option) TYPE REF TO zcl_option.
CLASS-METHODS none
RETURNING VALUE(option) TYPE REF TO zcl_option.
METHODS is_some
RETURNING VALUE(is_some) TYPE abap_bool.
METHODS get
RETURNING VALUE(val) TYPE ???.
ENDCLASS.
尝试在返回值get
中使用泛型类型失败,并显示“必须完全键入返回参数”。
有没有办法构造ABAP中的选项类型,甚至更一般的sum types?
答案 0 :(得分:1)
这是我想出的。当它开始看起来不是 100 %无用的时候,我就要把它扔掉,所以它就变成了:D:D
PROGRAM ztest_options_tongue_in_cheek.
*&---------------------------------------------------------------------*
TYPES:
BEGIN OF ENUM t_options,
some,
none,
END OF ENUM t_options.
DEFINE macro_option_type.
CLASS zcl_option_&1 DEFINITION FINAL.
PUBLIC SECTION.
METHODS:
constructor
IMPORTING VALUE(i_val) TYPE &1
VALUE(i_option) TYPE t_options,
is_some
RETURNING VALUE(e_is_some) TYPE abap_bool,
get
RETURNING VALUE(e_val) TYPE &1.
PRIVATE SECTION.
DATA:
lv_the_value TYPE &1,
lv_is_none TYPE abap_bool.
ENDCLASS.
CLASS zcl_option_&1 IMPLEMENTATION.
METHOD constructor.
lv_the_value = i_val.
lv_is_none = COND #( WHEN i_option = none THEN abap_true ELSE abap_false ).
ENDMETHOD.
METHOD is_some.
e_is_some = COND #( WHEN lv_is_none = abap_false THEN abap_true ELSE abap_false ).
ENDMETHOD.
METHOD get.
e_val = lv_the_value.
ENDMETHOD.
ENDCLASS.
END-OF-DEFINITION.
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
* Static declaration of required option types
macro_option_type:
i, string, char256, float, uzeit, datum.
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
DEFINE option.
* Rely on garbage collector for simplicity
&2 = NEW zcl_option_&1( i_val = CONV &1( &3 ) i_option = &4 ).
END-OF-DEFINITION.
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
DEFINE declare_init_option.
DATA &2 TYPE REF TO zcl_option_&1.
option &1 &2 space none.
END-OF-DEFINITION.
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
START-OF-SELECTION.
*&---------------------------------------------------------------------*
PERFORM test_options.
*&---------------------------------------------------------------------*
*& Form TEST_OPTIONS
*&---------------------------------------------------------------------*
FORM test_options .
declare_init_option:
i lo_integer_option,
string lo_string_option,
float lo_float_option,
uzeit lo_time_option.
option i lo_integer_option 123 some.
option string lo_string_option 'I am now a string' some.
option string lo_string_option `` none. "back to none
* e.g.,
IF lo_integer_option->is_some( ) = abap_true.
WRITE: / |lo_integer_option is { lo_integer_option->get( ) }|.
ELSE.
WRITE: / 'lo_integer_option is nothing'.
ENDIF.
ENDFORM.
答案 1 :(得分:0)
是的,有可能。但是,它不像类型安全那样方便,因此不像支持通用类型化的编程语言那样方便。
CLASS zcl_optional DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS constructor
IMPORTING
value TYPE simple OPTIONAL.
METHODS is_available
RETURNING
VALUE(result) TYPE abap_bool.
METHODS put_into
IMPORTING
reference TYPE REF TO data.
PRIVATE SECTION.
DATA value TYPE REF TO data.
ENDCLASS.
CLASS zcl_optional IMPLEMENTATION.
METHOD constructor.
IF value IS SUPPLIED.
DATA(type_descriptor) =
CAST cl_abap_datadescr( cl_abap_datadescr=>describe_by_data( value ) ).
CREATE DATA me->value TYPE HANDLE type_descriptor.
ASSIGN me->value->* TO FIELD-SYMBOL(<target>).
<target> = value.
ENDIF.
ENDMETHOD.
METHOD is_available.
result = xsdbool( me->value IS BOUND ).
ENDMETHOD.
METHOD put_into.
IF value IS BOUND.
ASSIGN value->* TO FIELD-SYMBOL(<source>).
ASSIGN reference->* TO FIELD-SYMBOL(<target>).
<target> = <source>.
ENDIF.
ENDMETHOD.
ENDCLASS.
使用方式
DATA(optional_integer) = NEW zcl_optional( 42 ).
cl_abap_unit_assert=>assert_true( optional_integer->is_available( ) ).
DATA integer_variable TYPE i.
optional_integer->put_into( REF #( integer_variable ) ).
cl_abap_unit_assert=>assert_equals( act = integer_variable exp = 42 ).
DATA(optional_string) = NEW zcl_optional( `abc` ).
cl_abap_unit_assert=>assert_true( optional_string->is_available( ) ).
DATA string_variable TYPE string.
optional_string->put_into( REF #( string_variable ) ).
cl_abap_unit_assert=>assert_equals( act = string_variable exp = `abc` ).
DATA(empty_optional) = NEW zcl_optional( ).
cl_abap_unit_assert=>assert_false( empty_optional->is_available( ) ).
DATA another_variable TYPE string.
empty_optional->put_into( REF #( another_variable ) ).
cl_abap_unit_assert=>assert_initial( another_variable ).
问题在于返回可选参数的方法无法描述内容的实际类型。
METHODS do_something
RETURNS
VALUE(result) TYPE REF TO zcl_optional. " int4 or string?
答案 2 :(得分:0)
The initial value是总是没有行的空表。因此,您的整个想法毫无意义。
设置初始值不会阻止您获得CX_SY_ITAB_LINE_NOT_FOUND
异常。