如果Instr函数与命名参数一起使用并且返回值分配给变量

时间:2016-01-30 09:43:04

标签: 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

关注:在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"
    

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

参考:“ InstrRev ”的VBA编辑器屏幕截图和“ Instr ”功能工具提示。差异以红色突出显示。

Comparison of '*InstrRev*' and '*Instr*' functions tips in VBA editor

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

2 个答案:

答案 0 :(得分:2)

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

特别是奇怪,因为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()vs X()

这很好:

ptr = VBA.CLng(AddressOf someFunc)

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

ptr = CLng(AddressOf someFunc)

答案 1 :(得分:2)

InStr通过Variant参数

重载

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

在以下4个示例中,x 总是分配了值4

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

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

  

函数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 - 使用备用订单或名称含义

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

  

函数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

使用命名参数

但是正如您所发现的那样,InStr函数在使用命名参数时会受到语法和/或编译错误的影响:

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

所有参数都被命名为:

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

你得到:

  

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

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

某些参数命名为:

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

你得到:

  

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

与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不会出现错误。

那么,InStrStrComp的共同点是InStrRev看似所有其他VBA函数有什么不同?

好吧,InStrStrComp都有这些功能:

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

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

对该功能进行限定可以解决问题!?!?

InStrRevStrComp都可以与所有/一些命名参数一起使用,如果该函数由库名称或模块名称限定:

'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