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

Fab*_*nay 6 vba arguments named list-separator

背景:在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
Run Code Online (Sandbox Code Playgroud)

关注:在VBA中,如果' InStr '函数,编译器返回"Expected:list separator"错误:

  • 用命名参数调用
  • 其返回值分配给变量

    'Call without named parameters
    
     Call InStr("AB", "B")                   'No compiler error  
     i = InStr("AB", "B")                    'No compiler error
    
    'Call with named parameters
    
     Call InStr(String1:="AB", String2:="B") 'No compiler error
     i = InStr(String1:="AB", String2:="B")  'Compiler error : "Expected: list separator"
    
    Run Code Online (Sandbox Code Playgroud)

问题:当' Instr '函数与命名参数一起使用并且其返回值被赋值给变量时,为什么会出现VBA编译器错误?它是语言或编译器错误的限制吗?

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

在VBA编辑器中比较'*InstrRev*'和'*Instr*'函数提示

备注:" 字符串1 "和" String2的 "是"的可选参数InStr函数 "功能根据上面的截图工具提示方括号中.但是,它们是必需的,如下面的答案和Visual Basic语言参考中所述:https://msdn.microsoft.com/EN-US/library/office/gg264811.aspx

Thu*_*ame 5

InStr 通过 Variant 参数重载

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

在以下 4 个示例中,始终x分配值4

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

函数签名的行为与定义相同:

Function InStr([Start], [String1], [String2], [比较为 VbCompareMethod = vbBinaryCompare])

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

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

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

Function InStr([String1], [String2], , [比较为 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
Run Code Online (Sandbox Code Playgroud)

使用命名参数

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

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

所有参数都被命名时:

x = InStr(Start:=1, String1:="foo", String1:="foo", Compare:=vbBinaryCompare)
Run Code Online (Sandbox Code Playgroud)

你得到:

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

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

某些参数被命名时:

x = InStr(1, String1:="foo", String2:="foo", Compare:=vbBinaryCompare)
Run Code Online (Sandbox Code Playgroud)

你得到:

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

与 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
Run Code Online (Sandbox Code Playgroud)

但正如OP发现的那样,错误不会发生在InStrRev.

那么,与看似所有其他 VBA 函数InStr有何StrComp共同点InStrRev和不同点呢?

好吧,InStr两者StrComp都有以下特征:

  • 这些函数在第一个引用的类型库中定义
  • 这些函数在 TLB/COM 模块中定义
  • 除最后一个之外的所有参数都是Variant类型。
  • 最后一个参数是一个Enum带有默认值的
  • 返回值是一个 Variant

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

限定该函数可以解决问题!?!?

如果函数由库名称或模块名称限定,则和 都InStrRev可以StrComp与所有/部分命名参数一起使用:

'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
Run Code Online (Sandbox Code Playgroud)

  • 哇,这太破了。 (4认同)

Ale*_* K. 3

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

具体来说,这很奇怪,因为 VBA 不允许这样做;规则是非可选参数不能跟随可选参数,这是有道理的,因为在某些情况下编译器无法将参数与函数期望的参数匹配。这也迫使它的所有参数都是变体。

VB6/A 有很多从 QBASIC 继承下来的包袱,并且该语言(iirc 不允许用户定义可选参数)具有完全相同的签名,因此INSTR()我假设您看到的行为是特殊解析规则的产物必须存在才能调用InStr.

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

 i = VBA.Strings.InStr(String1:="AB", String2:="B")` 
Run Code Online (Sandbox Code Playgroud)

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

i = VBA.Strings.InStr(String1:="AB", String2:="B", Start:=1)` 
Run Code Online (Sandbox Code Playgroud)

其按预期工作。

Call该表单看起来有效的一个原因是它是一个无操作并且可以被优化掉。


VBA.X() 与 X()

这完全没问题:

ptr = VBA.CLng(AddressOf someFunc)
Run Code Online (Sandbox Code Playgroud)

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

ptr = CLng(AddressOf someFunc)
Run Code Online (Sandbox Code Playgroud)