管理VBA函数调用中括号使用的规则是什么?

时间:2011-03-24 01:34:48

标签: ms-access vba syntax

我刚刚对VBA(Access 2003)中的“编译器错误”感到恼火30分钟,这是因为我在传递给我定义的Sub的参数周围使用了括号。

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

7 个答案:

答案 0 :(得分:53)

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

因为无法解析。

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

3:   SaveNewValues Value1, Value2, Value3

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

4:   SaveNewValues(Value1, Value2, Value3)

为了避免混淆括号或没有括号(实际上,为了完全避免使用括号规则),对这些调用使用Call关键字总是一个好主意;这确保了过程调用不是该行的唯一语句,因此需要括号:

5:   Call SaveNewValues(Value1, Value2, Value3)

因此,如果您习惯使用Call关键字进行自包含过程调用,则可以忘记括号规则,因为您可以随后将参数括在括号中。

这个问题被括号在VB(A)(和许多其他语言)中扮演的额外角色所困惑:它们还表明了表达式的评估优先级。如果在任何其他上下文中使用括号但包含过程调用参数,VB(A)将尝试将括号中的表达式计算为生成的简单值。

因此,在示例4中,括号对于包含参数是非法的,VB(A)将尝试计算括号中的表达式。由于(Value1,Value 2,Value3)不是可以计算的表达式,因此会出现语法错误。

这也解释了为什么如果参数括在括号中,带有传递给ByRef的变量的调用就像调用ByVal一样。在上面的例子中,使用ByRef参数a调用函数p时,这两个p调用之间存在很大差异:

6:  p a

7:  p(a)

如上所述,6是正确的语法:调用在其行上是单独的,因此不应使用括号来包含参数。

在7中,无论如何,参数都括在括号中,提示VB(A)将包含的表达式计算为一个简单的值。这当然是传递ByVal的定义。括号确保不是指向a的指针,而是传递a的值,并且a保持不变。

这也解释了为什么括号规则似乎并不总是占据主导地位。最明显的例子是MsgBox调用:

8:  MsgBox "Hello World!"

并且

9:  MsgBox ("Hello World!")

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

最后,这解释了奇怪的类型不匹配错误和传递Object参数时的奇怪行为。假设您的应用程序有一个HighlightContent过程,它将TextBox作为参数(并且,您永远不会猜测,突出显示它的内容)。您可以调用它来选择文本框中的所有文本。您可以通过三种语法正确的方式调用此过程:

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

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

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

答案 1 :(得分:22)

来自Here

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

Call MySubroutine

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

Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 

调用函数 调用函数有两种可能的方法。您可以直接通过名称调用函数,也可以使用VBScript调用语句调用它。

按名称调用功能 当直接按名称调用函数并且没有赋值给返回值时,以下所有内容都是合法语法:

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

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

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

答案 2 :(得分:7)

我刚发现一些奇怪的行为,调用带/不带括号的函数。谷歌把我带到了这里。

sub test()
  dim a as double
  a = 1#
  p(a) 'this won't change a's value
  Debug.Print a '1
  p a  ' 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

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

答案 3 :(得分:5)

我只花了10分钟搞清楚“类型不兼容”的异常,同时调用一个Sub,它通过

获取1个参数
CallMe(argument)

事实证明,这是无效的,谷歌搜索引导我到这里,最后

Call CallMe(argument)

CallMe argument

做了这个伎俩。因此,在调用没有call-statement的sub时,不能使用括号,只需要1个参数。

答案 4 :(得分:3)

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

答案 5 :(得分:2)

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

MsgBox "Hello World"

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

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

3 - 如果要将call关键字与过程一起使用,则必须用括号括起参数(例如,当您想要在变量中分配结果或在表达式中使用函数时):

Call MsgBox("Hello World")

4 - 如果要强制ByRef参数(默认值)传递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"

答案 6 :(得分:-1)

我使用另一种逻辑来区分何时使用括号。如果函数不返回值(类 C 语言中的 void 类型),则不需要括号。对于 subs 总是如此,因为返回值是 sub 和 function 之间的主要区别。否则,您必须使用括号。