问题描述
我在得到的一些代码中遇到了这个 “错误”,并且能够将其简化为此示例 (我只给出软件包主体,规范只是过程而已)
所以我在身体中定义了一个全局集合,并用一些数据填充它。
然后迭代集合,并通过调用一个包含IN OUT参数的过程来修改每个记录 (他们有一些理由这样做)。
全局变量的修改在离开程序后保留,但是对集合的修改丢失了!
但是,当我将IN OUT更改为IN时,将保留对集合的修改。
因此,当从以下位置更改输入变量时by reference 到by value,我的代码中的一个不相关的变量变得不可变。
你能解释这种行为吗?
package body asl_test
is
type gr_rec is record ( id number , kol varchar2(1) );
type gt_tab is table of gr_rec index by binary_integer;
g_tab gt_tab := gt_tab();
g_const varchar2(10);
procedure modify_record
( p_in in out gr_rec --> this breaks the mutability of the global collection
)
is
begin
-- This works...
g_const := 2;
/*
But the IN OUT ignores this modification
Original code deleted the entry from the collection
but the entry stayed.
*/
g_tab(p_in.id).kol := 'J';
end;
procedure modify_collection
is
begin
for i in g_tab.first .. g_tab.last
loop
modify_record(g_tab(i));
end loop;
end;
procedure go
is
begin
g_const := 1;
g_tab(1).id := 1; g_tab(1).kol := 'N';
g_tab(2).id := 2; g_tab(2).kol := 'N';
--
modify_collection();
--
dbms_output.put_line('The collection is not modified!');
for i in g_tab.first .. g_tab.last
loop
dbms_output.put_line(g_tab(i).kol);
end loop;
dbms_output.put_line('variable is correctly modified 到2: '||g_const);
end;
end;
所以我在身体中定义了一个全局集合,并用一些数据填充它。
然后迭代集合,并通过调用一个包含IN OUT参数的过程来修改每个记录 (他们有一些理由这样做)。
全局变量的修改在离开程序后保留,但是对集合的修改丢失了!
但是,当我将IN OUT更改为IN时,将保留对集合的修改。
因此,当从以下位置更改输入变量时by reference 到by value,我的代码中的一个不相关的变量变得不可变。
你能解释这种行为吗?
专家解答
这里的问题是代码没有为IN OUT参数分配值。事件的链条是:
-传递参数的值
-设置全局变量
-将参数的值传递出去
因为实际参数是全局变量,所以会发生这种情况:
-传递参数的值
-设置全局变量
-将参数的值传递出去 - OVERWRITING the previous assignment to the global
一个更简单的例子显示了这一点:
为了避免这种情况,您需要为过程中的参数分配一个值:
将modify_collection中的赋值更改为:
你会得到你想要的行为。
但是传递全局参数是令人困惑的-它有点违背了使它成为一个全局的点。
最好将要更改的数组条目的索引作为IN参数传递:
-传递参数的值
-设置全局变量
-将参数的值传递出去
因为实际参数是全局变量,所以会发生这种情况:
-传递参数的值
-设置全局变量
-将参数的值传递出去 - OVERWRITING the previous assignment to the global
一个更简单的例子显示了这一点:
DECLARE
n NUMBER := 10;
PROCEDURE p (
n1 IN OUT NUMBER
) IS
BEGIN
DBMS_OUTPUT.put_line('Global ' || n); -- global value is 10
DBMS_OUTPUT.put_line('Actual ' || n1); -- actual parameter value is 10
n := -99;
DBMS_OUTPUT.put_line('Global ' || n); -- global value is -99
DBMS_OUTPUT.put_line('Actual ' || n1); -- actual parameter value is still 10
-- this value is copied back to the global when this procedure exits!
END;
BEGIN
p(n);
DBMS_OUTPUT.put_line(n);
END;
/
Global 10
Actual 10
Global -99
Actual 10
10为了避免这种情况,您需要为过程中的参数分配一个值:
DECLARE
n NUMBER := 10;
PROCEDURE p (
n1 IN OUT NUMBER
) IS
BEGIN
DBMS_OUTPUT.put_line('Global ' || n); -- global value is 10
DBMS_OUTPUT.put_line('Actual ' || n1); -- actual parameter value is 10
n1 := -99;
DBMS_OUTPUT.put_line('Global ' || n); -- global value is 10
DBMS_OUTPUT.put_line('Actual ' || n1); -- actual parameter value is still -99
-- this is copied back over the global value when this procedure exits!
END;
BEGIN
p(n);
DBMS_OUTPUT.put_line(n);
END;
/
Global 10
Actual 10
Global 10
Actual -99
-99将modify_collection中的赋值更改为:
p_in.kol := 'J';
你会得到你想要的行为。
但是传递全局参数是令人困惑的-它有点违背了使它成为一个全局的点。
最好将要更改的数组条目的索引作为IN参数传递:
procedure modify_record ( p_in in number )
is
begin
g_const := 2;
g_tab(p_in).kol := 'J';
end;
procedure modify_collection
is
begin
for i in g_tab.first .. g_tab.last
loop
modify_record(i);
end loop;
end; 文章转载自ASKTOM,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




