问题描述
考虑以下示例:
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.
这对我来说毫无意义。显然,PL/sql 在进入函数和退出函数时都忽略了 integer
规范。这只是一个错误吗?是语言开发者故意做出的设计选择吗?
这就是我觉得这令人困惑的原因。与以下示例进行比较:
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
是一个synonym for NUMBER(38)
。在分配给 NUMBER(38)
变量 x
时,如在您的第二个示例中,根据分配规则,NUMBER
(具有任意精度)文字 3.8
被四舍五入。
在您的第一个示例中,虽然没有发生赋值,因为 IN
PL/SQL 子程序 are passed by reference 的参数和相同的引用(对 NUMBER
值 3.8)被返回。