ABAP学习笔记之——第四章:模块化程序

一、子程序:

语法:

参数:

参数(Parameter)是指调用子程序时用于传入、传出的值。子程序中的参数与一般用 DATA语句定义的局部变量相同。调用子程序时使用的参数叫实参(Actual Parameter),在子程序中使用的参数叫虚参(Formal Parameter)。PERFORM 利用 USING、CHAING 定义参数,且使用时要与子程序的顺序一致。参数可以使用 ABAP 的所有对象,即基本数据类型、Field Smbol、内表等。

传递参数的三种方法:

Call by value:

传入参数即实参(Actual Parameter)与传出参数即虚参(Formal Parameter)有不同的物理内存。

VALUE 语句中虚参(FormalParameter)占用自己的单独内存。调用子程序时,实参(ActualParameter)值复制到虚参中,即使改变虚参的值也不会影响实参值。

例:

*call by value   using参数用法
DATA: gv_val TYPE c LENGTH 20 VALUE 'call by value test'.
PERFORM call_byvalue USING gv_val.
FORM call_byvalue USING VALUE(p_val).
  WRITE p_val.
ENDFORM.

Call by reference:

共有相同的物理内存并且互相传递地址。

子程序的虚参没有自己的内存空间。只是在调用子程序期间占用实参的地址。即在调用Subroutine 的程序的内存地址(相同名字的变量)中进行工作。

例:

*call by reference  changing参数用法
DATA : gv_val TYPE c LENGTH 30 VALUE 'call by reference test'.
WRITE / gv_val.
PERFORM call_byvref CHANGING gv_val.
WRITE / gv_val.
FORM call_byvref CHANGING p_val.
  p_val = 'value is changed'.
ENDFORM.

Call by Value and Result:

传入传出变量语句执行成功时返回变更后的值。拥有不同的物理地址。

USING 语句与VALUE 语句一起搭配使用,则无法修改子程序中的实参值(Call by value),但是 CHANGING 语句与 VALUE 语句一起配套使用时,当正常结束子程序时会修改实参值练习做一个定义整数类型的3 个变量后,在FORM语句内执行加法的程序。

例:

*call by value and result   changing 和 using 混合使用
PARAMETER :val1 TYPE i,
      val2 TYPE i.
DATA gv_sum  TYPE i.
PERFORM sum_data USING val1 val2
      CHANGING gv_sum.
WRITE : / 'resukt is :',gv_sum.
FORM sum_data USING VALUE(p_val1) VALUE(p_val2)
      CHANGING VALUE(p_sum).
  p_sum = p_val1 + p_val2.
ENDFORM.

参数类型:

FORM语句内的虚参(Formal Parameter)可以利用TYPE 与 LIKE 语定义所有ABAP 数据类型。若不明确指定类型,则被定义成 Generic 类型,会继承实参(Actual Parameter)的技术属性。

若传递了d类型的参数,则虚参的定义方法有下列 3 种形式:

  1. 使用 Generic TypeFORM subr CHANGING p_val
  2. 使用与实参(Actual Parameter)相同的数据类型FORM subr CHANGING p val TYPE d.
  3. 使用与实参(Actual Parameter)有相同类型的变量FORM subr CHANGING p valLIKE gv_VAL.

参数与结构体:

虚参可以使用所有 ABAP 数据类型,结构体也不例外。当结构体作为参数使用时,不仅能使用 TYPELIKE 语句定义,还可以使用 STRUCTURE语句定义结构体类型。

例:

*参数与结构体
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:

当程序参数为内表是也可以使用using和changing

*参数与内表
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 = 2.
APPEND gs_str TO gt_itab.

gs_str-col1 = 'b'.
gs_str-col2 = 3.
APPEND gs_str TO gt_itab.

PERFORM test_itab USING gt_itab.
FORM test_itab USING pt_itab TYPE t_itab.
  READ TABLE pt_itab WITH KEY col1 = 'b' INTO gs_str.
  IF sy-subrc = 0.
    WRITE: gs_str-col1,gs_str-col2.
  ENDIF.
ENDFORM.
*-------------内表---------------
PERFORM test_itab TABLES gt_itab.
PERFORM write_data TABLES gt_itab.

FORM test_itab TABLES pt_itab TYPE t_itab.
  DATA ls_str TYPE t_str.

  ls_str-col1 = 'a'.
  ls_str-col2 = 1.
  APPEND ls_str TO pt_itab.

  ls_str-col1 = 'b'.
  ls_str-col2 = 2.
  APPEND ls_str TO pt_itab.

ENDFORM.

