抱歉,我来晚了,但其他答案不正确,至少使用 Oracle 11gR2,您想要实现的目标确实是完全可能的。
我最近刚刚偶然发现了这个问题,我看到一个人可以明确地返回一个参考,SELF
就像你试图做的那样,而不需要任何权衡或应用变通方法。
唯一需要的是通过(显式)将(隐式)SELF
参数设置为来重新定义方法SELF IN OUT rectangle
。是静默传递给每个对象方法的主要参数,并且对于函数被定义为
(不可变的;这可能是编译器抱怨的原因)。这是在编译时建立的,但好的部分是在调用该方法时可以省略它。
在文章末尾的示例中(根据您的稍作改写),我们定义了一个SELF
IN
MEMBER FUNCTION incrementWidth(SELF IN OUT rectangle, w NUMBER) RETURN rectangle
我们执行它忽略SELF
引用:
declare
r rectangle := rectangle(1,2);
begin
dbms_output.put_line('width is: ' || r.width);
dbms_output.put_line('new width is: ' || r.incrementWidth(3).width);
end;
/
请注意,有两个警告需要注意。
警告 1
每个方法调用都会临时创建对象的新副本。
但只是暂时的,新实例是短暂的,就在方法的开始和结束之间。这是在所有函数或过程上使用IN OUT
参数所固有的,并不特定于对象类型。如果您想防止这种行为,您可能需要使用NOCOPY
提示重新定义函数的签名:
MEMBER FUNCTION incrementWidth(SELF IN OUT NOCOPY rectangle, w NUMBER) RETURN rectangle
有关详细信息,请参阅ORACLE-BASE - NOCOPY。请注意,这是一个提示,但不能保证您最终使用的是相同的对象引用而不是新创建的对象,因此请谨慎使用。
警告 2
鉴于您提出了这个问题,您可能有 OOP 背景,并且在尝试调用该方法而不使用返回的引用时,您可能会感到惊讶
r.incrementWidth(10);
编译器将返回错误:
PLS-00221: 'INCREMENTWIDTH' is not a procedure or is undefined
那么这里发生了什么?好吧,pl/sql 中所谓的“静态多态”(即编译过程中方法重载的选择)与其他 OOP 语言略有不同,因为它甚至考虑了 RETURNed 类型的使用。为了解决这个问题,添加一个带有签名的伴随过程,其区别在于缺少返回类型:
MEMBER FUNCTION incrementWidth(SELF IN OUT rectangle, w NUMBER) RETURN rectangle,
MEMBER PROCEDURE incrementWidth(SELF IN OUT rectangle, w NUMBER)
合理地,如果您不想在函数和过程中重复相同的代码,过程将在内部委托函数;并且根据您使用的 Oracle 版本,您可能希望使用代码内联(请参阅OCP:更多新的 PL/SQL 功能)以达到与复制粘贴实现相同的速度(您几乎不会注意到真正的区别) . 显式“内联”按名称指向方法,但它也适用于方法名称重载的情况。
在下面的示例中,您将看到根据返回/未返回参数的使用情况交替调用函数或过程。
所以最后...
可能想要编写的代码如下(我没有使用NOCOPY
不污染相关的东西,但它很简单)
CREATE OR REPLACE TYPE rectangle AS OBJECT
(
length NUMBER,
width NUMBER,
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT,
MEMBER FUNCTION incrementWidth(SELF IN OUT rectangle, w NUMBER) RETURN rectangle,
MEMBER PROCEDURE incrementWidth(SELF IN OUT rectangle, w NUMBER)
);
/
CREATE OR REPLACE TYPE BODY rectangle AS
CONSTRUCTOR FUNCTION rectangle(length NUMBER, width NUMBER)
RETURN SELF AS RESULT
AS
BEGIN
SELF.length := length;
SELF.width := width;
RETURN;
END;
MEMBER FUNCTION incrementWidth(SELF IN OUT rectangle, w NUMBER) RETURN rectangle IS
BEGIN
dbms_output.put_line('...invoking the function with input ' || w);
width := width + w;
RETURN SELF;
END;
MEMBER PROCEDURE incrementWidth(SELF IN OUT rectangle, w NUMBER) IS
BEGIN
PRAGMA INLINE (incrementWidth, 'YES');
dbms_output.put_line('...invoking the procedure with input ' || w || ', that in turn is...');
self := incrementWidth(w);
END;
END;
/
在执行...
set serveroutput on
select * from v$version where rownum = 1;
declare
r rectangle := rectangle(1,2);
begin
dbms_output.put_line('width is: ' || r.width);
--this is invoking the "function" version, because we are making use of
--the returned rectangle object
dbms_output.put_line('new width is: ' || r.incrementWidth(3).width);
--the original reference has been updated even without using the NO COPY hint
dbms_output.put_line('original object has width updated: ' || r.width);
--this is invoking the "procedure" version, because we are not using the returned object
r.incrementWidth(3);
--of course this has finally worked as well
dbms_output.put_line('again what is the new width like now?: ' || r.width);
end;
/
你得到
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
width is: 2
...invoking the function with input 3
new width is: 5
original object has width updated: 5
...invoking the procedure with input 3, that in turn is...
...invoking the function with input 3
again what is the new width like now?: 8