Ошибка компиляции 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. Различия выделены красным.

Сравнение советов по функциям * InstrRev * и Instr * в редакторе VBA

Примечание: '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")

Почему : смотрите другие ответы.

Другие вопросы по тегам