FORM write_data TABLES pt_itab LIKE gt_itab.
  DATA ls_str TYPE t_str.
  LOOP AT pt_itab INTO ls_str.
    WRITE : / ls_str-col1,ls_str-col2.
  ENDLOOP.
ENDFORM.

Tables:

在 Rel 3.0 版本以前使用过TABLES 语,可以替代USING 与 CHANGING 语。以前开发的程序中使用了 TABLES 语句,因此出于互换性问题现在也经常使用此语句。

调用子程序:

程序内部调用子程序

例:

*调用程序内部的子程序
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).
  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.

程序外部调用子程序

例:

*调用程序外部子程序
*外部程序z_subrouite_1与上面调用程序内部子程序的例子一样(别忘了先激活)
DATA: gv_first(10)  TYPE c VALUE 'external',
      gv_second(10) TYPE c VALUE 'call',
      gv_result(20) TYPE c.

PERFORM concate_string(z_subrouite_1) 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_subrouite_1',
      gv_subname(20) TYPE c VALUE 'concate_string'.

TRANSLATE gv_pname TO UPPER CASE.
TRANSLATE gv_subname TO UPPER CASE.  "记得转大写

PERFORM (gv_subname) IN PROGRAM (gv_pname) IF FOUND
USING gv_first gv_second
      CHANGING gv_result.

利用list调用子程序:

*利用list调用子程序
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.

Abap循环语句:

DO~ENDDO 循环语句

是可以指定循环次数的语句,若不指定次数,则会无限执行循环,当前循环次数保存在系统变量 SY-INDEX 中。

WHILE~ENDWHILE

循环语句当WHILE 语句的表达式结果为真时反复持续循环。当前循环次数保存在系统变量 SY-INDEX 中。

LOOP~ENDLOOP 

循环语句按顺序依次循环内表,将读取内表行数据保存到工作区或者表头的循环语句。当前循环次数保存在系统变量 SYINDEX 中。SY-TABX 表示内表的当前行数。

结束子程序:

子程序遇到 END FORM语句就正常结束。此外,还可以利用 EXIT、CHECK 语句强制在执行过程中结束此子程序。遇到 EXIT 语句会直接跳出子程序,遇到 CHECK 语句时,判其值结果为假时不执行后续操作会跳出子程序。

例:

*结束子程序
PARAMETERS: p_val TYPE char10.
PERFORM end_subr USING p_val.

TRANSLATE p_val TO LOWER CASE.

FORM end_subr USING VALUE(p_val).
  CASE p_val.
    WHEN 'exit'.
      WRITE 'subroutine exit'.
      EXIT.
    WHEN 'check'.
      WRITE 'value check'.
      CHECK p_val NE 'check'.
    WHEN OTHERS.
  ENDCASE.
  WRITE 'subroutine is normally ended'.
ENDFORM.

Abap条件语句:

IF~ENDIF 分歧语句

比较条件语句中的逻辑值,当值为真时执行里面语句并跳出此语句块

IF 条件语句.
    ...
    ELSEIF 条件语句.
    ...
    ELSE.
    ...
ENDIF.

CASE~ENDCASE 分歧语句

一个变量有多个值时,根据每个值执行不同操作时使用的语句。

临时子程序:

可以定义在主内存中执行的动态子程序

上面语句有在执行中程序的主内存里创建子程序池的功能。将子程序池的代码插入到内表<itab>中,创建 8 位类型为 C 的子程序名prog 。即当需要使用动态的子程序时利用子程序池(程序),动态定义内表时经常使用此语句。例如,假设做一本根据用户指定的期间查询该期间销售额的程序。此时用户每次指定的日期是不一样的,因此无法事先预测内表的字段个数。这时用 GENERATE 语句就可以根据日期数动态地定义内表,此外还有很多动态定义内表的方法,在此不一一列举。子程序池只存在于程序执行过程中,在一个程序中可以创建36个子程序池。发生错误时 SY-SUBRC 返回8。

例:

*临时子程序
DATA:gt_code(72) OCCURS 10,
     gv_prog(8),
     gv_msg(120).
APPEND 'PROGRAM SUBPOOL.' TO gt_code.
APPEND 'FORM dynamic_subr.' TO gt_code.
APPEND 'WRITE / ''dynamic subroutine is called''.' TO gt_code.  "这里需要注意单引号的拼接
APPEND 'ENDFORM.' TO gt_code.    "拼接子程序代码
WRITE sy-subrc.
GENERATE SUBROUTINE POOL gt_code NAME gv_prog
MESSAGE gv_msg.
WRITE / sy-subrc.
IF sy-subrc <> 0. "注:sy-subrc  0:成功  4:源代码错误(注意查看字符串拼接是否正确)  8:发生错误
  WRITE: / 'subroutine pool is failed.'.
