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

这节也是ABAP学习的关键所在,Form、Function、Method的参数定义都差不多,弄懂一个,其他都好办。参数传递涉及传值、传址问题,这是其也语言也有的问题,要学好他,你得要仔细想想
1.10.
Form
、
Function
、
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
d
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
1.10.2.1.
Function Group
结构
当使用
Function Builder
创建函数组时,系统会自动创建
main program
与相应的
include
程序:
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
文件等)加载到主调程序所在的
中,然后该
得到执行,该
Function Group
一直保留在内存中,直到
internal session
结束。
中的所定义的
Include
文件中的变量是全局,被所有
Function Module
共享,所以
好比
Java
中的类,而
Function Module
则好比类中的方法,所以
Function Group
中的
Include
文件中定义的东西是全局型的,能被所有
Function Module
所共享使用
1.10.2.2.
Function
参数传值、传址
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
[SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址的更多相关文章
- [SAP ABAP开发技术总结]面向对象OO
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- ABAP开发顾问必备:SAP ABAP开发技术总结
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [SAP ABAP开发技术总结]OPEN SQL
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- ABAP开发顾问必备:SAP ABAP开发技术总结[转载]
转载自SAP师太技术博客,原文链接:http://www.cnblogs.com/jiangzhengjun/p/4260224.html 在原文上增加了链接,此文及此文的链接版权都归SAP师太所有. ...
- [SAP ABAP开发技术总结]ABAP程序之间数据共享与传递
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [SAP ABAP开发技术总结]内表操作
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [SAP ABAP开发技术总结]字符串处理函数、正则表达式
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [SAP ABAP开发技术总结]FTP到文件服务器,服务器上文件读写
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- [SAP ABAP开发技术总结]Function远程、同步、异步调用
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
随机推荐
- Delphi Xe2 后的版本如何让Delphi程序启动自动“以管理员身份运行"
由于Vista以后win中加入的UAC安全机制,采用Delphi开发的程序如果不右键点击“以管理员身份运行”,则会报错. 在XE2以上的Delphi版本处理这个问题已经非常简单了. 右建点击工程,选择 ...
- json_decode和json_encode
JSON出错:Cannot use object of type stdClass as array解决方法php再调用json_decode从字符串对象生成json对象时,如果使用[]操作符取数据, ...
- 【python cookbook】【数据结构与算法】13.通过公共键对字典列表排序
问题:想根据一个或多个字典中的值来对列表排序 解决方案:利用operator模块中的itemgetter()函数对这类结构进行排序是非常简单的. # Sort a list of a dicts on ...
- zabbix监控phpfpm
php-fpm status详解 pool – fpm池子名称,大多数为wwwprocess manager – 进程管理方式,值:static, dynamic or ondemand. dynam ...
- db2常用函数(1)
VALUE函数 语法:VALUE(EXPRESSION1,EXPRESSION2) VALUE函数是用返回一个非空的值,当其第一个参数非空,直接返回该参数的值,如果第一个参数为空,则返回第一个参数的值 ...
- C#:实现接口中定义的事件
public delegate void TestDelegate(); // delegate declaration public interface ITestInterface { event ...
- JavaScript脚本语言基础(二)
导读: JavaScript条件语句 JavaScript循环语句 JavaScript网页中错误捕获 JavaScript的Break和Continue命令 JavaScript的转义字符 1.Ja ...
- DataRow数组转换DataTable
public DataTable ToDataTable(DataRow[] rows) { if (rows == null || rows.Length == 0) return null; Da ...
- JAVA基础知识之网络编程——-基于NIO的非阻塞Socket通信
阻塞IO与非阻塞IO 通常情况下的Socket都是阻塞式的, 程序的输入输出都会让当前线程进入阻塞状态, 因此服务器需要为每一个客户端都创建一个线程. 从JAVA1.4开始引入了NIO API, NI ...
- SecureCRT issue "Could not open clipboard: Assess is denied" (无法打开粘贴板:访问被拒绝)
I got an issue when copying some line/word (actually just select the context ) in the Linux terminal ...