Bagaimana cara membuat fungsi vimscript dengan argumen opsional?

35

Saya ingin membuat fungsi yang memiliki argumen opsional.

Dengan python saya akan melakukan sesuatu seperti ini:

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

Saya sudah mencoba melakukan function FunctionName(arg1,arg2=false,arg3=false), tetapi itu hanya memberi saya kesalahan mengatakan argumen yang tidak valid.

Bagaimana saya melakukan ini dalam vimscript?

iProgram
sumber

Jawaban:

35

Ya, Anda dapat mengambil argumen opsional dalam suatu fungsi. Ini tidak semudah cara python melakukannya, tetapi ini adalah bagaimana Anda melakukannya:

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

Perhatikan bahwa Anda mungkin hanya memiliki hingga 20 argumen dengan cara ini.

Topik bantuan yang relevan:

:help :function
:help function-argument
Pohon cemara
sumber
27

Terlambat ke pesta sedikit tetapi saya tidak melihat favorit saya:

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

di mana get(a:, n, default)akan mendapatkan nthargumen opsional kembali defaultjika tidak ada.

phicr
sumber
Oooh itu bagus!
joeytwiddle
3
Saya tahu ini super tua, tetapi hanya FYI bagi siapa saja yang membaca ini. Anda tidak dapat melakukannya let a:arg=lagi di vim. Anda harus menggunakan sesuatu seperti let l:arg=atau adil let arg=. Lihat github.com/vim/vim/commit/…
jmzagorski
23

Pola ini akan memungkinkan Anda menetapkan nama yang bermakna untuk setiap argumen, dan memberikan nilai default untuk setiap argumen yang tidak disediakan:

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

Seperti yang ditunjukkan oleh Boris Brodski:

a:0 menghitung jumlah argumen opsional yang diteruskan

a:1,, a:2... mari kita mengakses argumen opsional

Argumen wajib (hanya foodalam contoh di atas) tidak dihitung

condition ? result_if_true : result_if_false adalah ekspresi kondisional (ternary), yang mengevaluasi ke istilah kedua atau ketiga tergantung pada apakah istilah pertama itu benar atau tidak.

Jadi jika tidak ada argumen ketiga yang diberikan, bazakan mengambil nilai default 0.

Salah satu perhatian dengan contoh di atas adalah bahwa a:foodapat hanya diakses dengan a:awalan, sementara bardan bazdapat melakukannya tanpa prefiks. Karena ini tidak terlalu konsisten, Anda dapat memilih untuk menarik semua argumen ke dalam variabel lokal, seperti:

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

(Secara teknis, Anda dapat menggunakan l:awalan untuk merujuk ke variabel lokal di dalam suatu fungsi, misalnya l:baz, tetapi ini berlebihan sehingga saya tidak akan merekomendasikannya.)


Tetapi saya merekomendasikan Anda untuk menggunakan formulir ini jika memungkinkan:

function! s:FunctionName(...)

The !memungkinkan Anda untuk mendefinisikan kembali fungsi Anda saat runtime (misalnya dengan reload script), dan s:membatasi fungsi untuk lingkup naskah. Itu menghindari polusi namespace global (dan mempertaruhkan tabrakan) jika fungsi Anda hanya dirujuk dari tempat lain di dalam skrip. Ini umumnya merupakan cara yang lebih disukai untuk mendefinisikan fungsi ketika mereka tidak perlu terlihat secara global. ;-)

joeytwiddle
sumber
a:0tidak termasuk parameter bernama tetap. a:1adalah parameter pertama dalam ...(Baru diuji dengan VIM 8.0)
Boris Brodski
Terima kasih @BorisBrodski Anda benar, tangkapan bagus. Saya sudah mengoreksi jawabannya.
joeytwiddle
8

Saya tidak cukup berpengalaman dalam vimscript, tetapi ini adalah bagaimana saya akan melakukannya:

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

Anda kemudian dapat call Func("Hello", "World"), dan melihat bahwa ia mencetak "Halo", "Dunia", "baz tidak ditentukan".

Ini menggunakan fitur varargs dari fungsi vim, yang memungkinkan Anda meneruskan sejumlah argumen tambahan sembarang ke fungsi. Argumen disimpan dalam variabel yang, tergantung pada a:0(panjang daftar argumen tambahan), baik diatur ke argumen yang sesuai atau nilai default.

Score_Under
sumber
2

Karena Vim 8.1.1310 Vim juga mendukung argumen fungsi opsional nyata.

Namun, itu berarti bahwa sebagian besar instalasi vim belum mendukung ini. Neovim juga tidak menawarkan fitur itu juga.

Contoh dari :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
sumber
Rapi. Anda harus memperluas jawaban Anda untuk memberikan contoh sehingga kami dapat memahami dengan cepat apa yang ditambahkannya.
Luc Hermitte
@LucHermitte Saya memodifikasi jawaban saya.
radlan