2011-03-24 230 views
27

我刚刚在VBA(Access 2003)的“编译器错误”中引发了一个令人讨厌的30分钟,这是由于我使用括号传递给我定义的子参数。关于在VBA函数调用中使用括号的规则是什么?

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

+2

这里的我对这个话题最喜欢的职位:http://dailydoseofexcel.com/archives/2012/05/01/quick-vba-tip-parentheses/ – 2014-12-13 15:03:34

回答

21

Here

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

Call MySubroutine 

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

Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 

调用函数 有两种可能的方式来调用一个函数。您可以直接通过名称直接调用该函数,也可以使用VBScript Call语句调用该函数。

通过名称调用 一种功能,当通过名称直接调用的函数,当没有分配到一个返回值,以下所有的都是合法的语法:

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

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

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

感谢 - 它看起来像我的问题是,因为我的函数没有返回值,但我仍然在我的参数列表中使用括号。这似乎是一个相当奇怪的语法决定... – HorusKol 2011-03-24 02:44:32

3

当您使用 Call MySub你应该使用周围参数的括号,但如果忽略呼叫,你不需要括号。

5

我只花了10分钟找出一个“类型不兼容”的异常而调用子这需要通过

CallMe(argument) 

1个参数事实证明,这是无效的,谷歌搜索导致我在这里终于

Call CallMe(argument) 

CallMe argument 

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

+0

+ _1为子名称 – 2017-01-15 17:17:52

7

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

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 

我的结论是,你可以选择使用电话或拨打电话时的功能只有一个参数,否则该参数不通过引用传递(它仍然被调用,因为我查的话)省略圆括号。

+0

括号确实强制参数传递'ByVal'。 – RubberDuck 2015-03-31 17:05:09

44

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) 

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

5: Call SaveNewValues(Value1, Value2, Value3) 

所以,如果你在前面的自包含程序的习惯,获得与Call关键字调用,你可以忘记括号规则,因为你总是可以将你的参数括在括号内。

VB(A)(和许多其他语言)中额外的角色括号发挥作用会使事情混淆:它们还表示评估表达式的优先级。如果在任何其他上下文中使用括号,但要包含过程调用参数,则VB(A)将尝试将括号中的表达式计算为生成的简单值。

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

这也解释了为什么使用ByRef传递的变量的调用如果将参数括在圆括号中,就好像调用了ByVal一样。在上面的例子,其中函数p被调用的ByRef参数,有至p这两个调用之间有很大的不同:

6: 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关键字之后。)

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

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

比方说,你的用户已经进入“约翰”的文本框,您的应用程序调用HighlightContent。会发生什么,哪个电话会起作用?

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

+5

+1有一个很好的答案,但我仍然不同意括号规则是“完全合乎逻辑”的......我无法想象一种笨拙的方式来处理简单的括号操作! – Emma 2014-04-04 20:05:06

+1

什么时候有'点'? (请随时纠正我的术语) 'myCollection.add obj' AND 'myCollection.item(obj)' 这些都不是正确的方法吗?但括号规则是不同的,我不知道为什么。 – bmende 2015-09-13 01:25:14

+0

彻底解答了我一直困惑的事情。它仍然显得有点愚蠢。其他语言没有任何问题用括号解析函数调用,也没有“调用”关键字。但现在我知道了规则,我不会浪费时间来弄清楚WTFITMWTSL!感谢您的帮助。 B^J – riderBill 2015-11-30 13:43:37

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”

相关问题