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

时间:2023-03-08 22:43:03
[SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址
[SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址
声明:原创作品,转载时请注明文章来自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

中通过

引用传递时,

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

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

1.10.2.1.

Function Group

结构

当使用

Function Builder

创建函数组时,系统会自动创建

main program

与相应的

include

程序:

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

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

文件等)加载到主调程序所在的

internal session

中,然后该

Function Module

得到执行,该

Function Group

一直保留在内存中,直到

internal session

结束。

Function Group

中的所定义的

Include

文件中的变量是全局,被所有

Function Module

共享,所以

Function Group

好比

Java

中的类,而

Function Module

则好比类中的方法,所以

Function Group

中的

Include

文件中定义的东西是全局型的,能被所有

Function Module

所共享使用

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

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

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

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

1.10.2.2.

Function

参数传值、传址

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

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

[SAP ABAP开发技术总结]Form(subroutine)、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