【问题标题】:ByVal vs ByRef VBAByVal 与 ByRef VBA
【发布时间】:2017-10-26 17:00:51
【问题描述】:

我尝试过 JaredPar ByRef vs ByVal Clarification 回答的问题

ByVal 在 VB.NET 中表示将发送所提供值的副本 到功能。对于值类型(IntegerSingle 等),这将 提供值的浅拷贝。对于更大的类型,这可以是 效率低下。对于引用类型(String,类实例) 引用的副本被传递。因为在突变中传递了一个副本 通过= 传递给参数,调用函数将看不到它。

ByRef 在 VB.NET 中意味着对原始值的引用将是 发送到函数(1)。这几乎就像原始价值一样 直接在函数中使用。像= 这样的操作会影响 原始值并在调用函数中立即可见。

我已经尝试使用以下代码对其进行测试,但我似乎无法让它工作使用ByRef 将单元格的值更改为0,如果它是1

这是我正在测试的以下代码,我做错了什么? Range("A1")的值还是1

Sub test1()

    Dim trythis As Boolean

    trythis = False

    If (Sheets("TESTING").Range("A1").value = 1) Then
        testingRoutine (trythis)
        If (trythis) Then
            Debug.Print "Value changed to 0"
            Sheets("TESTING").Range("A1").value = 0
        End If
    End If

End Sub

Private Function testingRoutine(ByRef trythis As Boolean)

    Debug.Print "Ran Function"
    trythis = True

End Function

【问题讨论】:

  • 悲伤..这一切都在 Documentation.SO 中得到了彻底的记录——现在已经不复存在了。如果您不放弃这种习惯,那么您对多余括号的使用将在某一天或另一天咬到您@$$。此外,Function 过程应该有一个返回类型 - Private Function testingRoutine(ByRef tryThis As Boolean) As Boolean - 否则你会将返回值包装到 Variant 中。请注意,在 VBA 中,隐式默认值为 ByRef(这很愚蠢,这就是 VB.NET 修复它的原因)。请参阅 this answer 了解更多 ByRef/ByVal 涉及数组的疯狂。
  • @Mat'sMug 感谢您提供信息;如果我不打算用函数返回值,我应该使用什么?那么是潜艇吗?
  • 是的。 Function 接受一些输入并返回结果Sub 做某事,通常带有副作用(对象、应用程序或全局状态的更改)。
  • 我觉得烦人的是每次我去查看我的宏列表时,每个子功能都在这里列出......有没有办法避免这种情况?
  • 这是非常有用的信息,非常感谢!我只是进行了很多试验和错误,看看哪些有效,哪些无效。如果您可以将此信息放在答案格式中,我很乐意为您提供已回答的标记:)

标签: excel vba


【解决方案1】:

VB 子例程不需要在参数列表周围加上大括号。但是,如果您传递单个参数并将其括在大括号中,则您传递的是 expression 。表达式不能通过引用传递。他们被评估并且他们的结果被通过。因此,您必须删除调用testingRoutine (trythis) 中的大括号并写入testingRoutine trythis

注意:如果你调用一个函数而不使用它的返回值,它必须写成一个过程调用(参数列表周围没有大括号)。举个例子:

myVal = myFunction (trythis)   ' trythis will be passed by reference
myFunction (trythis)           ' trythis will be seen as an expression
myFunction trythis             ' trythis will be passed by reference

myVal = mySub (trythis)        ' invalid: mySub is not a function
mySub (trythis)                ' trythis will be seen as an expression
mySub trythis                  ' trythis will be passed by reference

当然,当一个函数或子函数有多个参数时,问题会立即清楚,因为逗号不能出现在表达式中。

【讨论】:

  • 有个误解,OP的testingRoutine不是sub,而是function。
  • 这太好了,谢谢!现在更有意义了:)
【解决方案2】:

改变这个:

testingRoutine (trythis)

对此:

testingRoutine trythis

那就试试吧。

另外,看看如果我把它改成这个会发生什么,函数被用作函数(返回一些东西)

Sub test1()

    Dim trythis As Boolean
    Dim testit As Boolean

    trythis = False

    If (Sheets("Sheet1").Range("A1").Value = 1) Then
        testit = testingRoutine(trythis)
        If (trythis) Then
            Debug.Print "Value changed to 0"
            Sheets("TESTING").Range("A1").Value = 0
        End If
    End If

End Sub

Private Function testingRoutine(ByRef trythis As Boolean) As Boolean

    Debug.Print "Ran Function"
    trythis = True

End Function

【讨论】:

  • 那为什么有效呢?但是() 不是吗?
  • 带括号意味着它正在尝试返回一个值,但没有变量可以分配给它。没有括号意味着它只是执行请求的功能而不试图返回任何东西。
  • 非常有趣...感谢您对我的问题的帮助,它确实回答了我做错了什么,但我想知道为什么。 Paul Ogilvie 能够更彻底地回答我的问题,所以我把答案检查给了他!对不起:(
  • 不,这很酷 - 我不介意。他的回答更好,我只是更快。 :P
【解决方案3】:

我会这样做。

Sub test1()

    Dim trythis As Boolean

    trythis = False

    If (Sheets("TESTING").Range("A1").value = 1) Then
        tr = testingRoutine(trythis)
        If tr Then
            Debug.Print "Value changed to 0"
            Sheets("TESTING").Range("A1").value = 0
        End If
    End If

End Sub

Private Function testingRoutine(ByRef trythis As Boolean)

    Debug.Print "Ran Function"
    testingRoutine = True

End Function

因为trythis 不是全局变量,所以在函数中更改它不会在子中执行任何操作。它只会在函数中将 trythis 定义为 True 并保持在该范围内。要让 trythis 受函数影响并被子读取,您必须将其分配给子内的变量。

【讨论】:

    【解决方案4】:

    我不记得我在哪里读到的,但我知道如果在调用子/函数时将括号 () 添加到参数中,这是微软为解决 byref 调用而实施的一种特定(不是错误)方式(到byval)。

    示例:假设您调用了一个只有 byref 和 2 个参数的子:

    call Sub1 (a), (b)

    是强制Byvalarguments 的正确方法,即使它们最初被编码为Byval

    【讨论】:

    • Paul Ogilvie 已经为我回答了这个问题并解释了为什么会这样
    猜你喜欢
    • 2018-03-11
    • 1970-01-01
    • 2015-02-15
    • 2013-03-16
    • 2012-01-21
    • 1970-01-01
    • 2020-06-30
    • 2011-06-21
    • 1970-01-01
    相关资源
    最近更新 更多