Как сделать функцию vimscript с необязательными аргументами?

35

Я хочу сделать функцию, которая имеет необязательные аргументы.

В Python я бы сделал что-то вроде этого:

def functionName(arg1,arg2=false,arg3=false):
    if arg2:
        #Do stuff with arguments
    else:
        #Do stuff without arguments

Я пытался сделать function FunctionName(arg1,arg2=false,arg3=false), но это просто дает мне ошибку, говоря неверный аргумент.

Как бы я сделал это в Vimscript?

iProgram
источник

Ответы:

35

Да, вы можете принимать необязательные аргументы в функции. Это не так удобно, как в Python, но вот как вы это делаете:

function FooBar(...) " This is like *args in python
    echom a:0 " a:0 contains an integer which is the number of arguments passed to the function
    echom a:1 " a:1 contains the first argument passed, a:2 contains the second and so on
    echo a:000 " a:000 contains a list of all arguments that were passed to the function
endfunction

Обратите внимание, что у вас может быть до 20 аргументов таким образом.

Соответствующие разделы справки:

:help :function
:help function-argument
Вечнозеленое дерево
источник
27

Немного опоздал на вечеринку, но я не увидел свою любимую:

function! FunctionName(arg1,...)
    let arg2 = get(a:, 1, 0)
    let arg3 = get(a:, 2, 0)

    if arg2
        "Do stuff with arguments"
    else
        "Do stuff without arguments"
    endif
endfunction

в котором get(a:, n, default)будет возвращаться nthнеобязательный аргумент, defaultесли его нет.

phicr
источник
О, это мило!
Joeytwiddle
3
Я знаю, что это очень старое, но просто к сведению тех, кто читает это. Вы не можете let a:arg=больше делать в Vim. Вы должны использовать что-то вроде let l:arg=или просто let arg=. См github.com/vim/vim/commit/...
jmzagorski
23

Этот шаблон позволит вам присвоить значимые имена каждому аргументу и предоставить значение по умолчанию для любых аргументов, которые не были предоставлены:

function FunctionName(foo, ...)
  let bar = a:0 >= 1 ? a:1 : 0
  let baz = a:0 >= 2 ? a:2 : 0
  ...
  " Code that makes use of a:foo, bar and baz

Как отметил Борис Бродский:

a:0 подсчитывает количество переданных необязательных аргументов

a:1, a:2... давайте доступ необязательные аргументы

Обязательные аргументы (как fooв примере выше) не учитываются

condition ? result_if_true : result_if_false является условным (троичным) выражением, которое оценивает второй или третий член в зависимости от того, был ли первый член истинным или нет.

Так что, если третий аргумент не предоставлен, bazпримет значение по умолчанию 0.

Одна из проблем , с приведенным выше примером является то , что a:fooможет только быть доступны с a:префиксом, в то время как barи bazможет обойтись без префикса. Поскольку это не очень согласованно, вы можете предпочесть вытянуть все аргументы в локальные переменные, например, так:

function FunctionName(...)
  let foo = a:1                  " Will throw an error if no arg was provided
  let bar = a:0 >= 2 ? a:2 : 0
  let baz = a:0 >= 3 ? a:3 : 0
  ...
  " Code that makes use of foo, bar and baz

(Технически вы можете использовать l:префикс, например, для ссылки на локальные переменные внутри функции l:baz, но это избыточно, поэтому я бы не рекомендовал его.)


Но я рекомендую вам использовать эту форму всякий раз, когда это возможно:

function! s:FunctionName(...)

!Позволяет переопределить ваши функции во время выполнения (например , путем перезагрузки скрипта), и s:ограничивает функцию области скрипта. Это исключает загрязнение глобального пространства имен (и риск столкновения), если на вашу функцию ссылаются только из других мест внутри скрипта. Обычно это предпочтительный способ определения функций, когда они не должны быть видны глобально. ;-)

joeytwiddle
источник
a:0не включает в себя фиксированные именованные параметры. a:1является первым параметром в ...(Только что протестирован с VIM 8.0)
Борис Бродский
Спасибо @BorisBrodski, ты прав, хороший улов. Я исправил ответ.
Joeytwiddle
8

Я не очень хорошо разбираюсь в vimscript, но вот как бы я это сделал:

function Func(foo, ...)
  if a:0 < 1
    let bar = "Unspecified bar"
  else
    let bar = a:1
  endif
  if a:0 < 2
    let baz = "Unspecified baz"
  else
    let baz = a:2
  endif

  echo a:foo
  echo bar
  echo baz
endfunction

Затем вы можете call Func("Hello", "World")увидеть, что он печатает «Hello», «World», «Unspecified baz».

Это использует функцию varargs функций vim, которая позволяет передавать произвольное количество дополнительных аргументов функции. Аргументы хранятся в переменных, которые, в зависимости от a:0(длина списка дополнительных аргументов), либо устанавливаются в соответствующие аргументы, либо в значение по умолчанию.

Score_Under
источник
2

Начиная с Vim 8.1.1310, Vim также поддерживает реальные необязательные аргументы функций.

Однако это означает, что большинство установок vim пока не поддерживают это. Также neovim также не предлагает эту функцию.

Пример из :help optional-function-argument:

  function Something(key, value = 10)
     echo a:key .. ": " .. a:value
  endfunction
  call Something('empty')   "empty: 10"
  call Something('key', 20) "key: 20"   
radlan
источник
Ухоженная. Вы должны расширить свой ответ, чтобы привести пример, чтобы мы могли быстро понять, что он добавляет.
Люк Эрмита
@LucHermitte Я изменил свой ответ соответственно.
Радлан