VBA函数调用中括号用法的规则是什么?

我刚刚在VBA(Access 2003)的“编译器错误”中引起了一个恼人的30分钟,这是由于我使用括号来传递给我定义的参数。

我一直在寻找一个体面的文章/教程/指示,何时括号是必要/适当/不适当/禁止,但找不到任何明确的指导方针。

从这里 :

使用VBScript调用语句调用子例程当您希望调用子例程时,使用Call语句是可选的。 与Sub一起使用时,Call语句的目的是允许您将参数列表括在括号内。 但是,如果子例程不传递任何参数,那么在使用Call语句调用Sub时,您仍然不应该使用括号。

Call MySubroutine 

如果子程序有参数,则在使用Call语句时必须使用括号。 如果有多个参数,则必须用逗号分隔参数。

 Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 

调用函数有两种可能的方法来调用一个函数。 您可以直接调用函数,也可以使用VBScript调用语句来调用函数。

按名称调用函数按名称直接调用函数时,如果没有赋值给返回值,则以下所有内容都是合法语法:

 MyFunction MyFunction() MyFunction intUsageFee, intTimeInHours, "DevGuru" 

如果你想要一个返回值,你可以将该函数分配给一个variables。 请注意,如果有一个或多个参数,则必须使用括号。

 returnval = MyFunction returnval = MyFunction() returnval = MyFunction(intUsageFee, intTimeInHours, "DevGuru") 

VB(A)中的圆括号规则有完美的逻辑,就是这样。

如果使用参数调用过程(函数或子),并且调用与其他语句或关键字一致,则参数必须括在括号中。 这是为了区分属于过程调用的参数和其余行。 所以:

 1: If CheckConditions(A, B, C) = DONT_PROCEED Then Exit Sub 

是一条有效的路线; 对CheckConditions的调用需要括号来表示该行的其他位是它的参数。 相反,这会产生一个语法错误:

 2: If CheckConditions A, B, C = DONT_PROCEED Then Exit Sub 

因为不可能parsing。

将过程调用作为唯一的语句,不需要括号,因为很明显参数属于过程调用:

 3: SaveNewValues Value1, Value2, Value3 

虽然这会导致语法错误(出于下面讨论的合理原因):

 4: SaveNewValues(Value1, Value2, Value3) 

为了避免混淆括号或者不使用括号(事实上,为了完全避免括号规则),对这样的调用使用Call关键字总是一个好主意; 确保程序调用不是唯一的声明,因此需要括号:

 5: Call SaveNewValues(Value1, Value2, Value3) 

因此,如果您习惯使用Call关键字进行自包含的过程调用,则可以忘记括号规则,因为您可以始终将括号括起来。

这个问题被VB(A)(和其他许多语言)中的额外的angular色括号所困扰,它们也表示评价expression的优先级。 如果在任何其他上下文中使用圆括号,而是包含过程调用参数,则VB(A)将尝试将括号中的expression式计算为生成的简单值。

因此,在示例4中,括号参数的括号是非法的,VB(A)将改为尝试评估括号中的expression式。 由于(值1,值2,值3)不是可以评估的expression式,因此会出现语法错误。

这也解释了为什么使用ByRef传递的variables的调用,如果参数被括在圆括号中,就像调用ByVal一样。 在上面的例子中,用ByRef参数a调用函数p,这两个调用p:

 6: pa 

 7: p(a) 

正如上面所讨论的,6是正确的语法:调用是独立的,所以括号不应该被用来包围参数。

在7中,无论如何都将括号括在括号内,促使VB(A)将封闭的expression式评估为一个简单的值。 这当然是通过ByVal的定义。 圆括号确保不是指向a的指针,而是传递a的值,并且不修改a。

这也解释了为什么括号规则似乎并不总是摇摆不定。 最清晰的例子是一个MsgBox调用:

 8: MsgBox "Hello World!" 

 9: MsgBox ("Hello World!") 

即使括号规定9应该是错的,两者都是正确的。 当然,这是所有事情发生的是VB(A)评估括号中的expression式。 并且string文字的计算结果与完全相同的string文字相同,因此实际调用的值是8.换句话说:对具有常量或string文字参数的单参数过程的调用具有相同的结果,有或没有括号。 (这就是为什么即使我的MsgBox调用前面有Call关键字。)

最后,这解释了在传递Object参数时奇怪的types不匹配错误和奇怪的行为。 比方说,你的应用程序有一个HighlightContent过程,它将一个TextBox作为参数(并且,你永远不会猜测,高亮显示它的内容)。 您可以调用它来select文本框中的所有文本。 你可以用三种语法正确的方式调用这个过程:

 10: HighlightContent txtName 11: HighlightContent (txtName) 12: Call HighlightContent(txtName) 

假设您的用户在文本框中input了“John”,并且您的应用程序调用了HighlightContent。 会发生什么,哪个电话会起作用?

10和12是正确的; John的名字将在文本框中突出显示。 但11在语法上是正确的,但会导致编译或运行时错误。 为什么? 因为括号不合适 这将提示VB(A)尝试评估括号中的expression式。 对象的评估结果通常是其默认属性的值; .Text,在这种情况下。 所以调用像11这样的过程不会将TextBox对象传递给过程,而是一个string值“John”。 导致types不匹配。

我只是发现一些奇怪的行为调用一个函数有/无括号。 Google把我带到了这里。

 sub test() dim a as double a = 1# p(a) 'this won't change a's value Debug.Print a '1 pa ' this is expected behavior Debug.Print a '2 Call p(a) 'this is also valid Debug.Print a '3 end sub Function p(a as Double) 'default is byref a = a + 1 end function 

我的结论是,你必须使用调用或省略括号只有一个参数调用一个函数,否则该参数不被引用传递(它仍然被调用,因为我已经检查)。

我只花了10分钟搞清楚“types不兼容”的exception,同时调用一个通过1参数的子

 CallMe(argument) 

事实certificate,这是无效的,谷歌search导致我在这里,最后

 Call CallMe(argument) 

要么

 CallMe argument 

做的伎俩。 所以当调用一个没有只带1个参数的调用语句的时候,你不能使用括号。

当您使用Call MySub您应该在参数周围使用括号,但是如果您省略Call,则不需要括号。

1 – 默认情况下,在调用过程或函数时不要使用括号:

 MsgBox "Hello World" 

2 – 如果你正在调用一个函数,并且对结果感兴趣,那么你必须用圆括号括住它的参数:

 Dim s As String Dim l As Long s = "Hello World" l = Len(s) 

3 – 如果你想在过程中使用call关键字,那么你必须用括号括起参数(例如,当你想把结果赋给一个variables或者在expression式中使用该函数):

 Call MsgBox("Hello World") 

4 – 如果要强制传递ByVal参数(缺省值)以传递ByVal,请将ByRef参数用括号括起来:

 Sub Test Dim text As String text = "Hello World" ChangeArgument((text)) MsgBox text End Sub Sub ChangeArgument(ByRef s As String) s = "Changed" End Sub 

这显示“Hello World”