“var”和“out”参数有啥区别?

Posted

技术标签:

【中文标题】“var”和“out”参数有啥区别?【英文标题】:What's the difference between "var" and "out" parameters?“var”和“out”参数有什么区别? 【发布时间】:2013-01-08 13:28:09 【问题描述】:

var声明的参数和out声明的参数有什么区别?编译器如何区别对待它们(例如,通过生成不同的代码,或通过更改它发出的诊断信息)?或者不同的修饰符是否仅仅允许程序员记录参数的预期用途?参数的类型对此事有何影响?

【问题讨论】:

我一直有同样的问题,但从来没有问过。 我也是。我实际上已经run into this problem,所以我想要一个非常好的答案。 文档说得很清楚,IMO:docwiki.embarcadero.com/RADStudio/XE3/en/… @ain 很清楚。这是不正确的。它仅适用于托管类型。 也许问 Embarcadero 会有所作为... 【参考方案1】:

var 参数将通过引用传递,就是这样。

out 参数也通过引用传递,但假定输入值无关紧要。对于托管类型(字符串、接口等),编译器将通过在例程开始之前清除变量来强制执行此操作,相当于编写param := nil。对于非托管类型,编译器实现 outvar 相同。

请注意,托管参数的清除是在调用站点执行的,因此为函数生成的代码不会随outvar 参数而变化。

【讨论】:

这个答案很好很简单,但现在我已经阅读了 Serg 的(已删除)答案,我再次感到困惑。他说out对于外部函数的接口参数很重要,因为其他(非Delphi)代码可能会用“垃圾值”调用它。但是如果varout之间的唯一区别在于编译器处理调用端的方式,而调用端在Serg的场景中不在Delphi中,那我不明白Serg 试图指出什么区别。 @Rob 我认为 Serg 在这里有点困惑。他在他的博客上说得对:sergworks.wordpress.com/2012/10/01/… 我越想为什么要实现out 参数,我就越想知道。在本机 Delphi 代码中,不需要在过程之外将 out 参数设为 nil,而且我无法了解当前的 out 参数实现如何帮助搭建与其他处理接口类型 @ 的语言的桥梁987654335@ 参数不同。 @Serg,如果其他语言在分配给它之前清除输出参数,并且Delphi没有在调用之前清除它,那么这就是内存泄漏。 Delphi 不知道被调用函数会做什么,因此唯一安全的选择是在将变量传递给其他代码之前始终清除该变量。清除变量两次总比不清除要好。 @RobKennedy +1 Delphi 端可能的内存泄漏是一个充分的解释,谢谢。【参考方案2】:

对于编译器来说没有太大区别。请参阅Mason's answer。

语义上有很大的区别:

var 告诉程序员例程可以使用其当前值, out 告诉程序员例程将忽略/丢弃它的当前值。

【讨论】:

@David,这个答案是处理文档,而不是实际行为。我认为大多数人通常假设 Delphi 中的out 与C# 中的out 工作方式相同,在参数写入之前读取参数是非法的。当人们在 Delphi 中声明 out 参数时,我认为这通常是他们打算对待它们的方式。使用 out 而不是 var 可以记录该意图,即使编译器实际上并未强制执行。在写入 out 参数之前读取它是一个错误和错误,即使编译器没有将其标记为错误。 @Rob 如果编译器不检查,那么整个大厦就会倒塌。在调用函数之前,程序员必须去检查函数。我的意思是,在编写函数时,我使用out 来记录我的意图。但是当我遇到一个带有out参数的函数时,我必须去检查。 @NGLN 我完全明白了。我完全理解 out 的语义。只是因为编译器不强制执行,所以函数很可能会使用我输入的值。换句话说,例程的作者可以骗我,编译器不会抱怨。想象一下,如果编译器不费心强制执行类型安全。仅仅因为函数说它期望接收一种类型的参数,错误的程序员可以发送其他东西。 IMO 的问题在于有关 Delphi 如何处理 out 参数的文档可能是为 Delphi.NET 或其他内容编写的,但不是为 Delphi 编写的。根据文档,Delphi 编译器无法实现 out 参数,这引发了一些问题,out 参数到底是什么以及何时应该使用它们。 我认为,如果程序员使用“out”,那么他就是在声明他不会读取该值并假设它是有用的。如果我有问题,我个人只会检查是否有人正确编写了例程。所以我认为 NGLN 的答案是正确的。【参考方案3】:

有点晚了,但为了记录,我遇到了一个案例,varout 有很大的不同。

我正在开发一个导出以下方法的 SOAP Web 服务:

function GetUser( out User :TUser ) :TResult;

它被导入到 C# 中,相当于

function GetUser( out Result :TResult) :TUser;

当我将 out 更改为 var 时,它会正确导入。

我猜测 Delphi SOAP 调用程序将函数结果视为一个 out 参数,并且具有两个 out 参数会混淆 Delphi SOAP 例程。我不确定是否有解决方法允许您使用 out 参数。

【讨论】:

以上是关于“var”和“out”参数有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

参数和参数有啥区别? [复制]

实际参数、格式参数、虚拟参数以及实际参数和形式参数之间有啥区别? [复制]

参数和选项有啥区别?

python视角中的参数和参数有啥区别[不重复:)]? [复制]

操作参数和 GraphQL 变量有啥区别?

jmeter有啥方法可以在参数内传递参数吗? [复制]