Plsql PL/SQL:混淆了函数调用(堆栈帧)中的类型强制

Plsql PL/SQL:混淆了函数调用(堆栈帧)中的类型强制,plsql,coercion,stack-frame,Plsql,Coercion,Stack Frame,考虑以下示例: create or replace function f(n integer) return integer as begin return n; end; / begin dbms_output.put_line(f(3.8)); end; / 3.8 PL/SQL procedure successfully completed. declare x integer; begin x := 3.8; dbms_output.put_line(x)

考虑以下示例:

create or replace function f(n integer) return integer as
begin
  return n;
end;
/

begin
  dbms_output.put_line(f(3.8));
end;
/

3.8


PL/SQL procedure successfully completed.
declare
  x integer;
begin
  x := 3.8;
  dbms_output.put_line(x);
end;
/

4


PL/SQL procedure successfully completed.
这对我来说毫无意义。显然,PL/SQL在进入函数和退出函数时都忽略了
整数
规范。这仅仅是一个bug吗?这是语言开发人员故意做出的设计选择吗

这就是为什么我感到困惑。与以下示例进行比较:

create or replace function f(n integer) return integer as
begin
  return n;
end;
/

begin
  dbms_output.put_line(f(3.8));
end;
/

3.8


PL/SQL procedure successfully completed.
declare
  x integer;
begin
  x := 3.8;
  dbms_output.put_line(x);
end;
/

4


PL/SQL procedure successfully completed.
在此示例中,符合数据类型规范。PL/SQL不会抛出错误,但至少它执行隐式强制,并且不会违反为
x
声明的数据类型-该变量存储值4,一个整数,而不是3.8

那么,在第一个示例中,PL/SQL是如何进行函数调用的呢?据我所知(从未接受过正式的计算培训),每当编译器或解释器发现函数调用时,它都会创建一个堆栈框架,其中包含传递给函数的参数变量和从函数返回的返回值变量。当创建堆栈帧时,这些变量不应该与函数声明中指定的数据类型相同吗?如果堆栈帧的参数3.8有一个
integer
数据类型的字段,为什么在它存储到相应的变量中之前不强制为4?返回值也是一样:如果函数返回3.8,但调用方需要一个整数(因此堆栈帧中的相应变量应该是
integer
),它如何能够接受返回值3.8

而且,最令人不安的是——为什么这种行为与涉及显式声明变量时的行为不同(如我的第二个示例)


谢谢你分享你的想法

答案可在Oracle数据库文档中找到(您的问题与此完全无关)

首先,所述数据库中的
INTEGER
是一个整数。如第二个示例所示,在分配给
数字(38)
变量
x
时,根据分配规则,
数字
(具有任意精度)文字
3.8
四舍五入


在您的第一个示例中,由于PL/SQL子程序的
中的
参数和相同的引用(到
编号
值3.8)被返回,因此不会发生赋值。

OK-关于
中的
参数是通过引用传递的这一事实,这一点非常好。这解释了如何将值3.8传递给函数。不过,我不相信这可以解释
返回步骤的行为。函数返回的值可能与传入的变量无关;为什么允许返回非整数,这是怎么可能的?并且,为了进一步澄清:如果我更改函数的定义,将
return
子句更改为
return 3.8
(硬编码常量),函数将返回4。为什么当我写
return n
时它返回3.8,而
n
是3.8?经过进一步的思考和额外的实验,我对输入仍然不是100%清楚。如果我将函数更改为
return varchar2
,返回值为
return n
,如果我调用
f('000100')
,则输出为
'100'
,而不是
'000100'
。这意味着在某个地方,参数确实被转换为数字并返回-函数并不是简单地返回输入值。当输入的数据类型与函数期望的不同时,“通过引用传递”显然不是真正的“通过引用传递”。这是一个完美的例子,说明了为什么永远不应该依赖隐式数据转换。如果变量应包含数据类型T,则将指定的变量设为数据类型T,必要时使用显式转换。@Belayer-毫无疑问。我倾向于在将错误类型的值传递给函数(或分配给变量)时抛出错误,而不是在我背后尝试隐式转换。但我无法控制用户如何使用我的函数。我在OTN上发布了一个相关(但不同)的问题: