¿Cómo hacer que una función vimscript funcione con argumentos opcionales?

35

Quiero hacer una función que tenga argumentos opcionales.

En python haría algo como esto:

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

He intentado hacerlo function FunctionName(arg1,arg2=false,arg3=false), pero me da un error que dice argumento no válido.

¿Cómo haría esto en vimscript?

iProgram
fuente

Respuestas:

35

Sí, puede tomar argumentos opcionales en una función. No es tan conveniente como la forma de hacerlo de Python, pero así es como lo haces:

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

Tenga en cuenta que solo puede tener hasta 20 argumentos de esta manera.

Temas de ayuda relevantes:

:help :function
:help function-argument
Árbol de hoja perenne
fuente
27

Llegué un poco tarde a la fiesta pero no vi mi favorita:

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

en el que get(a:, n, default)obtendrá el nthargumento opcional que regresa defaultsi no está presente.

phicr
fuente
Oooh eso es bueno!
joeytwiddle
3
Sé que esto es muy antiguo, pero solo para tu información, cualquiera que lea esto No puedes hacer let a:arg=más en vim. Debes usar algo como let l:arg=o solo let arg=. Ver github.com/vim/vim/commit/…
jmzagorski
23

Este patrón le permitirá asignar nombres significativos a cada argumento y proporcionará un valor predeterminado para los argumentos que no se proporcionaron:

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

Como señaló Boris Brodski:

a:0 cuenta el número de argumentos opcionales pasados

a:1, a:2, ... vamos a acceder a los argumentos opcionales

Los argumentos obligatorios (solo fooen el ejemplo anterior) no se cuentan

condition ? result_if_true : result_if_false es la expresión condicional (ternaria), que se evalúa al segundo o tercer término dependiendo de si el primer término era verdadero o no.

Entonces, si no se proporciona un tercer argumento, baztomará el valor predeterminado de 0.

Una preocupación con el ejemplo anterior es que a:foopuede solamente puede acceder con el a:prefijo, mientras que bary bazpuede estar sin un prefijo. Como esto no es muy consistente, puede preferir extraer todos los argumentos en variables locales, de esta manera:

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

(Técnicamente, puede usar el l:prefijo para referirse a variables locales dentro de una función, por ejemplo l:baz, pero esto es redundante, por lo que no lo recomendaría).


Pero le recomiendo que use este formulario siempre que sea posible:

function! s:FunctionName(...)

El le !permite redefinir su función en tiempo de ejecución (por ejemplo, volviendo a cargar el script), y s:limita la función al alcance del script. Eso evita contaminar el espacio de nombres global (y arriesgarse a una colisión) si solo se hace referencia a su función desde otro lugar dentro del script. Generalmente es la forma preferida de definir funciones cuando no es necesario que sean visibles globalmente. ;-)

joeytwiddle
fuente
a:0no incluye los parámetros fijos con nombre. a:1es el primer parámetro dentro de ...(Recién probado con VIM 8.0)
Boris Brodski
Gracias @BorisBrodski tienes razón, buena captura. He corregido la respuesta.
joeytwiddle
8

No estoy bien versado en vimscript, pero así es como lo haría:

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

A continuación call Func("Hello", "World"), puede ver que imprime "Hola", "Mundo", "Baz no especificado".

Esto está utilizando la función varargs de las funciones vim, que le permite pasar un número arbitrario de argumentos adicionales a la función. Los argumentos se almacenan en variables que, dependiendo de a:0(la longitud de la lista de argumentos adicionales), se configuran en su argumento correspondiente o en un valor predeterminado.

Score_Under
fuente
2

Desde Vim 8.1.1310, Vim también admite argumentos de funciones opcionales reales.

Sin embargo, eso significa que la mayoría de las instalaciones de vim aún no lo admiten. Además, neovim no ofrece esa característica también.

Ejemplo de :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
fuente
Ordenado. Debe ampliar su respuesta para dar un ejemplo para que podamos comprender rápidamente lo que agrega.
Luc Hermitte
@LucHermitte Modifiqué mi respuesta en consecuencia.
Radlan