一些关于 Dim 和 Set Worksheet 的疑问

4
通常在vba代码中应先进行Dim操作,然后再进行Set操作,就像下面的代码一样。
Dim xWs1 As Worksheet
Dim xWs2 As Worksheet
.
.
.
Dim xWsN As Worksheet
Set xWs1 = Worksheets("A")
Set xWs2 = Worksheets("B")
.
.
.
Set xWsN = Worksheets("NNN")

如果我需要对5个工作表进行 Dim 和 Set 操作,那么就需要写10行代码。当我需要对超过5个工作表进行操作时,代码似乎会变得很长。
我发现如果只使用 Set,vba 代码也可以正常运行。请问如果不使用 Dim 是否会出现任何问题?
Set xWs1 = Worksheets("A")
Set xWs2 = Worksheets("B")
.
.
.
Set xWsN = Worksheets("NNN")

谢谢!


你正在隐式地声明你的变量。这不会破坏你的代码,但如果你拼错一个变量或尝试使用错误的数据类型,那么调试可能会成为噩梦。 - K.Dᴀᴠɪs
@Drager 我可以回答你的问题!请给我几分钟来解释。 - ashleedawg
自行决定,我不会在同一行上进行多个声明,除非我非常懒惰,即使这样也不会超过几个对象! - QHarr
它隐式地将除最后一个之外的所有内容声明为变量。只有最后一个是工作表对象。在Dim中不放置类型=隐式变量。 - QHarr
@Drager,你已经有了一个答案。然而,你没有解释每个工作表上要执行的操作。如果要执行的操作相同,则还可以提供其他替代方案。 - shrivallabha.redij
显示剩余5条评论
3个回答

2
如果您不使用Dim语句,则变量会自动创建为Variant类型。
Variant类型可以是整数、字符串、工作簿或任何其他类型的变量,它可以随着变量的更改而更改,一会儿它可以是一个字符串,然后可以更改为工作簿。
使用Dim语句。

enter image description here

不使用Dim

enter image description here

使用Dim有两个主要问题:
  1. 使用Variant类型会占用更多的计算机内存,这导致在使用循环时代码运行缓慢。
  2. 很难找到错误(例如,在您的情况下,您可以将任何内容分配给变量XWs1,例如数字、名称等等,如果使用dim就可以避免这种情况)。

谢谢。我忽略了内存问题,你为我澄清了一些VBA的基本概念。非常感谢! - Drager

2
如何使用92个字符声明和设置92个对象:
如果“占用空间”是您关心的问题,并且您假设要显式设置5个过程级变量(w1..w5)为Set,以设置5个工作表(Sht1..Sht5),则可以使用以下代码:
示例#1:
DefObj W
Sub wSet1()
  Dim w1, w2, w3, w4, w5
  Set w1=[Sht1]:Set w2=[Sht2]:Set w3=[Sht3]:Set w4=[Sht4]:Set w5=[Sht5]
End Sub

...或者更加节省空间的是,如果你有92个工作表需要在92个声明变量中设置,那么:
示例2:
DefObj W
Sub wSet2():Dim wks(1To 92),x:For x=1To 92:Set wks(x)=Sheets("Sht"&x):Next x:End Sub

这是92个字符……不包括换行符!

说明:

在这两种缩短声明的方式中,我们使用了六个快捷方式。以下是每个快捷方式的摘要,请查看“更多信息”下面的链接以获取有关每个快捷方式的完整文档。

免责声明:我们不应该在编程中使用快捷方式的原因有很多。显而易见的是,代码压缩得越多,阅读和理解就越困难(特别是对于其他人),因此可能更难排除故障或扩展。如果您不知道“标准方法”是什么,请不要先学习快捷方式!无论看起来多么吸引人,都要先学习如何以“正确的方式”完成任务,然后再学习快捷方式。曾经有一段时间,我认为像缩进和注释以及完整的、正确的技术等整洁性并不重要。我错了;我必须通过艰苦的方式学习。如果你正在阅读这篇文章,你可能也需要通过艰苦的方式学习,但至少:在发布问题时不要使用快捷方式示例代码在你的Stack Overflow问题中。(这不是 [MCVE]的方法!)你可能会被嚷嚷!......并可能被贬低或忽视......你已经被警告了!

