用函数改变多个值的最佳方法

时间:2017-08-18 08:37:36

标签: vba excel-vba function excel

VBA中的函数至少只能返回1 thing 。那个东西可能包含多个值,但它仍然是1个包。

我想创建一个Sub / Function,它对多于1个变量的值有影响。据我所知,这有三种方法:

1。声明调用者子

之外的变量
Private val1 As Long, val2 As Long
Sub Caller()
    val1 = 1
    val2 = 2
    valueChanger
    Debug.Print val1 + val2         'Prints 5
End Sub

Sub valueChanger()                  'no need to pass any values, but could pass both byVal
    val1 = val1 + 1
    val2 = val2 + 1
End Sub

2。通过byRef

Sub Caller()
    Dim val1 As Long, val2 As Long
    val1 = 1
    val2 = 2
    valueChanger val1, val2
    Debug.Print val1 + val2                      'Prints 5
End Sub

Sub valueChanger(ByRef value1 As Long, ByRef value2 As Long)
    value1 = value1 + 1
    value2 = value2 + 1
End Sub

3。返回单个"数据包"

Sub Caller()
    Dim val1 As Long, val2 As Long, results() As Long
    val1 = 1
    val2 = 2
    results = valueChanger(val1, val2)
    Debug.Print results(1) + results(2)          'Prints 5
End Sub

Function valueChanger(ByVal value1 As Long, ByVal value2 As Long) As Long() 'return an array, could equally return a collection or even a string
    Dim resultVals(1 To 2) As Long
    resultVals(1) = value1 + 1
    resultVals(2) = value2 + 1
    valueChanger = resultVals
End Function

我可以看到选项3可能是最独立的,选项1可能是最不重要的。选项3可能是最耗费内存的,也需要将结果分散得相当混乱。

我个人认为选项2是一个中间立场,我认为只要你知道byRef 的风险,因为你正在输入例行程序,一旦'完成之后,您可以基本忘记它,因为变量在代码中的其他任何地方都不会显示 - 与选项1不同。

但我错过了什么吗?我应该遵循这些标准实践中的任何一种方法吗?

2 个答案:

答案 0 :(得分:1)

您的第三种方法在概念上最简单,因此可能更容易调试(并且首先不太可能需要调试)。您可以简化机制:

1)只需使用Variant将数组传递给函数

2)使用Array()打包返回信息

3)编写一个与Array()相反的子,一个可以将数组解包到提供的变量列表中的子句(隐式使用VBA的默认byRef语义:

Sub UnPack(A As Variant, ParamArray Vars() As Variant)
    'A is a 0-based array of the same length as Vars
    'The elements of A are assigned to the variables in Vars
    Dim i As Long
    For i = 0 To UBound(Vars)
        Vars(i) = A(i)
    Next i
End Sub

然后你的valueChanger()就可以了:

Function valueChanger(ByVal value1 As Long, ByVal value2 As Long) As Variant
    valueChanger = Array(value1 + 1, value2 + 1)
End Function

用过:

Sub Caller()
    Dim val1 As Long, val2 As Long, results As Variant
    val1 = 1
    val2 = 2
    results = valueChanger(val1, val2)
    UnPack results, val1, val2
    Debug.Print val1 + val2          'Prints 5
End Sub

甚至只是:

Sub Caller()
    Dim val1 As Long, val2 As Long
    val1 = 1
    val2 = 2
    UnPack valueChanger(val1, val2), val1, val2
    Debug.Print val1 + val2          'Prints 5
End Sub

或者,您可以通过扩展“数据包”的含义来实现方法3。当某些意义上的值一起出现时,通常只有从函数返回多个值才有意义。这表明将这些值包装在类型甚至类中是很自然的:

'at top of module:
Type Pair
    val1 As Long
    val2 As Long
End Type

然后:

Function valueChanger(p As Pair) As Pair 'can't pass a user-defined type ByVal
    Dim q As Pair
    q.val1 = p.val1 + 1
    q.val2 = p.val2 + 1
    valueChanger = q
End Function

用过:

Sub Caller()
    Dim p As Pair
    p.val1 = 1
    p.val2 = 2
    p = valueChanger(p)
    Debug.Print p.val1 + p.val2          'Prints 5
End Sub

答案 1 :(得分:0)

第一个代码将值传递给Module Level Variables。因此可以从该模块的任何过程访问它。

第二个ByR​​ef会改变变量的值。

第3个ByVal不会更改变量的值,只会从变量中获取值。

所有这些都是根据编程需要使用的。

希望它清楚。