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'函数:
- 使用命名参数调用并且
它的return值赋给了一个变量
'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'函数与命名参数及其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
支持两种不同的语法并有效地模拟重载函数。这就是 String1
和 String2
被定义为 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
不会出现错误。
那么,InStr
和 StrComp
与 InStrRev
和 看似 所有其他 VBA 有什么共同点? ] 功能?
嗯,InStr
和 StrComp
都有这些特点:
- 函数在第一个引用的类型库中定义
- 函数在TLB/COM模块中定义
- 除最后一个参数外,所有参数均为
Variant
类型。
- 最后一个参数是一个
Enum
,默认值为
- return 值是变体
我在 VBA 库中找不到任何其他具有这些特征的函数,因此我怀疑存在与这些特征相关的编译错误。
限定函数解决了问题!?!?
InStrRev
和StrComp
都可以与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
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'函数:
- 使用命名参数调用并且
它的return值赋给了一个变量
'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'函数与命名参数及其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
支持两种不同的语法并有效地模拟重载函数。这就是 String1
和 String2
被定义为 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
不会出现错误。
那么,InStr
和 StrComp
与 InStrRev
和 看似 所有其他 VBA 有什么共同点? ] 功能?
嗯,InStr
和 StrComp
都有这些特点:
- 函数在第一个引用的类型库中定义
- 函数在TLB/COM模块中定义
- 除最后一个参数外,所有参数均为
Variant
类型。 - 最后一个参数是一个
Enum
,默认值为 - return 值是变体
我在 VBA 库中找不到任何其他具有这些特征的函数,因此我怀疑存在与这些特征相关的编译错误。
限定函数解决了问题!?!?
InStrRev
和StrComp
都可以与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