在不同子区域中使用全局变量和局部变量

时间:2019-05-09 07:12:51

标签: excel vba powerpoint

我正在使用VBA将粘贴内容从Excel复制到PowerPoint。它正在工作,但是我需要清理代码。问题是我不知道在多个过程中使用的变量(或对象)有什么好的做法。我认为我在这方面缺乏一些基本的了解。

  1. 将变量从一个过程传递到另一个过程时,在两个过程中使用相同的名称是一个坏主意吗?例如

    Sub 1()
        Dim a As Long, b As Long
        Call Sub2(a, b)
        '...
    End Sub
    
    Sub2(a As Long, b As Long)
        '...
    End Sub
    

    Sub2是否应以不同的方式调用变量,例如x和y?如果没有,我将回到问题1):将这些变量直接从Sub1传递到Sub2而不在全局进行声明的原因是什么?当我打算在调用a之后使用b中的Sub1Sub2的原始值时得到它(因此基本上将它作为ByVal传递给{{ 1}}),但我的情况并非如此。

  2. 是否有理由限制全局变量的使用?我在代码中将其保留为本地,但是应该全局定义Sub2lRowAn等吗?

  3. 何时应将变量从子变量传递给另一个?在下面的代码中,用lRowData做到这一点对我来说很有意义,但对iSlides而言却没有意义。

    以下是我的实际代码的一部分。子wsEmEmData非常相似,我将看看是否可以合并它们,但是它们很好地说明了我的问题,因为它们使用了许多相同的变量。

    EmDataAn

这与代码功能无关,而是在一般情况下如何使用变量。

2 个答案:

答案 0 :(得分:3)

局部变量

首先,将每个变量声明为局部变量。例如,如果仅在一个过程/函数中需要它,则在那里声明它。

局部变量(作为参数传递)

如果您需要通过多个过程/函数访问变量,则最好将其作为参数传递给下一个函数。可以ByRef(默认)或ByVal来完成。

Sub ProcedureA()
    Dim ParamA As String
    ParamA = "AAA"
    Dim ParamB As String
    ParamB = "BBB"

    ProcedureB ParamA, ParamB

    Debug.Print ParamA 'returns 111
    Debug.Print ParamB 'returns BBB
End Sub

Sub ProcedureB(ByRef Param1 As String, ByVal Param2 As String)
    Param1 = "111" 'this will change ParamA in ProcedureA too
    Param2 = "222" 'this value will only be changed in ProcedureB
End Sub

虽然使用ByRef(通过引用)可以更改ProcedureB中的参数,也可以在ProcedureA中对其进行更改,但是传递的参数ByVal (按值)在ProcedureA中保持不变。

如果您以不同的方式命名变量或使用相同的名称,从技术上讲,这没有什么区别。最好在每个过程中使用最有意义的名称(请参见下面的标题变量名称)。

实际上,我认为始终指定它是ByRef还是ByVal而不使用默认值也是一种好习惯。使用默认值时,您始终必须记住,在VBA中默认值是ByRef,但在VB.NET中默认值是ByVal,这很容易引起混淆(至少是我)。

ProcedureA结束后,变量不再可用(数据丢失)。

全局变量

如果您希望数据具有持久性并且可以通过多个函数进行访问,请使用全局变量(尽可能少使用)。

Dim GlobalVarA As String

Sub ProcedureA()
    GlobalVarA = "AAA"
End Sub

Sub ProcedureB()
    Debug.Print GlobalVarA 'return AAA (if ProcedureA was run before)
End Sub

请注意,在这种情况下,任何过程都可以更改GlobalVarA的值。如果如上所述将其作为参数传递,则只有将变量传递给的过程才能访问该变量。

Excel VBA结束(或文件关闭)时,全局变量将丢失其数据。

在过程中使用全局变量的缺点是,您始终需要在首次使用它之前检查它的值。因为如果尚未初始化,它是EmptyNothing。例如(上),在运行ProcedureB时,您不能依靠ProcedureA已经运行过。因此,在GlobalVarA中使用ProcedureB之前,您需要检查Nothing的值,特别是如果它是一个对象,则必须测试是否不发声Dim VarA As String 'global Sub ProcedureA() Dim VarA As String 'same name local VarA = "AAA" 'this uses always the local variable! End Sub Sub ProcedureB() Debug.Print VarA 'this uses the global variable and it is empty (after ProcedureA is run) End Sub ,否则很容易出错。

本地与全球

因此我们可以总结一下,尽可能限制对变量的访问将使您的代码更安全,更可靠(如果仅在本地声明,则其他任何函数都不会意外更改它)。仅在确实需要时使用全局变量。

重新使用变量名

如果在本地声明变量名,那么重用变量名通常是没有问题的。但是,如果您对全局变量和局部变量使用相同的名称,则会变得很棘手(然后VBA会首选局部变量!)

rng1

通常,仅使用有意义的变量名是一个很好的做法。这意味着要调用变量rng2InputRange,而不是调用变量OutputRangei。另外,如果您需要计数器(例如遍历行和列),通常会使用jiRow,但是如果使用例如iCol和{{1} }作为变量名。

显式选项

为了强制执行正确的变量声明,我建议始终激活Option Explicit:在VBA编辑器中,转到工具选项 { {3}} 。这样可以防止您错误键入变量名称并意外引入新变量。

答案 1 :(得分:1)

1) When passing a variable from one procedure to another, is it a bad idea to use the same name in both procedures?

有两种方法可以将参数传递到另一个过程ByValByRef

默认情况下,VBA使用ByRef,所以这样做:

Option Explicit
Sub Test()

    Dim i As Long

    For i = 0 To 1000
        Call Tested(i)
    Next i

End Sub
Sub Tested(i As Long)

    i = i + 1

End Sub

将使您发疯,因为从第一个循环起,i = 0将跳到i = 2。为什么?因为Tested()将1加到i上,而Next i中的Test()又加上一个。

如何避免这种情况并且仍然使用相同的变量?使用ByVal,以便为Tested()赋予i的值,并且对Tested()进行的更改不会影响您的初始循环。

全局变量?尽可能不要使用它们。

何时根据我的经验使用它们?

例如,在工作簿中使用许多工作表以及将调用它们的不同过程,然后只需对所有工作表进行子设置并将其声明为全局。

其他情况下,我认为没有必要,因为像QHarr所说的那样,对于优化将参数传递给过程的速度更快。