Ошибка компиляции VBA, если функция Instr используется с именованным параметром и возвращаемое значение назначено переменной
Предыстория: в 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":
- Вызывается с именованными параметрами и
Его возвращаемое значение присваивается переменной
'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"
Вопрос: Почему возникает ошибка компилятора VBA, когда функция "Instr" используется с именованными параметрами, а ее возвращаемое значение присваивается переменной? Это ограничение языка или ошибка компилятора?
Справка: скриншот редактора VBA дляподсказок по функциям InstrRev иInstr. Различия выделены красным.
Примечание: 'String1' и 'String2' являются необязательными аргументами для функции 'InStr' в соответствии с квадратными скобками всплывающей подсказки на скриншоте выше. Тем не менее, они необходимы, как указано в ответе ниже и в ссылке на язык Visual Basic: https://msdn.microsoft.com/EN-US/library/office/gg264811.aspx
3 ответа
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() против X()
Это прекрасно
ptr = VBA.CLng(AddressOf someFunc)
Это создает ошибку синтаксического анализа ожидаемого выражения:
ptr = CLng(AddressOf someFunc)
InStr перегружается с помощью параметров Variant
InStr
Функция имеет 4 необязательных параметра во время разработки, но как минимум 2 аргумента должны быть предоставлены во время выполнения. Первые 3 параметра для InStr
все Variant
, который позволяет InStr
поддерживать два разных синтаксиса и эффективно имитировать перегруженную функцию. Это одна из причин того, что String1
а также String2
определяются как Variant
типы а не как String
типы. Start
может быть Long
, но это Variant
типа тоже.
В следующих 4 примерах x
всегда присваивается значение 4
Вариант 1. Использование определенного порядка параметров или значений имен
Сигнатура функции ведет себя так, как она определена:
Функция 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
Вариант 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
,
Итак, что же InStr
а также StrComp
имеет общее, что отличается от InStrRev
а вроде бы все остальные функции VBA?
Что ж, InStr
а также StrComp
оба разделяют эти особенности:
- Функции определены в первой библиотеке типов, на которую есть ссылки
- Функции определены в модуле TLB/COM
- Все параметры, кроме последнего,
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
Два ответа потрясающие и очень интересные, но мне бы очень хотелось, чтобы в вопросе также задавалось «как решить», а не просто «почему» , потому что я думаю, что многие люди больше заинтересованы в решении (быстро). Извините, что перевел вопрос.
Вопрос : как решить странноеCompile error: Expected: list separator or )
этого кода:
i = InStr(String1:="AB", String2:="B")
Ответ (украдено из других ответов): используйте как «полное имя» , т.е. префикс сVBA.
и использовать
Start:=...
что является обязательным , иначе вы получите ошибку 5Invalid procedure call or argument
во время выполнения:
i = VBA.InStr(Start:=1,String1:="AB", String2:="B")
Почему : смотрите другие ответы.