• [SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址


    这节也是ABAP学习的关键所在,Form、Function、Method的参数定义都差不多,弄懂一个,其他都好办。参数传递涉及传值、传址问题,这是其也语言也有的问题,要学好他,你得要仔细想想

    1.10.      Form Function

    Form Function 中的 TABLES 参数, TYPE LIKE 后面只能接 标准内表 类型或标准内表对象,如果要使用排序内表或者哈希内表,则只能使用 USING Form )与 CHANGING 方式来代替。当把一个带表头的实参通过 TABLES 参数传递时,表头也会传递过去,如果实参不带表头或者只传递了表体(使用了 [] 时),系统会自动为内表参数变量创建一个局部空的表头

    不管是以 TABLES 还是以 USING Form 非值 CHANGE 非值 方式传递时,都是以 引用方式 (即 别名 ,不是指地址,注意与 Java 中的传引用区别: Java 实为传值,但传递的值为地址的值,而 ABAP 中传递的是否为地址,则要看实参是否是通过 Type ref to 定义的)传递;但如果 USING 值传递 ,则 对形参数的修改不会改变实参 ,因为此时不是引用传递;但如果 CHANGE 值传递 ,对形参数的修改还是会改变实参,只是修改的时机在 Form 执行或 Function 执行完后,才去修改

    Form 中通过 引用传递时, USING CHANGING 完全一样 ;但 CHANGING 为值传递方式时,需要在 Form 执行完后,才去真正修改实参变量的内容,所以 CHANGING 传值与传引用其结果都是一样:结果都修改了实参内容,只是修改的时机不太一样而已

    1.10.1.            FORM

    FORM subr [ TABLES   t1 [{ TYPE itab_type}|{ LIKE itab}|{ STRUCTURE struc}]
    t2 […] ]  

    [ USING   { VALUE ( p1 ) |p1 } [ { TYPE generic_type }

    | { LIKE <generic_fs>|generic_para }
    | {
    TYPE {[ LINE OF ] complete_type}|{ REF   TO type} }

    | {
    LIKE {[ LINE OF ] dobj} | { REF   TO
    dobj} }
    |
    STRUCTURE struc]

    { VALUE ( p2 ) |p2 } […] ]  

    [ CHANGING { VALUE ( p1 ) |p1 } [ { TYPE generic_type }

    | { LIKE <generic_fs>|generic_para } 

    | { TYPE {[ LINE OF ] complete_type} | { REF   TO type} }  
    | {
    LIKE {[ LINE OF ] dobj} | { REF   TO
    dobj} }
    |
    STRUCTURE struc]

    { VALUE (p2)|p2 } […] ]  

    [ RAISING {exc1| RESUMABLE ( exc1 )} { exc2| RESUMABLE ( exc2 )} ... ] .

    generic _type :为通用类型

    complete_type :为完全限制类型

    <generic_fs> :为字段符号变量类型,如下面的 fs 形式参数

    generic_para :为另一个形式参数类型,如下面的 b 形式参数

    DATA : d ( 10 ) VALUE '11' .
    FIELD-SYMBOLS : <fs> LIKE d .
    ASSIGN d TO <fs> .
    PERFORM aa USING <fs> d d .
    FORM aa
    USING   fs   like <fs>  a   like b   like a .
     
    WRITE : fs , / a , / b .
    ENDFORM .

    如果没有给形式参数指定类,则为 ANY 类型

    如果 TABLES USING CHANGING 一起使用时,则 一定要 按照 TABLES USING CHANGING 顺序声明

    值传递中的 VALUE 关键字只是在 FORM 定义时出现,在调用时 PERFORM 语句中无需出现 ,也就是说,调用时值传递和引用传递不存在语法格式差别

     

    DATA : i   TYPE   i   VALUE   100 .
    WRITE : / 'frm_ref===='
    .
    PERFORM frm_ref USING   i
    .
    WRITE : / i . "200


    WRITE : / 'frm_val====' .
    i = 100
    .
    PERFORM frm_val USING   i
    .
    WRITE : / i . "100


    WRITE : / 'frm_ref2====' .

    " 不能将下面的变量定义到 frm_ref2 过程中,如果这样,下面的 dref 指针在调用 frm_ref2 后, 指向的是 Form 中局部变量内存,为不安全发布 ,运行会抛异常,因为 From 结束后,它所拥有的所有变量内存空间会释放掉
    DATA : i_frm_ref2 TYPE   i   VALUE   400 .
    i = 100
    .
    DATA : dref TYPE   REF   TO   i
    .
    get   REFERENCE   OF   i   INTO
    dref.
    PERFORM frm_ref2 USING dref . "
    传递的内容为地址,属于别名引用传递
    WRITE : / i . "4000

    field - SYMBOLS : <fs> TYPE   i .
    ASSIGN dref->* to <fs>. "
    由于 frm_ref2 过程中已修改了 dref 的指向,现指向了 i_frm_ref2 变量的内存空间
    WRITE : / <fs>. "400

    WRITE : / 'frm_val2====' .
    i = 100
    .
    DATA : dref2 TYPE   REF   TO   i
    .
    get   REFERENCE   OF   i   INTO
    dref2.
    PERFORM frm_val2 USING
    dref2 .
    WRITE : / i . "4000

    ASSIGN dref2->* to <fs>.
    WRITE : / <fs>. "4000


    FORM
      frm_ref   USING   p_i TYPE   i . " C++ 中的引用参数传递 p_i 为实参 i 的别名
     
    WRITE : /  p_i. "100
      p_i =
    200 . "p_i 为参数 i 的别名,所以可以直接修改实参
    ENDFORM .  

    FORM
      frm_val   USING    value (p_i). " 传值 p_i 为实参 i 的拷贝
     
    WRITE : /  p_i. "100
      p_i =
    300 . " 由于是传值,所以不会修改主调程序中的实参的值
    ENDFORM .
    FORM
      frm_ref2 USING p_i   TYPE   REF   TO   i . "p_i 为实参 dref 的别名, 类似 C++ 中的引用参数传递 (传递的内容为地址,并且属于别名引用传递)
     
    field - SYMBOLS : <fs> TYPE   i .
     
    "
    现在 <fs> 就是实参所指向的内存内容的别名,代表实参所指向的实际内容
     
    ASSIGN p_i->* to <fs>.
     
    WRITE : /  <fs>. "100

    <fs> =
    4000 . "
    直接修改实参所指向的实际内存


     
    DATA : dref TYPE   REF   TO   i .
     
    get   REFERENCE   OF i_frm_ref2 INTO
    dref.
     
    "
    由于 USING C++ 的引用参数 ,所以这里修改的直接是实参所存储的地址内容,这里的 p_i 为传进来的 dref 的别名,是同一个变量,所以实参的指向也发生了改变 ( 这与 Java 中传递引用是不一样的, Java 中传递引用时为地址的拷贝,即 Java 中永远也只有传值,但 C/C++/ABAP 中可以传递真正引用——别名)
      p_i = dref.
    " 此处会修改实参的指向  
    ENDFORM
    .

    FORM
      frm_val2 USING   VALUE (p_i)   TYPE   REF   TO   i . "p_i 为实参 dref2 的拷贝, 类似 Java 中的引用传递 (虽然传递的内容为地址,但传递的方式属于地址拷贝——值传递)
     
    field -SYMBOLS : <fs> TYPE   i .
     
    "
    现在 <fs> 就是实参所指向的内存内容的别名,代表实参所指向的实际内容
     
    ASSIGN p_i->* to <fs>.
     
    WRITE : /  <fs>. "100

    <fs> =
    4000 . "
    但这里还是可以直接修改实参所指向的实际内容


     
    DATA : dref TYPE   REF   TO   i .
     
    get   REFERENCE   OF i_frm_ref2 INTO
    dref.
     
    "
    这里与过程 frm_ref2 不一样,该过程 frm_val2 参数的传递方式与 java 中的引用传递是原理是一样的:传递的是地址拷贝,所以下面不会修改主调程序中实参 dref2 的指向,它所改变的只是拷贝过来的 Form 中局部形式参数的指向
      p_i = dref. 
    ENDFORM .

    1.10.2.            FUNCTION

    image024[4]

    1.10.2.1.        Function Group 结构

    当使用 Function Builder 创建函数组时,系统会自动创建 main program 与相应的 include 程序:

    image025[4]

    l   <fgrp> Function Group 的名称

    l   SAPL<fgrp> 为主程序名,它将 Function Group 里的所有 Include 文件包括进来,除了 INCLUDE 语句之外,没有其他语句了

    l   L<fgrp>TOP ,里面有 FUNCTION-POOL 语句,以及所有 Function Module 都可以使用的全局数据定义

    l   L<fgrp>UXX ,也只有 INCLUDE 语句,它所包括的 Include 文件为相应具体 Function Module 所对应 Include 文件名: L<fgrp>U01 L<fgrp>U02 ... 这些 Include 文件实际上包含了所对应的 Function Module 代码(即双击它们进去就是对应的 Function ,而显示的不是真正 Include 文件所对应的代码)

    l   L<fgrp>U01 L<fgrp>U02 中的 01 02 编号对应 L<fgrp>UXX 中的“ XX ”,代表其创建先后的序号,例如 L<fgrp>U01 L<fgrp>U02 是头两个被创建的函数,在函数组中创建出的函数代码就放在相应的 L<fgrp>UXX (这里的 XX 代表某个数字,而不是字面上的 XX Include 头文件中

    l   L<fgrg>FXX ,用来存一些 Form 子过程,并且可以 被所有 Function Modules 所使用(不是针对某个 Function Module 的,但一般在设计时会针对每个 Function Module 设计这样单独的 Include 文件,这是一个好习惯),并且在使用时不需要在 Function Module 中使用 INCLUDE 语句包含它们(因为这些文件在主程序 SAPL<fgrp> 里就已经被 Include 进来了)。另外, L<fgrg>FXX 中的 F 是指 Form 的意思,这是一种名称约束而已,在创建时我们可以随便指定,一般还有 IXX (表示些类 Include 文件包括的是一些 PAI 事件中调用的 Module ,有时干脆直接使用 L<fgrg>PAI 或者 L<fgrg> PAIXX ), OXX (表示些类 Include 文件包括的是一些 PBO 事件中调用的 Module ,有时干脆直接使用 L<fgrg>PBO 或者 L<fgrg> PBOXX )。注:如果 Form 只被某一函数单独使用,实质上还可直接将这些 Form 定义在 Function Module 里的 ENDFUNCTION 语句后面

     

    当你调用一个 function module 时,系统加将整个 function group (包括 Function Module Include 文件等)加载到主调程序所在的 internal session 中,然后该 Function Module 得到执行,该 Function Group 一直保留在内存中,直到 internal session 结束。 Function Group 中的所定义的 Include 文件中的变量是全局,被所有 Function Module 共享,所以 Function Group 好比 Java 中的类,而 Function Module 则好比类中的方法,所以 Function Group 中的 Include 文件中定义的东西是全局型的,能被所有 Function Module 所共享使用

    image026[4]

    image027[4]

    image028[4]

    image029[4]

    1.10.2.2.        Function 参数传值、传址

    image030[4]

    image031[4]

    image032[4]

    function fuc_ref .
    *" -------------------------------------------------------------------

    *"*"Local Interface:
    *"  IMPORTING
    *"     REFERENCE (I_I1) TYPE  I    REFERENCE 别名 为参数的默认传递类型
    *"     VALUE (I_I2) TYPE  I        定义时勾选了 Pass Value 选项才会是 VALUE 类型
    *"     REFERENCE(I_I3) TYPE   REF TO   I
    *"     VALUE(I_I4) TYPE REF TO  I
    *"  EXPORTING
    *"     REFERENCE(E_I1) TYPE  I
    *"     VALUE(E_I2) TYPE  I
    *"     REFERENCE(E_I3) TYPE REF TO  I
    *"     VALUE(E_I4) TYPE REF TO  I
    *"  TABLES
    *"      T_1 TYPE  ZJZJ_ITAB
    *"  CHANGING
    *"     REFERENCE(C_I1) TYPE  I
    *"     VALUE(C_I2) TYPE  I
    *"     REFERENCE(C_I3) TYPE REF TO  I
    *"     VALUE(C_I4) TYPE REF TO  I
    *"-------------------------------------------------------------------
    write : / i_i1. "1
    " 由于 i_i1 为输入类型参数 且又是引用类型 实参不能被修改 。这里 i_i1 是以 C++ 中的引用(别名)参数方式传递参数,所以如果修改了 i_i1 就会修改实际参数,所以函数中不能修改 REFERENCE IMPORTING 类型的参数,如果去掉下面注释则编译出错
    "i_i1 = 10.

    write : / i_i2. "2
    " 虽然 i_i2 是输入类型的参数,但不是引用类型,所以可以修改 ,编译能通过但不会修改外面实参的值,只是修改了该函数局部变量的值
    i_i2 = 20 .

    field - symbols : <fs> type   i
    .
    assign i_i3->* to
    <fs>.
    "
    由于 i_i3 存储的是地址,所以先要解引用再能使用
    write : / <fs>.
    "
    同上面, REFERENCE IMPORTING 类型的参数不能被修改:这里即不能修改实参的指向
    "GET REFERENCE OF 30 INTO i_i3." 虽然不可以修改实参的指向,但可以修改实参所指向的实际内容
    <fs> =
    30 .

    assign i_i4->* to
    <fs>.
    "i_i4
    存储也的是地址,所以先要解引用再能使用
    write : / <fs>.
    "
    虽然 i_i4 是输入类型的参数,但不是引用类型,所以可以修改,只会修改函数中的局部参数 i_i4 的指向,但并不会修改实参的指向
    get   reference   of   40   into
    i_i4.
    "
    虽然不能修改实参的指向,但可以直接修改实参的所指向的实际内容
    <fs> =
    400 .

    WRITE : / c_i1. "111

    "c_i1 为实参的别名,修改形参就等于修改实参内容
    c_i1 =
    1110 .

    WRITE : / c_i2. "222

    "c_i2 为实参的副本,所以不会影响实参的内容,但是, 由于是 CHANGING 类型的参数 , 且为值传递 ,在函数正常执行完后,还是会将该副本再次拷贝给实参,所以最终实参还是会被修改
    c_i2 =
    2220
    .
    ENDFUNCTION
    .

     

    调用程序:

    DATA : i_i1 TYPE   i   VALUE   1 ,
          i_i2
    TYPE   i   VALUE   2
    ,
          i_i3
    TYPE   REF   TO   i
    ,
          i_i4
    TYPE   REF   TO   i
    ,
          c_i1
    TYPE   i   VALUE   111
    ,
          c_i2
    TYPE   i   VALUE   222
    ,
          c_i3
    TYPE   REF   TO   i
    ,
          c_i4
    TYPE   REF   TO   i
    ,
          t_1
    TYPE zjzj_itab WITH   HEADER   LINE
    .

    DATA : i_i3_ TYPE   i   VALUE   3
    .
    GET   REFERENCE   OF i_i3_ INTO
    i_i3.
    DATA : i_i4_ TYPE   i   VALUE   4
    .
    GET   REFERENCE   OF i_i4_ INTO
    i_i4.
    DATA : c_i3_ TYPE   i   VALUE   333
    .
    GET   REFERENCE   OF c_i3_ INTO
    c_i3.
    DATA : c_i4_ TYPE   i   VALUE   444
    .
    GET   REFERENCE   OF c_i4_ INTO
    c_i4.

    CALL   FUNCTION   'FUC_REF'

     
    EXPORTING
        i_i1 = i_i1
        i_i2 = i_i2
        i_i3 = i_i3
        i_i4 = i_i4
     
    TABLES
        t_1 = t_1
     
    CHANGING
        c_i1 = c_i1
        c_i2 = c_i2
        c_i3 = c_i3
        c_i4 = c_i4.
    WRITE : / i_i2. "2
    WRITE : / i_i3_. "30
    WRITE : / i_i4_. "400
    WRITE : / c_i1. "1110
    WRITE : / c_i2. "2220

  • 相关阅读:
    javascript高级编程笔记第五章
    关于form表单:hover没有修改表单子元素样式
    JavaScript 生成 对应的protobuf 对象
    ProtoBuf Maven 整合 用来生成对象
    NettyClient 连接 WebSocket
    Exception in thread "Thread-5" java.lang.NoSuchMethodError: io.netty.util.concurrent.SingleThreadEventExecutor异常处理
    Jsonp 使用 爬取 可直接解析页面
    OpenResty 配置SSL 同时支持http 全部转发到 https中
    Nginx(OpenResty)+Lua+Redis IP限流 10s内
    NginxUrl校验路径token+时间戳
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4263707.html
Copyright © 2020-2023  润新知