ELSE.
  WRITE: / 'subroutine pool name:',gv_prog.
  SKIP 1.
  PERFORM dynamic_subr IN PROGRAM (gv_prog).
ENDIF.

Perform on commit:

Using PERFORM ON COMMIT:遇到 COMMIT WORK 时调用子程序。

Using PERFORM ON ROLLBACK: 遇到 ROLLBACK WORK 时调用子程序

例:

*perform on commit   用法
DATA:gs_scarr LIKE scarr,
     gv_flg   TYPE c.

SELECT SINGLE * INTO gs_scarr FROM scarr
  WHERE carrid = 'AA'.

PERFORM delete_data USING gs_scarr.
PERFORM insert_data ON COMMIT.

IF gv_flg = 'X'.
  COMMIT WORK.
ENDIF.

FORM delete_data USING VALUE(ps_scarr) TYPE scarr.
  DELETE scarr FROM ps_scarr.
  IF sy-subrc = 0.
    gv_flg = 'X'.
  ENDIF.
ENDFORM.

FORM insert_data.
  INSERT scarr FROM gs_scarr.
ENDFORM.

Macro:

局部:

在程序中重复使用的语句,最好定义成 Macro 后使用。当在程序中使用时,先以DEFINE~END-OF-DEFINITION 形式定义后用 Macro 名字和参数调用即可。如果 PERFORM语句只是逻辑中包含的重复利用模块,Macro 功能只是为了减少代码重复。

 例:

*局部 MACRO
DATA:gv_val1 TYPE c VALUE 'A',
     gv_val2 TYPE c VALUE 'B',
     gv_val3 TYPE char3.
DEFINE con.
  CONCATENATE &1 &2 INTO &3 SEPARATED BY space.
  dis &3.
END-OF-DEFINITION.
DEFINE dis.
  WRITE &1.
END-OF-DEFINITION.
con gv_val1 gv_val2 gv_val3.

全局:

全局 Macro 在数据库表 TRMAC 中进行维护。经常使用的全局 Macro 中包含指定断点时用的 BREAK 语句。从[图 4-3]中显示的数据库表 TRMAC 的数据中可以看出,在程序中输入 BREAK 会调用此Macro,从而可以实现设定断点的功能。

Function:

函数(Function Module) 是储存在中央库 (R/3 Repository)中的特殊全局子程序。在一个程序中多次使用相同功能的语句会增加代码量,另外有修改需求时要修改多处,因此效率低。此时使用函数将代码模块化就可以实现代码重复利用,从而减少代码量。

传入参数

 往函数里传入值的参数,是可选项。

传出参数

从函数往 ABAP 程序里传递值的参数,也是可选项。传入/传出参数可以往函数里传值并且改变其值再传出。

表(Tables)

可以往函数传入/传出内表。

例外处理

提供错误信息。

函数属性:

子程序和函数的区别:

函数包含在称为函数组的一个池中。

函数提供例外处理功能,因此当发生错误时调用设定例外处理的程序

函数与调用的程序无关可以单独在 Stand-alone 模式下进行测试。

函数组:

函数组 (Function Group)可以看成是集合多个函数的集装箱。函数组不能直接运行,调用函数时,系统负载所有函数组到正在执行的程序内部会话中。这是指在一个函数组内的函数可以互相共享所有数据,还可以共享创建的屏幕,子程序等。

函数组名字最多可以指定成 26 个字母。通过函数编辑器创建函数和函数组,则系统会自动生成主程序及共享程序(Include Program)。

RFC:

        为了充当源系统和 R/3 系统的数据接口,要把 R/3 的函数定义为 RFC 函数。导入 SAPERP 之前,很多企业一般都是分别用各个不同的语言如 C、JAVA、power build 等语言来构筑财务、人事、生产等系统的。当导入 SAP 后,这种源系统一般会被废弃,但也存在与其并行执行的系统。此时,难免会遇到将源系统的数据传递到 SAP 或者 SAP 数据要在源系统上进行查询的情况,这种工作就需要通过 SAP RFC 来完成。而有时只用 RFC 无法实现 SAP 与多种语言开发的源系统的连接。

        为了解决此类问题,通常会创建 METHODS 来充当交换设备SAP 系统担当者利用 RFC 函数来传出数据,然后 WEBMETHODS 接收此数据后传递到源系统。同样,也可以从源系统接收数据后传递到 SAP 系统。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值