DefObj (默认数据类型)

[Deftype statements][1] are a forgotten method of declaring default data types.  Normally, the default data type is [`Variant`][2], so this:

Dim myVariable as Variant

"...与以下相同:"
Dim myVariable 

...然而,在模块级别使用的DefObj W语句表示:

在此模块中声明的所有变量以字母'W'开头,默认为类型Object(除非另有规定)。请注意,必须在模块级别(在第一个Sub之前)使用Deftypes语句。

整个列表:(更多信息

DefBool DefByte DefCur DefDate DefDbl DefDec DefInt DefLng DefSng DefStr DefObj DefVar


, (在“Dim”语句中的逗号)

使用Dim声明变量时,可以在同一行上列出多个变量,用逗号分隔。因此,下面这个例子:

Sub mySub()
    Dim myVariable1 as Currency  
    Dim myVariable2 as Currency  
    …

这句话的意思是:“……与此相同:(将示例与Deftypes结合起来)”。
DefCur m
Sub mySub()
    Dim myVariable1, myVariable1 
    …

Sheets (工作表集合)

  • WorkSheets 对象 指的是指定或活动工作簿中所有工作表对象的集合。

  • Charts 对象 指的是指定或活动工作簿中所有图表对象的集合。

    • 但是,Sheets 对象则同时包含WorksheetsCharts 集合。

因此,在 VBA 中,如果一个工作簿有3 个工作表和 2 个图表工作表

  • Sheets.Count 将返回 5

  • Worksheets.Count 将返回 3

警告:如果您同时拥有一个图表和一个工作表具有相同的名称(并且在引用其他文件中的工作表时也应避免使用),则使用Sheets可能会导致冲突。但对于仅包含工作表的简单单个文件,为了节省一些Work,请坚持使用Sheets

[ ] (方括号引用快捷键)

在引用工作表单元格范围单个单元格时,可以使用方括号作为快捷方式。您可以使用A1引用样式命名范围作为范围属性的快捷方式。您不必键入“Range”一词或使用引号。

Worksheets("Sheet1").[A1:B5].ClearContents 

[MyRange].Value = 30 

这几乎没有记录,甚至更少的记录是,如果按照逻辑顺序使用,方括号可以用于引用工作表。
结合示例,所有这些语句将具有相同的结果:
Worksheets("Sheet1").Range("A1") = Now()
Sheets("Sheet1").Range("A1") = Now()
Worksheets("Sheet1").[A1] = Now()
Sheets("Sheet1").[A1] = Now()
[Sheet1].[A1] = Now()

wks() (变量数组)

如果您要声明大量相似的对象,则通常更容易(并且更有组织)将它们分组在数组中。 数组可以声明为任何类型,例如Object、Worksheet等。(……或者甚至是很少使用和奇怪的类型,如LongLongIConverterApplicationPreferences。(显然,想出这个想法的人不喜欢捷径。)


For..Set..Next (循环设置变量数组)

当使用对象数组(任何变量集)时,下一个逻辑步骤是通过任何需要在整个对象组上执行的任务来减少代码。


其他注释:

示例#1本可以压缩成一行,但我希望答案易于阅读。如果我们的工作表名称是S1..S5而不是如此冗长的Sht1..Sht5并且我们使用:,我们可以在105个字符内完成同样的事情:

示例#1b:

DefObj W
Sub wSet():Dim w1,w2,w3,w4,w5:Set w1=[S1]:Set w2=[S2]:Set w3=[S3]:Set w4=[S4]:Set w5=[S5]:End Sub

数据类型快捷符号

另一组很少使用的数据类型快捷方式可以追溯到1974年:这些快捷方式是由Gary Kildall为CP/M操作系统选择的。

符号  数据类型  常量

%       Integer    vbInteger = 2
$       String     vbString = 8
&       Long       vbLong = 3
@       Decimal    vbDecimal = 6
!       Single     vbSingle = 4
#       Double     vbDouble = 5

今天在许多编程语言中仍然得到支持,例如,您可以交替使用它们:
Dim myVariable as String
Dim myVariable$

更多信息:

哦,非常详细的解释。非常感谢。我只有一个问题,你在代码中使用Dim ... As Variant。使用Dim ... As Worksheet不是更好的内存分配吗?另外,感谢您教我DefObj,这是我没有学过的。其他的东西,我认为我知道你说的,比如[Sht1](Evaluate),wks()(Array),For..Set..Next(For循环)和Sheets(Object)。 - Drager
@ashleedawg,你写道:“如果你有一个名字相同的图表和工作表”,但这真的可能吗?我现在没有电脑来测试它,但我似乎记得这是不可能的。 - DisplayName

1

接下来举一个例子说明为什么使用隐式变量声明通常是一个不好的想法:

Sub Test()

    myVariable = 10

    myOutcome = myVaraible + 5

End Test

myOutcome = 5。你能看出为什么吗?

我在第二行中拼错了myVariable,因此实际上创建了一个全新的变量myVaraible(默认值为0)。

这就是为什么您应该始终在每个模块的开头使用Option Explicit以及始终明确声明所有变量的原因。

虽然它仍然可以工作,但您只是为自己设置了不必要的调试问题。


如果您的问题是想要压缩代码以使用更少的行,您可以像这样做:
Option Explicit

Sub Test()

    Dim myVariable As Long:    myVariable = 10
    Dim myOutput As Long
    myOutput = myVariable + 5

End Sub

你可以在同一行上声明多个变量:
Option Explicit

Sub Test()

    Dim myVariable As Long, myOutput As Long
    myVariable = 10
    myOutput = myVariable + 5

End Sub

并不一定推荐这种做法(因为它可能会降低可读性),但这是另一种声明变量的方法。这确实需要相同的数据类型,但你可以将工作表添加到数组中(从你的示例中):

Option Explicit

Sub Test()

    Dim xWs(1 To 5) As Worksheet

    Set xWs(1) = Worksheets("A")
    Set xWs(2) = Worksheets("B")
    Set xWs(3) = Worksheets("C")
    Set xWs(4) = Worksheets("D")
    Set xWs(5) = Worksheets("E")

End Sub

我知道这一点,但如果我只是使用Set,例如Set xWs = Worksheets("A"),Set xWs2 = Worksheets("B"),xWs.cells(1,1).value = xWs2.cells(1,1).value。没有发生错误,代码也可以正常运行。因此,我怀疑是否可以不使用Dim来设置工作表。 - Drager
@Drager 这就是我的意思。你_不必_使用Dim(声明变量)。但这样做会增加打字错误的风险。这也是为什么Dim存在的全部原因,只是为了防止您在使用Option Explicit时意外使用xWss1而不是xWs1,因为Excel会通知您在使用未声明的变量。它还可以防止您尝试使用与声明的数据类型不符的类型。 - K.Dᴀᴠɪs
简而言之,“Dim”存在作为“安全特性”,而不是要求。 - K.Dᴀᴠɪs
哦,谢谢。原本我想只使用Set来缩短代码行。但是在阅读了你的评论后,发现仅使用Set在使用Option Explicit时无法运行。似乎使用Dim更安全,可以避免错误。 - Drager
Dim 也可以确保您声明类型,以便为要处理的对象分配正确的内存分配。 - QHarr
@QHarr 非常好的观点。对于小项目来说不算太大的问题,但在一般编程中,内存分配非常重要。 - K.Dᴀᴠɪs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接