我的目标是使用一组名称在VBA中创建动态变量,以下是代码:
Sub mymacro()
Dim names()
names = Array("cat_code()", "dog_code()", "eagle_code()")
For Each c In names
Dim c As Integer
Next
end sub
当然,我的真实姓名阵列中有数百只动物,因此对于每一个动物来说Dim
都很无聊。我得到的错误是Compile Error: Duplicate declaration in current scope
我目标的最佳可行解决方案是什么?
答案 0 :(得分:6)
您获得的编译错误是由当前作用域中的重复声明引起的。
换句话说:这意味着您要声明多个具有相同名称的变量。
在模块顶部添加Option Explicit
语句需要您声明您使用的每个变量。当您收到此错误时非常有用,因为您可以快速扫描代码,以便重复声明突出显示的行Dim <variable_name>
这是一个示例,说明您收到错误的原因:
Option Explicit
Sub Main()
Dim c As Worksheet
For Each c In Sheets
Dim c As Long ' you are going to get an error in here because
' a variable named: c, is already declared within the sub
' you can't have two variables named: c.
For c = 1 To ws.Range("A" & Rows.Count).End(xlUp).Row
' some code
Next c
Next
End Sub
解决问题并不容易。如果您能更好地解释您想要实现的目标,我们本来能够为您的问题提供更好的解决方案。
有一种解决方法可以达到你想要的效果但我不建议你这样做,如果你不确定你实际上在做什么;)。以下代码将在您当前的VBA项目中创建一个新模块。在使用动物名称迭代数组时,它将向Module2
写入新行,因此在执行之后,您的模块二将是
为了使此代码有效,您必须在VBE窗口中添加对Microsoft Visual Basic for Applications Extensibility 5.3". You can do that by selecting
工具>>
引用`的引用。
此外,这需要您Trust Access to VBA Project Object Model
。转到Excel设置&gt;&gt;信任中心&gt;&gt;宏&gt;&gt; tick信任访问VBA项目对象模型。
运行示例代码。
Option Explicit
' this VBA project requires
' 1 - references to Microsoft Visual Basic For Applications Extensibility 5.3
' add it via Tools > References
'
' 2 - trust access to VBA project object model
' In spreadsheet view go to Excel(application options) >> Trust Centre >> Macro Settings
' tick the Trust Access to VBA project object model
Sub mymacro()
Dim names
names = Array("cat_code", "dog_code", "eagle_code")
Dim c As Variant
AddAModule
For Each c In names
' dynamically create arrays
WriteToModule CStr(c)
Next
CloseModule
End Sub
Private Sub AddAModule()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.vbComponent
Dim CodeMod As VBIDE.CodeModule
Set VBProj = ThisWorkbook.VBProject
Set VBComp = VBProj.VBComponents.Add(vbext_ct_StdModule)
Set CodeMod = VBComp.CodeModule
With CodeMod
.DeleteLines 1, .CountOfLines
.InsertLines 1, "Public Sub DynamicallyCreatedArrays()"
.InsertLines 2, " ' code for the sub"
End With
End Sub
Private Sub WriteToModule(arrayName As String)
With ActiveWorkbook.VBProject.VBComponents("Module2").CodeModule
.InsertLines .CountOfLines + 2, " Dim " & arrayName & " as Variant"
End With
End Sub
Private Sub CloseModule()
With ActiveWorkbook.VBProject.VBComponents("Module2").CodeModule
.InsertLines .CountOfLines + 2, "End Sub"
End With
End Sub
答案 1 :(得分:6)
如何使用VBA Collection
对象呢?您需要创建一个简单的类来保存数字,因为VBA集合使用引用而不是值。
所以我创建了一个类,并将其名称设置为“AnimalCounter
”,其内容为:
Public Counter As Integer
然后你的宏会变成这样:
Sub mymacro()
Dim coll As New Collection
Dim c As Variant
Dim ac As AnimalCounter
For Each c In Array("cat", "dog", "eagle")
Set ac = New AnimalCounter
coll.Add ac, c
Next
Debug.Print coll("cat").Counter ' what's in "cat"?
coll("dog").Counter = coll("dog").Counter + 1 ' update "dog" by one
Debug.Print coll("dog").Counter ' "dog" should now be one more
End Sub
如果您想要数组,请将数组放入类中。或者另一个Collection
,也许?
答案 2 :(得分:4)
Mike Woodhouse有正确的想法使用Collection
与动物的钥匙。我添加了两个注释:
首先,我建议改用Dictionary
。它比Collection
更快,并允许显式访问Keys
和Items
集合。使用Collection
,实际上无法获取密钥,因为基本目的是项目的有序列表,而不是与Dictionary
一样的与订单无关的哈希
对于早期绑定使用Dictionary
类型,请添加对Microsoft Scripting Runtime的引用。
其次,不要为个体动物使用阵列!。原因是因为VBA中的数组使用按值语义(有关详细信息,请参阅Collections in VBA – Overview,Values and References in VBA,Array Assignment Rules。简而言之,每次从包含Collection
或Dictionary
的数组中获取数组实例时,您将获得整个数组的新副本。因此,您对该数组内容所做的任何更改都不会影响Dictionary
或Collection
中的实际数组。要解决此问题,请改用Collection
。这将使用by-reference语义,并使附加新项更容易。
所以这就是你想要做的事情:
Sub ReadCodes()
Dim ws As Worksheet
Dim strAnimalName As String
Dim dctAnimalCodes As New Dictionary
Dim colAnimalCodes As Collection
Dim lngAnimalCode As Long
Set ws = Worksheets("Animal Code Data")
For iRow = 1 To ws.UsedRange.Rows.Count
strAnimalName = ws.Cells(iRow, 1)
lngAnimalCode = ws.Cells(iRow, 2)
' Easy to check if key exists
If Not dctAnimalCodes.Exists(strAnimalName) Then
Set dctAnimalCodes(strAnimalName) = New Collection
End If
' Getting the collection for this animal
Set colAnimalCodes = dctAnimalCodes(strAnimalName)
' Easy appending of new code
colAnimalCodes.Add lngAnimalCode
Next
End Sub