Jak zrobić funkcję vimscript z opcjonalnymi argumentami?

35

Chcę utworzyć funkcję z opcjonalnymi argumentami.

W Pythonie zrobiłbym coś takiego:

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

Próbowałem to zrobić function FunctionName(arg1,arg2=false,arg3=false), ale po prostu wyświetla mi się błąd, mówiąc niepoprawny argument.

Jak mam to zrobić w vimscript?

iProgram
źródło

Odpowiedzi:

35

Tak, możesz wziąć opcjonalne argumenty w funkcji. Nie jest to tak wygodne, jak w Pythonie, ale tak to robisz:

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

Pamiętaj, że w ten sposób możesz mieć maksymalnie 20 argumentów.

Odpowiednie tematy pomocy:

:help :function
:help function-argument
Wiecznie zielone drzewo
źródło
27

Późno na imprezę, ale nie widziałem mojej ulubionej:

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

w którym get(a:, n, default)zostanie zwrócony nthopcjonalny argument, defaultjeśli nie jest obecny.

phicr
źródło
Oooch to miło!
joeytwiddle
3
Wiem, że to jest bardzo stare, ale po prostu dla każdego, kto to czyta. Nie możesz let a:arg=już więcej robić w vimie. Musisz użyć czegoś takiego let l:arg=lub po prostu let arg=. Zobacz github.com/vim/vim/commit/…
jmzagorski
23

Ten wzorzec pozwoli ci przypisać znaczące nazwy do każdego argumentu i zapewni domyślną wartość dla wszystkich argumentów, które nie zostały podane:

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

Jak zauważył Boris Brodski:

a:0 zlicza liczbę przekazanych opcjonalnych argumentów

a:1, a:2... niech nam dostęp do argumentów opcjonalnych

Obowiązkowe argumenty (tylko foow powyższym przykładzie) nie są liczone

condition ? result_if_true : result_if_false to wyrażenie warunkowe (trójskładnikowe), które ocenia na drugi lub trzeci warunek w zależności od tego, czy pierwszy warunek był prawdziwy, czy nie.

Więc jeśli nie zostanie podany trzeci argument, bazprzyjmie wartość domyślną 0.

Jednym z problemów z powyższym przykładzie jest to, że a:foomoże jedynie być dostępne z a:prefiksem, a jednocześnie bari bazmoże się obejść bez prefiksu. Ponieważ nie jest to bardzo spójne, możesz chcieć wyciągnąć wszystkie argumenty do zmiennych lokalnych, na przykład:

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

(Technicznie rzecz biorąc, możesz użyć l:przedrostka, aby na przykład odwołać się do zmiennych lokalnych wewnątrz funkcji l:baz, ale jest to zbędne, więc nie poleciłbym tego.)


Ale zalecam korzystanie z tego formularza, gdy tylko jest to możliwe:

function! s:FunctionName(...)

!Pozwala przedefiniować swoją funkcję w czasie wykonywania (np przez przeładowywania scenariusz) oraz s:ogranicza zakres funkcji do skryptu. Pozwala to uniknąć zanieczyszczenia globalnej przestrzeni nazw (i ryzyka kolizji), jeśli do funkcji odwołuje się tylko z innego miejsca w skrypcie. Jest to ogólnie preferowany sposób definiowania funkcji, gdy nie muszą być one widoczne na całym świecie. ;-)

joeytwiddle
źródło
a:0nie zawiera ustalonych nazwanych parametrów. a:1jest pierwszym parametrem w ...(Właśnie przetestowane z VIM 8.0)
Boris Brodski
Dzięki @ BorisBrodski masz rację, dobry chwyt. Poprawiłem odpowiedź.
joeytwiddle
8

Nie znam się dobrze na vimscript, ale tak bym to zrobił:

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

Następnie możesz call Func("Hello", "World")zobaczyć, że wyświetla „Hello”, „World”, „Unspecified baz”.

Wykorzystuje to funkcję varargs funkcji vim, która pozwala przekazać dowolną liczbę dodatkowych argumentów do funkcji. Argumenty są przechowywane w zmiennych, które w zależności od a:0(długości listy dodatkowych argumentów) są ustawiane na odpowiadający im argument lub na wartość domyślną.

Score_Under
źródło
2

Od wersji Vim 8.1.1310 Vim obsługuje również rzeczywiste argumenty funkcji opcjonalnych.

Oznacza to jednak, że większość instalacji vima jeszcze tego nie obsługuje. Neovim również nie oferuje tej funkcji.

Przykład z :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
źródło
Schludny. Powinieneś poszerzyć swoją odpowiedź, aby dać przykład, abyśmy mogli szybko zrozumieć, co ona dodaje.
Luc Hermitte
@LucHermitte odpowiednio zmodyfikowałem swoją odpowiedź.
radlan