VBA 如果 Instr 函数与命名参数一起使用并且 return 值分配给变量,则编译错误

VBA compile error if Instr function used with named parameter and return value assigned to variable

Background : 在 VBA 中,'InStrRev' 函数可以在没有或有命名参数的情况下调用。

    'Call without named parameters

     Call InStrRev("AB", "B")                   'No compiler error  
     i = InStrRev("AB", "B")                    'No compiler error

    'Call with named parameters

     Call InStrRev(StringCheck:="AB", StringMatch:="B") 'No compiler error
     i = InStrRev(StringCheck:="AB", StringMatch:="B")  'No compiler error

关注 : In VBA, 编译器returns "Expected: list separator" error if 'InStr'函数:

问题 : 当'Instr'函数与命名参数及其return 值被分配给一个变量?是语言的限制还是编译器的错误?

参考文献 : VBA 'InstrRev' 和 'Instr 的编辑器截图]' 功能工具提示。差异以红色突出显示。

备注 : 'String1' & 'String2' 是 '[ 的可选参数=30=]InStr' 函数根据上面的屏幕截图工具提示方括号。但是,它们是必需的,如以下答案和 Visual Basic 语言参考中所述:https://msdn.microsoft.com/EN-US/library/office/gg264811.aspx

InStr 很奇怪,因为它的第一个参数 (Start) 是可选的,但其后续的 String1/String2 参数不是(尽管 [] 在工具提示中) - 如果它们 可选 InStr(1)parse 但它不会并生成与您看到的相同的错误。

特别奇怪,因为 VBA 不允许这样做;那里的规则是非可选参数不能跟在可选参数之后,这是有道理的,因为在某些情况下编译器无法将参数与函数预期的相匹配。这也迫使它的所有参数都是变体。

VB6/A 从 QBASIC 继承了很多包袱,并且该语言(iirc 不允许用户定义可选参数)的 INSTR() 具有完全相同的签名,所以我假设您看到的行为是调用 InStr.

时必须存在的特殊解析规则的产物

奇怪的是它的完全限定名称

 i = VBA.Strings.InStr(String1:="AB", String2:="B")` 

解析,但在运行时产生错误,除非提供 Start

i = VBA.Strings.InStr(String1:="AB", String2:="B", Start:=1)` 

按预期工作。

Call 表单似乎有效的一个原因是它是一个空操作,可能会被优化掉。


VBA.X() 对比 X()

这很好:

ptr = VBA.CLng(AddressOf someFunc)

这会生成解析时间预期表达式错误:

ptr = CLng(AddressOf someFunc)

InStr 通过 Variant 参数重载

InStr 函数在设计时有 4 个可选参数,但在 运行 时必须至少提供 2 个参数。 InStr 的前 3 个参数是 all Variant,它允许 InStr 支持两种不同的语法并有效地模拟重载函数。这就是 String1String2 被定义为 Variant 类型而不是 String 类型的原因之一。 Start 可能是 Long,但它也是 Variant 类型。

在下面的4个例子中,x总是赋值为4

选项 1 - 使用定义的参数顺序或名称含义

函数签名的行为与定义一致:

Function InStr([Start], [String1], [String2], [Compare As VbCompareMethod = vbBinaryCompare])

x = VBA.InStr(1, "food", "D", vbTextCompare)                                   '4
x = VBA.InStr(Start:=1, String1:="food", String2:="D", Compare:=vbTextCompare) '4

选项 2 - 使用替代顺序或名称含义

函数签名的行为就像定义如下:

Function InStr([String1], [String2], , [Compare As VbCompareMethod = vbBinaryCompare])

这实际上意味着 Start 应该像 String1 一样使用,而 String1 应该像 String2 一样使用。必须省略 String2 参数 ,否则会出现 Type Mismatch 错误。

x = VBA.InStr("food", "D", , vbTextCompare)                        '4
x = VBA.InStr(Start:="food", String1:="D", Compare:=vbTextCompare) '4

使用命名参数

但是正如您所发现的,InStr 函数在使用命名参数时会出现语法 and/or 编译错误:

语法错误:预期的列表分隔符

所有个参数命名时:

x = InStr(Start:=1, String1:="foo", String1:="foo", Compare:=vbBinaryCompare)

你得到:

Syntax Error: Expected List Separator

编译错误:对象不支持命名参数

一些的参数被命名为:

x = InStr(1, String1:="foo", String2:="foo", Compare:=vbBinaryCompare)

你得到:

Compile error: Object doesn't support named arguments

StrComp 函数出现同样的错误

StrComp 函数似乎没有任何重载类型的功能,但它在语法和编译错误方面存在相同的问题:

x = StrComp(String1:="foo", String2:="foo", Compare:=vbBinaryCompare) 'Syntax Error: Expected List Separator???
x = StrComp("foo", String2:="foo", Compare:=vbBinaryCompare) 'Compile error: Object doesn't support named arguments

但正如 OP 所发现的那样,InStrRev 不会出现错误。

那么,InStrStrCompInStrRev 看似 所有其他 VBA 有什么共同点? ] 功能?

嗯,InStrStrComp 都有这些特点:

  • 函数在第一个引用的类型库中定义
  • 函数在TLB/COM模块中定义
  • 除最后一个参数外,所有参数均为Variant类型。
  • 最后一个参数是一个 Enum,默认值为
  • return 值是变体

我在 VBA 库中找不到任何其他具有这些特征的函数,因此我怀疑存在与这些特征相关的编译错误。

限定函数解决了问题!?!?

InStrRevStrComp都可以与all/some命名参数一起使用,如果函数由库名或模块限定姓名:

'InStr Vanilla usage:
x = Strings.InStr(Start:=1, String1:="food", String2:="D", Compare:=vbTextCompare) '4
x = VBA.InStr(Start:=1, String1:="food", String2:="D", Compare:=vbTextCompare)     '4

'InStr Alternate usage:
x = Strings.InStr(Start:="food", String1:="D", Compare:=vbTextCompare) '4
x = VBA.InStr(Start:="food", String1:="D", Compare:=vbTextCompare)     '4

'StrComp usage
x = Strings.StrComp(String1:="food", String2:="D", Compare:=vbTextCompare)         '1
x = VBA.StrComp(String1:="food", String2:="D", Compare:=vbTextCompare)             '1