包体中有两个同名但参数不同的函数是啥意思?

Posted

技术标签:

【中文标题】包体中有两个同名但参数不同的函数是啥意思?【英文标题】:What does it means when there are two functions with the same name but different parameter in the package body?包体中有两个同名但参数不同的函数是什么意思? 【发布时间】:2019-04-04 14:57:16 【问题描述】:

在包规范中,函数名只出现一次,因此它没有被重载。在包体中,相同的函数名称使用不同的参数集出现两次。其中之一具有与包规范中的参数相同的参数。我的问题是,包体中的“第一个函数”是否实际被调用,如果是,它到底在做什么?它正在尝试返回自身。

    --package specification
    CREATE OR REPLACE 
    PACKAGE jtestpkg
      IS
    FUNCTION testfunc(p_num IN NUMBER, p_out1 IN out varchar2, p_out2 IN out varchar2)
      RETURN NUMBER;
    END jtestpkg;

    --package body
    CREATE OR REPLACE 
    PACKAGE BODY jtestpkg
      IS
      --first func
      function testfunc
            (p_num IN NUMBER,
             p_out1 IN OUT varchar2) 
            return number is
                v_out2 varchar2(50);
      BEGIN
      dbms_output.put_line('invoking first func');
          RETURN testfunc(
              p_num,
              p_out1,
              v_out2);
      END;
      --second func
      FUNCTION testfunc(
                p_num IN NUMBER,
                p_out1 IN OUT varchar2,
                p_out2 IN OUT varchar2)
        RETURN NUMBER
        IS
        v_num number;
      BEGIN
        IF 1=p_num THEN
          p_out1:='FirstOUT_1';
          p_out2:='SecondOUT_1';
          dbms_output.put_line(v_num||p_out1||p_out2);
          RETURN 1;
        elsif 2=p_num THEN
          p_out1:='FirstOUT_2';
          p_out2:='SecondOUT_2';
          dbms_output.put_line(v_num||p_out1||p_out2);
          RETURN 2;
        ELSE
          p_out1:='FirstOUT_3';
          p_out2:='SecondOUT_3';
          dbms_output.put_line(v_num||p_out1||p_out2);
          return 3;
        END IF;
        ------
      p_out1:='FirstOUT_0';
      p_out2:='SecondOUT_0';
      dbms_output.put_line(v_num||p_out1||p_out2);
      RETURN 0;
      END testfunc;
    END jtestpkg;

【问题讨论】:

【参考方案1】:

规范中声明的函数是公共的,可以从包外部调用。在主体中定义但未在规范中声明的函数是私有的,只能从该包中调用。

在您的示例中,您在包主体中标记为“第二个函数”的函数的第二个重载版本与规范中的声明相匹配,因此这是您从其他地方调用函数时所涉及的那个:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
  in_out_2 varchar2(20) := 'B';
begin
  rc := jtestpkg.testfunc(42, in_out_1, in_out_2);
end;
/

FirstOUT_3SecondOUT_3


PL/SQL procedure successfully completed.

你的主体中的第一个重载函数,你标记为“第一个函数”,在规范中没有匹配的声明,所以你不能在外部调用它:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
begin
  rc := jtestpkg.testfunc(42, in_out_1);
end;
/

ORA-06550: line 5, column 9:
PLS-00306: wrong number or types of arguments in call to 'TESTFUNC'
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored

我的问题是,包体中的“第一个函数”是否实际被调用

没有。在您的代码中,从未调用过“第一个函数”。

它试图返回自己。

不,不是。如果您的“第一个 func”本身是从包内的其他地方调用的,那么您的“第一个 func”将调用“第二个 func”,但您目前没有这样做。

那里的调试说“调用第一个函数”,但这不是真的,它正在调用 second 函数,因为它进行的调用具有三个参数 - 匹配“第二个函数”参数列表。 (这恰好是公开的,但如果不公开也没关系,因为它无论如何都在包的内部)。

例如,您可以将私有函数作为package instantiation and initialization 的一部分调用:

...
  END testfunc;

-- initialization, called on instantiation (for each session)
BEGIN
  dbms_output.put_line('Initialization start');
  declare
    rc number;
    in_out_1 varchar2(20) := 'A';
  begin
    dbms_output.put_line('Initialization: calling first func');
    rc := testfunc(1, in_out_1);
  end;
  dbms_output.put_line('Initialization end');
END jtestpkg;
/

然后在会话中第一次调用包中的任何公共内容都会对其进行实例化,从而对其进行初始化,从而运行该包级块。所以使用相同的匿名块:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
  in_out_2 varchar2(20) := 'B';
begin
  rc := jtestpkg.testfunc(42, in_out_1, in_out_2);
end;
/

您会看到(仅限会话中的第一次):

Initialization start
Initialization: calling first func
invoking first func
FirstOUT_1SecondOUT_1
Initialization end
FirstOUT_3SecondOUT_3


PL/SQL procedure successfully completed.

您仍然可以看到与之前相同的FirstOUT_3SecondOUT_3 输出,来自该调用中传递的值 42;但在此之前,您会看到来自 'first func' 调用 'second func' 的输出 FirstOUT_1SecondOUT_1,其值为 1 作为初始化过程的一部分。


允许函数调用自身,即递归调用,但每次都需要更改调用,否则会陷入无限循环,最终被杀死。不过,您在这里也没有这样做。

【讨论】:

惊人的阐述。我正在经历一个巨大的包裹,这部分让我感到困惑。包和其他子程序中似乎没有使用“第一个函数”。不知道为什么它被留在包里没有任何用处。您对我是否有任何指示来确定是否正在使用“第一个功能”?我目前正在根据参数的数量检查它是否正在使用。 假设你在一个开发环境中并且没有人对你大喊大叫,删除或注释掉你认为多余的函数——或者只是改变它的名字——然后重新编译。对于私有函数,任何调用都将在同一个文件中,因此如果使用它就不会编译。如果它是公开的,那么你必须在规范中做同样的事情;并且您可以查看是否有任何其他对象无效。但更可控的方式是通过PL/Scope。 @JohnAl - this might be helpful,至少在包内。

以上是关于包体中有两个同名但参数不同的函数是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

对虚函数进行重载是啥意思?

insert在python里是啥意思

glDrawElements中的index参数是啥意思?

Java中的方法覆盖(Overriding)和方法重载(Overloading)是啥意思?

英语parameter和argument作为参数的意思区别是啥?

php中的global关键字是啥意思