【问题标题】:ByRef and ByVal in VBScriptVBScript 中的 ByRef 和 ByVal
【发布时间】:2009-10-08 13:33:17
【问题描述】:

我在 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
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 传递时,它按预期工作,无论过程调用方式如何。 但是当指定参数通过 ByRef 传递时,如果以这种方式调用过程,它将按预期工作:

IncrementByRef Num

但不是这样:

IncrementByRef(Num)

这对我来说似乎很奇怪。有没有办法确保参数通过 ByRef 传递,无论过程如何调用?

【问题讨论】:

    标签: vbscript


    【解决方案1】:

    Eric Lippert 有一篇关于在 VBScript 中使用括号的精彩文章: What do you mean "cannot use parentheses?" 您的示例说明了他提到的要点之一,即:将 ByRef 参数括在括号中将其传递为 ByVal

    简而言之,VBScript 子例程调用中的括号不仅可以放在参数列表周围,还可以放在单个参数周围(在这种情况下,它们是强制的ByVal)。如果使用了Call 关键字,VBScript 只要求将参数列表括在括号中。由于IncrementByRef(Num) 调用不使用Call 关键字,VBScript 将括号视为应用于子例程参数,因此将其传递给ByVal 而不是ByRef

    令人困惑,但这就是它的工作方式。

    【讨论】:

    【解决方案2】:

    这是一项功能,而不是错误:
    http://msdn.microsoft.com/en-us/library/ee478101.aspx

    如果参数用括号括起来并且括号不适用于参数列表,则按值传递 ByRef 参数。

    如果满足以下条件之一,括号将应用于参数列表:

    • 语句是对返回值进行赋值的函数调用。

    • 该语句使用 Call 关键字。 (Call 关键字可以选择性地用于子例程调用,或用于没有赋值的函数调用。)

    所以尝试使用 Call 关键字或让它返回一个值。

    【讨论】:

    • 这是我见过的与 VBScript 相关的最令人困惑的 MSDN 主题之一
    【解决方案3】:

    要清楚。括号有三种不同的用途。

    1. 用于在定义或调用过程时包含参数列表
    2. 指示数组上的索引器。
    3. 作为表达式中的运算符。

    有两种方法可以将过程调用为语句或表达式。

    表达式:-

    x = func(y)
    

    声明:-

    func y
    

    注意Call 关键字调用过程就好像它是表达式的一部分,因此参数列表必须包含在括号中。

    在上面y 本身代表了一个非常简单的表达式。此时我们很可能使用y + z。事实上,此时我们可以使用任何有效的表达式,包括使用括号运算符的表达式。例如:-

     x = (y)
    

    是一个有效的表达式。因此,当您这样做时:-

     func(y)
    

    VBScript 看到对func 的调用,表达式(y) 的结果被传递到该调用。现在即使func 将此参数定义为ByRefy 中的值也不会受到影响,因为y 实际上并未作为参数传递。传递的是表达式(y) 的结果,它将临时存储在某个地方。即使这个临时存储被func 修改,它也会在之后被丢弃,因此如果参数被标记为ByVal,则具有相同的行为。

    【讨论】:

      【解决方案4】:
      IncrementByRef Num
      

      使用对 Num 的引用进行调用和递增

      IncrementByRef (47 + 3)
      

      使用对“50”的引用来调用和递增。退出时丢弃。

      IncrementByRef (Num)
      IncrementByRef (Num + 18)*5
      IncrementByRef Cint("32")
      

      在 BASIC 中都是合法的,就像在 FORTRAN 中一样。众所周知,在早期的 FORTRAN 中,传递 ref 允许您更改表达式的值,例如

      5
      

      这非常令人困惑,只有非常小的早期 FORTRAN 编译器才有这种行为。

      【讨论】:

        【解决方案5】:

        我不确定我是否遵循问题或答案,但我会分享这个。

        不管你是否有函数的子例程,定义ByValByRef中传递的参数将决定参数的值是否在子例程或函数调用之外保持其值。如果我有以下功能:

        Function ThisFByRef(ByRef MyValue)
        End Function
        

        我对函数(或子例程)中的参数所做的任何事情都将在函数完成后保留其值。 ByValByRef 与子例程或函数的范围相关联。传递给ByVal 的任何参数都不会保留在调用的子例程或函数中发生的更改。或者,传递给ByRef 的任何参数都将保留在子例程或函数中更改为的值。返回值只能通过函数而不是子例程完成,并且不会影响传入参数的值,除非参数通过ByRef 并在函数内更改。例如:

        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
        

        【讨论】:

        • 恕我直言,您的回答并没有阐明我的观点,我发现奇怪的是,在调用ThisFValue = ThisByRef(x) 后,x 包含 1,但如果我这样称呼它ThisByRef(x),x 包含 0。相同的功能,相同的参数,但不同的结果!
        【解决方案6】:

        这很简单。当您创建一个函数或子函数时,您可以通过以下方式调用它们:

        对于没有返回值:

        myFunction "This is a reference"
        

        对于返回值:

        myValue = myFunction ("This is a reference")
        

        【讨论】:

          猜你喜欢
          • 2013-03-16
          • 2012-01-21
          • 2011-06-21
          • 2020-06-30
          • 2015-02-15
          • 1970-01-01
          • 1970-01-01
          • 2018-03-11
          • 1970-01-01
          相关资源
          最近更新 更多