设为首页 收藏本站
查看: 1463|回复: 0

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

[复制链接]

尚未签到

发表于 2015-9-19 07:54:37 | 显示全部楼层 |阅读模式
DSC0000.gif
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4263707.html
这节也是ABAP学习的关键所在,Form、Function、Method的参数定义都差不多,弄懂一个,其他都好办。参数传递涉及传值、传址问题,这是其也语言也有的问题,要学好他,你得要仔细想想
1.10.        Form、Function.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.    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中通过引用传递时,USINGCHANGING完全一样;但CHANGING为值传递方式时,需要在Form执行完后,才去真正修改实参变量的内容,所以CHANGING传值与传引用其结果都是一样:结果都修改了实参内容,只是修改的时机不太一样而已
1.10.1.          FORM
FORMsubr[TABLES t1 [{TYPEitab_type}|{LIKEitab}|{STRUCTUREstruc}]
t2 […]]
[USING {VALUE(p1)|p1 } [ {TYPEgeneric_type}
| {LIKE<generic_fs>|generic_para }
|{TYPE{[LINE OF] complete_type}|{REF TOtype} }
| {LIKE{[LINE OF] dobj} | {REF TOdobj} }
|STRUCTUREstruc]
{VALUE(p2)|p2 } […]]
[CHANGING{VALUE(p1)|p1 } [ {TYPEgeneric_type}
| {LIKE<generic_fs>|generic_para }
| {TYPE{[LINE OF] complete_type} | {REF TOtype} }
| {LIKE{[LINE OF] dobj} | {REF TOdobj} }
|STRUCTUREstruc]
{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>LIKEd.
ASSIGNdTO<fs>.
PERFORMaaUSING<fs> d d.
FORMaaUSING fs like<fs> a liked b likea.
WRITE:fs,/ a,/ b.
ENDFORM.
如果没有给形式参数指定类,则为ANY类型
如果TABLES与USING、CHANGING一起使用时,则一定要按照TABLES、USING、CHANGING顺序声明
值传递中的VALUE关键字只是在FORM定义时出现,在调用时PERFORM语句中无需出现,也就是说,调用时值传递和引用传递不存在语法格式差别

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

WRITE: /'frm_val===='.
i=100.
PERFORMfrm_valUSING i.
WRITE: /i."100

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


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

WRITE: /'frm_val2===='.
i=100.
DATA: dref2TYPE REF TO i.
get REFERENCE OF i INTOdref2.
PERFORMfrm_val2USINGdref2 .
WRITE: /i."4000
ASSIGNdref2->*to<fs>.
WRITE: / <fs>."4000

FORM frm_ref USING  p_iTYPE 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_ref2USINGp_i TYPE REF TO i."p_i为实参dref的别名,类似C++中的引用参数传递(传递的内容为地址,并且属于别名引用传递)
field-SYMBOLS: <fs>TYPE i.
"现在<fs>就是实参所指向的内存内容的别名,代表实参所指向的实际内容
ASSIGNp_i->*to<fs>.
WRITE: /  <fs>."100
<fs> =4000."直接修改实参所指向的实际内存

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

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

DATA: drefTYPE REF TO i.
get REFERENCE OFi_frm_ref2INTOdref.
"这里与过程frm_ref2不一样,该过程frm_val2参数的传递方式与java中的引用传递是原理是一样的:传递的是地址拷贝,所以下面不会修改主调程序中实参dref2的指向,它所改变的只是拷贝过来的Form中局部形式参数的指向
  p_i = dref.
ENDFORM.
1.10.2.          FUNCTION
DSC0001.png
1.10.2.1.      Function Group结构
当使用Function Builder创建函数组时,系统会自动创建main program与相应的include程序:
DSC0002.png
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>U01L<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所共享使用
DSC0003.png
DSC0004.png
DSC0005.png
DSC0006.png
1.10.2.2.      Function参数传值、传址
DSC0007.png
DSC0008.png
DSC0009.png
functionfuc_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 REFTO  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.
assigni_i3->*to<fs>.
"由于i_i3存储的是地址,所以先要解引用再能使用
write: / <fs>.
"同上面,REFERENCEIMPORTING类型的参数不能被修改:这里即不能修改实参的指向"GET REFERENCE OF 30 INTO i_i3."虽然不可以修改实参的指向,但可以修改实参所指向的实际内容
<fs> =30.

assigni_i4->*to<fs>.
"i_i4存储也的是地址,所以先要解引用再能使用
write: / <fs>.
"虽然i_i4是输入类型的参数,但不是引用类型,所以可以修改,只会修改函数中的局部参数i_i4的指向,但并不会修改实参的指向
get reference of 40 intoi_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_i1TYPE i VALUE 1,
      i_i2TYPE i VALUE 2,
      i_i3TYPE REF TO i,
      i_i4TYPE REF TO i,
      c_i1TYPE i VALUE 111,
      c_i2TYPE i VALUE 222,
      c_i3TYPE REF TO i,
      c_i4TYPE REF TO i,
      t_1TYPEzjzj_itabWITH HEADER LINE.

DATA: i_i3_TYPE i VALUE 3.
GET REFERENCE OFi_i3_INTOi_i3.
DATA: i_i4_TYPE i VALUE 4.
GET REFERENCE OFi_i4_INTOi_i4.
DATA: c_i3_TYPE i VALUE 333.
GET REFERENCE OFc_i3_INTOc_i3.
DATA: c_i4_TYPE i VALUE 444.
GET REFERENCE OFc_i4_INTOc_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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-115582-1-1.html 上篇帖子: SAP*和DDIC用户被锁分析与解决方案 下篇帖子: SAP 导入XLS
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表