专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > SAP

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

发布时间:2010-06-06 17:05:16 文章来源:www.iduyao.cn 采编人员:星星草
[SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址
这节也是ABAP学习的关键所在,Form、Function、Method的参数定义都差不多,弄懂一个,其他都好办。参数传递涉及传值、传址问题,这是其也语言也有的问题,要学好他,你得要仔细想想

1.10.         FormFunction. 13

1.10.1.     FORM.. 13

1.10.2.     FUNCTION.. 15

1.10.2.1.           Function Group结构... 15

1.10.2.2.           Function参数传值、传址... 18

1.10.     FormFunction

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

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

Form中通过引用传递时,USINGCHANGING完全一样;但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类型

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

值传递中的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.
 
"
由于USINGC++的引用参数,所以这里修改的直接是实参所存储的地址内容,这里的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>U01L<fgrp>U02...这些Include文件实际上包含了所对应的Function Module代码(即双击它们进去就是对应的Function,而显示的不是真正Include文件所对应的代码)

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

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 ModuleInclude文件等)加载到主调程序所在的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>.
"
同上面,REFERENCEIMPORTING类型的参数不能被修改:这里即不能修改实参的指向
"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

友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

  • :安装MINI SAP失败

    求救:安装MINI SAP失败! 如题。 怎么办啊? 安装之前已经把SQL2000 2005 VS.NET05 08全都卸载了的。 安装CD1的时候就开始报错...

  • 哪位高手有abap eclipse editor

    谁有abap eclipse editor? 那位哥们有,可以进行资料交换。 ------解决方案-------------------- 这个现在只支持460,好像不支持640...

  • ,关于t-code:sgen的有关问题!

    求助,关于t-code:sgen的问题!急~~~ 昨天刚把sap ecc6装好了 。为了能够快速运行,事先准备用sgen编译一下 非常郁闷的是,在还没有开始...

  • sql查询语句中WHERE条件后面AND的个数解决方案

    sql查询语句中WHERE条件后面AND的个数 sql查询语句中WHERE条件后面AND的个数有没有限制啊! ------解决方案-------------------- ...

  • SAP模块,学哪个模块未来发展比较顺利

    【求助】SAP模块,学哪个模块未来发展比较顺利? 各位大侠,我是SAP新人。最近公司在培训,3周培训后要我们从PS,FI,CO,MM等中选择一个模...

  • 站在十字路口,该怎么处理

    站在十字路口 本人在一个快消公司做IT程序员,主要负责内部系统开发、报表开发、数据库维护等工作。现在公司要上SAP了,我也有幸参与...

  • alv field 是否可以进行日期选择解决方法

    alv field 是否可以进行日期选择 哪位达人知道怎么在ALV报表中实现 日期的选择,就像调整系统日期一样,不用手动收入 ------解决方...

  • 在sap中怎样获取字段所属的表解决思路

    在sap中怎样获取字段所属的表 小弟是SAP初学者,在这里遇到一个问题,由于对sap内部表结构不是很了解,现在要根据一些字段获取所属的表...

  • ABAP list report 输出有关问题

    ABAP list report 输出问题 小弟初学ABAP,苦难重重,望大侠门指点。两个问题: 第一,我做了一个list report,输出deliveray item 和invoi...

  • 在SAP中如何截取字符串

    在SAP中怎么截取字符串 在SAP中怎么截取字符串 比如 DATA:STR(10) LIKE C VALUE '1234567890', STR1(4) LIKE C. 我要取...

热门推荐: