zoukankan      html  css  js  c++  java
  • ABAP基础4:模块化

    子程序定义

    以form开始,以endform结束,用perform语句调用,from语句可以在程序内部/外部,perform一定要写在前面

    perform.
    from.
     子程序模块
    endform.
    perform writedata. "如果写到子程序模块后,这一行会提示 Statement is not accessible  问题:ABAP是编译型语言还是解释性语言
    form writedata.
      write 'asdfasdf'.
    endform.                    "writedata

    或者双击子程序名称,创建子程序

    1.在新文件中写子程序,在调用文件中写入包含语句

    INCLUDE Z_YZW_STRUC_WRITEDATAF01.

    2.如果是在原文件写子程序就写在perfrom语句下面

    子程序参数

    • 调用子程序时用于传入/传出的值.参数一般用data语句定义的局部变量相同.
    • 调用子程序使用的参数是实参, 子程序中的参数叫形参
    • perform利用using/changing定义参数,位置参数,顺序要保持一致
    FROM subr USING p1 TYPE type
                                           VALUE(p2) TYPE type
                                            ...
            CHANGING    p3 TYPE type
                                        VALUE(p4) TYPE type

    传参

    使用using和changing语句传参, 3种方法

    • Call by Value, 传入参数即实参与传出参数即形参有不同的物理内存, 使用using关键字传递参数时与value语句一起搭配使用
    FROM sub USING ... VALUE(pi) [TYPE <T>| LIKE <F>].

    VALUE子句形参占用自己的单独内存, 调用子程序是,实参值复制到形参中,即使改变形参的值也不户影响实参值

    data: gv_val type c length 20 value 'I am value'. "引号内为实参
    
    perform call_byvalue using gv_val. "执行子程序,带参数gv_val
    form call_byvalue using value(p_val). "p_val是形参,是局部变量
      write p_val. "打印形参,就是打印实参内容
    endform.
    • Call by reference, 具有相同的物理内存并且互相传递内存地址, 使用changing关键字传参, 改变子程序参数值;调用时,子程序形参内存地址空间指向实参内存地址空间
    FROM subr USING ... pi [TYPE <T> |LIKE <F>] ...
    FROM subr CHANGGING ...pi [TYPE <T> |LIKE <F>] ...
    data: gv_val type c length 30 value '我是实参'.
    write / gv_val. "1打印局部变量
    perform call_byvref changing gv_val. "3执行子程序,在子程序中修改了局部变量的值  这里比上面少了value关键字,如果不适用value关键字,using和changing语句都属于cal by reference
    write / gv_val. "4打印被修改后的局部变量
    form call_byvref changing p_val.  "2子程序
     p_val = 'value is changed'.
    endform.

    总结:

    1. 在from语句中不适用value语句, using与changing
    2. 出于可读性考虑,using代表传递数据,changging代表传递数据后变更值
    3. 因此使用using时最好加上value语句搭配使用,一眼看出是传递数据
    • Call by Value and Result, 传入传出变量语句执行成功时返回变更后的值.具有不同的物理内存地址
    FORM subr CHANGING .. VALUE(PI) [TYPE<T>| LIKE <F>].

    using..value无法更改子程序实参值,changing...value在子程序结束时会更改实参值

    data:
    gv_val1 type i value 2,
    gv_val2 type i value 3,
    gv_sum type i.
    
    perform sum_data using gv_val1 gv_val2 changing gv_sum." using ..changing,下面的子程序结束后,实参gv_sum被更改为p_sum的值
    write: / 'result is:', gv_sum.
    
    form sum_data using value(p_val1) value(p_val2) changing value(p_sum). "using .. changeing value 只传值,不能更改实参值
    p_sum = p_val1 + p_val2. "三个形参,接收实参值
    endform.
    
    最后输出5

    定义参数类型

    form的形参可以利用type和like语句定义所有的ABAP数据类型,不指定的话默认是Generic类型,集成实参的技术属性

    data gv_val type c.
    perform call_byvref changing gv_val. "这里传递实参类是c
    form call_byvref changing p_val type i. "指定形参数据类型为i, 两种数据类型不能直接转换
      p_val = 'xxxx'.
    endform.

    data gv_val type d.
    perform subr changing gv_val. 
    *形参类型定义方法有3种
    *1.直接不指定形参类型,使用默认Generic
    *perform subr changing pv_val. 
    *2.使用相同数据类型
    *perform subr changing pv_val type d. 
    *3.使用相同类型的变量
    *perform subr changing pv_val like gv_val.

    参数与结构体

    结构体与形参一样可以使用所有的ABAP数据类型

    当结构体作为参数时,可以使用type/like定义,还可以使用structrue语句定义结构体类型

    FORM subr USING p_str STRUCTURE str ...
    FORM subr USING p_str TYPE str ...
    FORM subr USING p_str LIKE str ...
    data: begin of gs_str,
    col1 value 'A',
    col2 value 'B',
    end of gs_str.
    perform write_data using gs_str.
    
    form write_data using ps_str structure gs_str.  "形参使用结构体数据类型
     write: ps_str-col1, ps_str-col2.
    endform.

    参数与内表

    子程序参数为内表时也可以使用关键字USING/CHANGING

    FROM subr CHANGING ... <itab> [TYPE<t> | LIKE <f>]
    types: begin of t_str,
    col1 type c,
    col2 type i,
    end of t_str. "定义结构体
    
    types: t_itab type table of t_str."定义内表形式
    
    data: gs_str type t_str,"根据结构体分别定义变量和内表,内表具有两列
    gt_itab type t_itab.
    
    gs_str-col1 = 'A'.
    gs_str-col2 = 1.
    append gs_str to gt_itab.
    
    gs_str-col1 = 'B'.
    gs_str-col2 = 2.
    append gs_str to gt_itab.
    
    perform test_itab using gt_itab. "gt_itab是实参,内表类型
    form test_itab using pt_itab type t_itab."形参指定数据类型为内表
      read table pt_itab with key col1 = 'A' into gs_str. "read table tabname with key condition into 变量,从表中读取符合条件的数据保存到变量
      if sy-subrc = 0 .
        write : gs_str-col1, gs_str-col2.
      endif.
    endform.
    types: begin of t_str,
    col1 type c,
    col2 type i,
    end of t_str. "定义结构体
    
    types: t_itab type table of t_str."定义内表形式
    
    data: gs_str type t_str,"根据结构体分别定义变量和内表,内表具有两列
    gt_itab type t_itab.
    
    gs_str-col1 = 'A'.
    gs_str-col2 = 1.
    append gs_str to gt_itab.
    
    data: gv_name type char10.
    gv_name = 'COL1'. "
    
    gs_str-col1 = 'B'.
    gs_str-col2 = 2.
    append gs_str to gt_itab.
    
    perform test_itab using gt_itab. "gt_itab是实参,内表类型
    form test_itab using pt_itab type any table."形参指定为任意表类型, 下面的read要用动态条件,即传值进去,不然动态表找不到列名
      read table pt_itab with key (gv_name) = 'A' into gs_str. "read table tabname with key condition into 变量,从表中读取符合条件的数据保存到变量
      if sy-subrc = 0 .
        write : gs_str-col1, gs_str-col2.
      endif.
    endform.

    使用内表指定参数也有三种方法:

    • 使用Generic type
    FROM subr CHANGING pt_itab TYPE TABLE.
    FROM subr CHANGING pt_itab TYPE ANY TABLE.
    FROM subr CHANGING pt_itab TYPE INDEX TABLE.
    FROM subr CHANGING pt_itab TYPE STANDARD TABLE.
    FROM subr CHANGING pt_itab TYPE SORTED TABLE.
    FROM subr CHANGING pt_itab TYPE HASHED TABLE.
    • 使用与实参相同的内表类型
    FROM subr CHANGING pv_val TYPE i_tab.
    • 使用与实参具有相同类型的内表
    FROM subr CHANGING pv_val LIKE gt_itab.

    TABLES语句

    Rel3.0以前使用tables,可以替代USING与CHANGING语句

    调用子程序

    • 调用子程序的方法有Inetrnal/External,外部调用的子程序名后面要明确指定盖子程序所属程序名
    • 通过perform可以调用ABAP程序内部子程序,也可以调用其他程序的子程序

    调用语法

    PERFORM sub.
    PERFORM subr(prog) [IF FOUND]. 括号内是外部程序名
    • 调用内部子程序
    data:
    gv_val1(10) type c value 'Enjoy',
    gv_val2(10) type c value 'ABAP',
    gv_val3(20) type c.
    perform concate_string using gv_val1 gv_val2 changing gv_val3.
    *form concate_string using value(p_val1) value(p_val2) changing value(p_val3).
    form concate_string using p_val1 p_val2 changing p_val3.
      concatenate p_val1 p_val2 into p_val3 separated by space.
      perform write_data using p_val3. "嵌套一个子程序,直接输出不行?
    endform.
    form write_data using value(p_val).
      write: / p_val.
    endform.
    • 调用外部子程序
    data:
    gv_first(10) type c value 'External',
    gv_second(10) type c value 'call',
    gv_result(20) type c.
    perform concate_string(z_yzw_struc) if found
      using gv_first gv_second
    changing gv_result.
    • 动态调用子程序,就是将程序名和子程序名当做实参传进去
    data:
    gv_first(10) type c value 'External',
    gv_second(10) type c value 'call',
    gv_result(20) type c.
    data:
    gv_pname(20) type c value 'Z_YZW_STRUC',"要用大写,不然系统识别不到
    gv_subname(20) type c value 'CONCATE_STRING'."要用大写,不然系统识别不到
    perform (gv_subname) in program (gv_pname) if found
      using gv_first gv_second
    changing gv_result.

    利用list调用子程序

    PERFORM idx OF subr1 subr2 .. subrn

    根据顺序索引调用列出的子程序,只能调用内部子程序,且不能指定参数

    do 2 times.
      perform sy-index of subr1 subr2.
    enddo.
    
    form subr1.
      write / '1 subroutine is called'.
    endform.
    form subr2.
      write / '2 subroutine is called'.
    endform.

     循环

    do ~ while

    • 可以指定循环次数的语句,不指定次数,进入死循环
    • 循环次数保存在系统变量sy-index
    do 3 times.
    ...
    enddo.

    while ~ endwhile

    • 当while语句的表达式结果为真,进入循环
    • 循环次数保存在系统变量sy-index
    while gv_flag = 'X'.
    ~~
    endwhile.

    loop ~ endloop

    • 按顺序依次循环内表,将读取内表行数据保存到工作区或者表头的循环语句.
    • 循环次数保存在系统变量sy-index, sy-tabix表示内表的当前行数
    loop at gt_itab to gs_wa.
    ~~~
    endloop.

    结束子程序

    • endform, 正常结束
    • exit, 直接跳出子程序
    • check, 结果为假跳出子程序
    parameters: p_val type char10.
    perform end_subr using p_val.
    form end_subr using value(p_val).
      case p_val.
        when 'EXIT'.  "屏幕输入后系统会转换成大写
          write 'subroutine exit'.
          exit.
        when 'CHECK'.
          write 'value check'.
        when others.
      endcase.
      write 'subroutine is normally ended'.
    endform.                    "end_subr

    判断语句

    if condition.
    ~~~
    elseif codition.
    ~~~
    else.
    ~~~
    endif.
    case variable
    when value1.
    ~~~
    when value2.
    ~~~
    when OTHERS.
    ~~~
    endcase.

    临时子程序

    创建一个程序池,存储子程序

    GENERATE Subroutin POOL <itab> NAME <PROG>.

    PERFORM ON COMMIT

    • using perform on cmmit, 遇到commit work时调用子程序
    select single * from scarr into gs_scarr where carrid ='AA'.  "gs_scarr存储1条数据
    
    perform delete_data using gs_scarr.  "子程序正常执行
    perform insert_data on commit. "子程序定义时带有选项on commit,遇到commit work才执行
    
    if gv_flg = 'X'.
     commit work.  "第二个子程序再这里开始执行
    endif.
    
    form delete_data using value(ps_scarr) type scarr.
    delete scarr from ps_scarr. "从表scarr中删除符合条件的条目
    if sy-subrc = 0.
     gv_flg = 'X'.
    endif.
    endform.
    
    form insert_data.
     insert scarr
     from gs_scarr.
    endform.
    • using perform on rollback, 遇到rollback work时调用子程序

    局部Macro

    减少代码重复,定义如下,但是不能在其他程序中调用

    DEFINE macro.
    ~~~
    END-OF-DEFINITION.
    data:
    gv_val1 type c value 'A',
    gv_val2 type c value 'B',
    gv_val3 type char3.
    
    define conn.
     concatenate &1 &2 into &3 separated by space.
     dis &3.  "这里在调用一个define,作为实参传递过去
    end-of-definition.
    
    define dis.
     write / &1. "打印传进来的内容
    end-of-definition.
    
    conn gv_val1 gv_val2 gv_val3.

    全局MACRO

    可以在其他程序中调用,全局MACRO维护在表TRMAC中,可以指定断点时用BREAK语句

  • 相关阅读:
    golang 数据结构 优先队列(堆)
    leetcode刷题笔记5210题 球会落何处
    leetcode刷题笔记5638题 吃苹果的最大数目
    leetcode刷题笔记5637题 判断字符串的两半是否相似
    剑指 Offer 28. 对称的二叉树
    剑指 Offer 27. 二叉树的镜像
    剑指 Offer 26. 树的子结构
    剑指 Offer 25. 合并两个排序的链表
    剑指 Offer 24. 反转链表
    剑指 Offer 22. 链表中倒数第k个节点
  • 原文地址:https://www.cnblogs.com/jenvid/p/8303805.html
Copyright © 2011-2022 走看看