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

Hor*_*Kol 33 syntax ms-access vba

我刚刚在VBA(Access 2003)中出现了一个令人恼火的30分钟因为我在传递给我定义的Sub的参数周围使用了括号而引起的.

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

小智 55

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

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

1:   If CheckConditions(A, B, C) = DONT_PROCEED Then Exit Sub
Run Code Online (Sandbox Code Playgroud)

是有效的; 对CheckConditions的调用需要括号来指示该行的其他位是其参数.相反,这会产生语法错误:

2:   If CheckConditions A, B, C = DONT_PROCEED Then Exit Sub
Run Code Online (Sandbox Code Playgroud)

因为无法解析.

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

3:   SaveNewValues Value1, Value2, Value3
Run Code Online (Sandbox Code Playgroud)

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

4:   SaveNewValues(Value1, Value2, Value3)
Run Code Online (Sandbox Code Playgroud)

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

5:   Call SaveNewValues(Value1, Value2, Value3)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

6:  p a
Run Code Online (Sandbox Code Playgroud)

7:  p(a)
Run Code Online (Sandbox Code Playgroud)

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

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

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

8:  MsgBox "Hello World!"
Run Code Online (Sandbox Code Playgroud)

9:  MsgBox ("Hello World!")
Run Code Online (Sandbox Code Playgroud)

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

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

10: HighlightContent txtName
11: HighlightContent (txtName)
12: Call HighlightContent(txtName)
Run Code Online (Sandbox Code Playgroud)

假设您的用户已在文本框中输入"John",您的应用程序将调用HighlightContent.会发生什么,哪个电话有效?

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

  • +1是一个很好的答案,但我仍然不同意括号规则是"完全合乎逻辑的"......我无法想象一个简单的方法来处理简单的括号! (15认同)
  • `Call Debug.Print("Hello world")` 仍然会引发错误。这背后的逻辑在哪里? (2认同)
  • @Microsoft,帮自己一个忙,重定向你的 [vba/language/concepts/getting-started/using-parentheses-in-code](https://learn.microsoft.com/en-us/office/vba/language/概念/入门/在代码中使用括号)到这里。 (2认同)

Mit*_*eat 22

这里:

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

Call MySubroutine
Run Code Online (Sandbox Code Playgroud)

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

Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 
Run Code Online (Sandbox Code Playgroud)

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

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

MyFunction
MyFunction()
MyFunction intUsageFee, intTimeInHours, "DevGuru"
Run Code Online (Sandbox Code Playgroud)

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

returnval = MyFunction
returnval = MyFunction()
returnval = MyFunction(intUsageFee, intTimeInHours, "DevGuru") 
Run Code Online (Sandbox Code Playgroud)

  • 谢谢 - 看起来我的问题是因为我的函数没有返回值,但我仍然在我的参数列表中使用括号.这似乎是一个相当奇怪的语法决定...... (10认同)

ale*_*231 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
Run Code Online (Sandbox Code Playgroud)

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

  • 括号确实强制传递一个参数“ByVal”。 (3认同)

met*_*cle 5

我只花了10分钟找出一个"类型不兼容"的异常,同时调用一个带有1个参数的Sub

CallMe(argument)
Run Code Online (Sandbox Code Playgroud)

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

Call CallMe(argument)
Run Code Online (Sandbox Code Playgroud)

要么

CallMe argument
Run Code Online (Sandbox Code Playgroud)

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