背景:在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 ”功能工具提示。差异以红色突出显示。
备注:' String1 '&根据上面的截图工具提示方括号,' String2 '是' InStr '函数的可选参数。但是,它们是必需的,如下面的答案和Visual Basic语言参考中所述:https://msdn.microsoft.com/EN-US/library/office/gg264811.aspx
答案 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
函数在设计时有4个可选参数,但在运行时必须至少提供2个参数。 InStr
的前3个参数是 all Variant
,它允许InStr
支持两种不同的语法并有效地模仿重载函数。这是String1
和String2
被定义为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
函数似乎没有任何重载类型的功能,但它与语法和编译错误有相同的问题:
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
不会出现错误。
那么,InStr
和StrComp
的共同点是InStrRev
和看似所有其他VBA函数有什么不同?
好吧,InStr
和StrComp
都有这些功能:
Variant
类型。Enum
,默认值为我无法在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