VBScript中的ByRef和ByVal
我在VBScript中遇到了一些奇怪的问题。在编写希望通过引用传递参数的过程时,调用此过程的方式会更改传递参数的方式 以下是一个例子:VBScript中的ByRef和ByVal,vbscript,Vbscript,我在VBScript中遇到了一些奇怪的问题。在编写希望通过引用传递参数的过程时,调用此过程的方式会更改传递参数的方式 以下是一个例子: Sub IncrementByRef(ByRef Value) Value = Value + 1 End Sub Sub IncrementByVal(ByVal Value) Value = Value + 1 End Sub Dim Num Num = 10 WScript.Echo "Num : " & Num Increment
Sub IncrementByRef(ByRef Value)
Value = Value + 1
End Sub
Sub IncrementByVal(ByVal Value)
Value = Value + 1
End Sub
Dim Num
Num = 10
WScript.Echo "Num : " & Num
IncrementByRef(Num) : WScript.Echo "IncrementByRef(Num) : " & Num
IncrementByRef Num : WScript.Echo "IncrementByRef Num : " & Num
IncrementByVal(Num) : WScript.Echo "IncrementByVal(Num) : " & Num
IncrementByVal Num : WScript.Echo "IncrementByVal Num : " & Num
以下是输出:
U:\>cscript //nologo byrefbyval.vbs
Num : 10
IncrementByRef(Num) : 10
IncrementByRef Num : 11
IncrementByVal(Num) : 11
IncrementByVal Num : 11
U:\>
当指定参数以ByVal传递时,无论调用过程的方式如何,它都会按预期工作。
但是,当指定参数时,如果以这种方式调用过程,它将按预期工作:
IncrementByRef Num
IncrementByRef(Num)
但不是这样:
IncrementByRef Num
IncrementByRef(Num)
我觉得这很奇怪。有没有办法确保参数是通过ref传递的,不管过程是如何调用的?这是一个特性,而不是一个bug:
如果参数用括号括起来,且括号不适用于参数列表,则ByRef参数按值传递 如果满足以下条件之一,则括号适用于参数列表:
- 该语句是对返回值进行赋值的函数调用
- 语句使用Call关键字。(Call关键字可选择性地用于子例程调用,或用于无赋值的函数调用。)
ByRef
参数括在括号中,将其作为ByVal
传递
IncrementByRef Num
简而言之,VBScript子例程调用中的括号不仅可以放在参数列表周围,还可以放在各个参数周围(在这种情况下,它们是强制的ByVal
)。如果使用了Call
关键字,VBScript只希望参数列表括在括号中。由于IncrementByRef(Num)
调用不使用call
关键字,VBScript将括号视为应用于子例程参数,因此将其传递为ByVal
,而不是ByRef
令人困惑,但这就是它的工作方式。要清楚。括号有三个不同的用途
x = func(y)
声明:-
func y
注意,Call
关键字调用过程就像它是表达式的一部分一样,因此参数列表必须包含在参数列表中
在上文中,y
本身代表了一个非常简单的支出。在这一点上,我们完全可以使用y+z
。事实上,此时我们可以使用任何有效的表达式,包括使用圆括号运算符的表达式。例如:-
x = (y)
是一个有效的表达式。因此,当您这样做时:-
func(y)
VBScript将看到对func
的调用,表达式(y)
的结果将传递给该调用。现在,即使func
将此参数定义为ByRef
,y
中的值不会受到影响,因为y
实际上没有作为参数传递。传递的是表达式(y)
的结果,该表达式将存储在临时位置。即使此临时存储被func
修改,它也会在以后被丢弃,因此,如果参数被标记为ByVal
,它的行为也会相同
IncrementByRef Num
使用对Num的引用调用和递增
IncrementByRef (47 + 3)
调用并使用对“50”的引用递增。在出口处被丢弃
IncrementByRef (Num)
IncrementByRef (Num + 18)*5
IncrementByRef Cint("32")
在BASIC中都是合法的,就像在FORTRAN中一样。众所周知,在早期的FORTRAN中,通过ref传递可以更改表达式的值,如
5
这让人非常困惑,因为只有非常小的早期FORTRAN编译器才有这种行为。这很简单。创建函数或子函数时,可以使用以下方式调用它们: 对于无返回值:
myFunction "This is a reference"
myValue = myFunction ("This is a reference")
对于返回值:
myFunction "This is a reference"
myValue = myFunction ("This is a reference")
我不确定我是否遵循了问题或答案,但我将分享这一点 无论您是否有函数的子程序,定义传入
ByVal
或ByRef
的参数将确定参数值是否在子程序或函数调用之外保留其值。如果我有以下功能:
Function ThisFByRef(ByRef MyValue)
End Function
我在函数(或子程序)中对参数所做的任何操作都将在函数完成后保留其值ByVal
和ByRef
与子程序或函数的范围相关联。通过val传递的任何参数都不会保留被调用子程序或函数中发生的更改。或者,通过refByRef
传递的任何参数将保留其在子程序或函数中更改的值。返回值只能通过函数而不是子程序来完成,并且不会影响传入的参数值,除非参数在函数中被传递并更改。例如:
Dim x
Dim ThisFValue
x = 0
ThisFValue = ThisFByRef(x)
At this point the values would be:
ThisFValue = 2
x = 1
x = 0
ThisFValue = ThisFByVal(x)
At this point the values would be:
ThisFValue = 2
x = 0
Function ThisFByRef(ByRef x)
x = x + 1
ThisFByRef = x + 1
End Function
Function ThisFByVal(ByVal x)
x = x + 1
ThisFByVal = x + 1
End Function
这是我见过的与VBScript相关的最令人困惑的MSDN主题之一…这么简单?我挣扎了一个小时!谢谢,+1。很多旧的MSDN内容已经被微软储存起来了。Eric Lippert引用的文章仍然可以在互联网档案中找到:@mnemotronic也可以在Eric的博客中找到。我已经更新了答案中的链接。IMHO,你的答案没有阐明我的观点,我觉得奇怪的是,在调用
ThisFValue=ThisByRef(x)
后,x包含1,但如果我这样调用它,则x包含0。相同的函数,相同的参数,但结果不同!