Tentukan nilai default untuk argumen fungsi

86

Di wiki Lua saya menemukan cara untuk menentukan nilai default untuk argumen yang hilang:

function myfunction(a,b,c)
    b = b or 7
    c = c or 5
    print (a,b,c)
end

Apakah itu satu-satunya cara? Gaya PHP myfunction (a,b=7,c=5)sepertinya tidak berfungsi. Bukannya cara Lua tidak berhasil, saya hanya ingin tahu apakah ini satu-satunya cara untuk melakukannya.

ripat
sumber

Jawaban:

87

Jika Anda ingin argumen bernama dan nilai default seperti PHP atau Python, Anda dapat memanggil fungsi Anda dengan konstruktor tabel:

myfunction{a,b=3,c=2}

(Ini terlihat di banyak tempat di Lua, seperti bentuk lanjutan dari modul protokol dan konstruktor LuaSocket di IUPLua .)

Fungsi itu sendiri bisa memiliki tanda tangan seperti ini:

function myfunction(t)
    setmetatable(t,{__index={b=7, c=5}})
    local a, b, c =
      t[1] or t.a, 
      t[2] or t.b,
      t[3] or t.c
    -- function continues down here...
end

Setiap nilai yang hilang dari tabel parameter akan diambil dari __indextabel di metatabelnya (lihat dokumentasi tentang tabel metatabel ).

Tentu saja, gaya parameter yang lebih canggih dapat dilakukan dengan menggunakan konstruktor dan fungsi tabel - Anda dapat menulis apa pun yang Anda butuhkan. Misalnya, berikut adalah fungsi yang membangun fungsi yang mengambil tabel argumen bernama-atau-posisi dari tabel yang mendefinisikan nama parameter dan nilai default dan fungsi yang mengambil daftar argumen biasa.

Sebagai fitur tingkat non-bahasa, panggilan tersebut dapat diubah untuk memberikan perilaku dan semantik baru:

  • Variabel dapat dibuat untuk menerima lebih dari satu nama
  • Variabel posisi dan variabel kata kunci dapat diselingi - dan mendefinisikan keduanya dapat mendahulukan (atau menyebabkan kesalahan)
  • Variabel tanpa posisi hanya kata kunci dapat dibuat, serta variabel khusus posisi tanpa nama
  • Konstruksi tabel yang cukup bertele-tele dapat dilakukan dengan mengurai string
  • Daftar argumen dapat digunakan secara verbatim jika fungsinya dipanggil dengan sesuatu selain 1 tabel

Beberapa fungsi yang berguna untuk menulis penerjemah argumen adalah unpack(pindah ke table.unpack5.2), setfenv(usang di 5.2 dengan _ENVkonstruksi baru ), dan select(yang mengembalikan satu nilai dari daftar argumen yang diberikan, atau panjang daftar dengan '#').

Stuart P. Bentley
sumber
AI baru saja mulai menggunakan lua, saya akan membuatnya sederhana untuk saat ini tetapi posting Anda sangat informatif. Mungkin berguna nanti. Terima kasih.
ripat
1
Dalam kebanyakan kasus, menjaganya tetap sederhana adalah cara yang tepat. Antarmuka meta-parameter hanya benar-benar diperlukan untuk objek dengan sejumlah besar atribut opsional (seperti objek UI).
Stuart P. Bentley
Saya pikir jawaban ini adalah orang yang memecahkan pertanyaan, bukan yang saat ini ditandai sebagai diterima. Terima kasih atas pencerahannya :)
Urungkan
2
Perlu dicatat bahwa x or defaultekspresi yang juga digunakan dalam balasan ini sebenarnya tidak setara dengan parameter default tetapi hanya solusi sederhana yang hanya berfungsi jika keduanya nildan falsemerupakan nilai parameter yang tidak valid. Misalkan default untuk parameter boolean xadalah truedan pemanggil meneruskan eksplisit false. Kemudian x or truememberi true, meskipun falsesecara eksplisit disahkan. Versi yang lebih baik adalah if x == nil then x = default end, yang juga lebih mudah dibaca; itu masih tidak bisa menangani nilargumen eksplisit .
Jesper
Oh, hei, inilah jawaban yang diterima sekarang! Bagus. (Sebagai catatan, dan untuk menempatkan komentar @ Undo dalam konteks, jawaban jpjacobs di bawah adalah jawaban yang diterima untuk waktu yang sangat lama: Saya hampir mendapatkan lencana Populis kedua di atasnya.)
Stuart P. Bentley
46

Menurut saya tidak ada cara lain. Itu hanya mentalitas Lua: tanpa embel-embel, dan kecuali beberapa gula sintaksis, tidak ada cara yang berlebihan untuk melakukan hal-hal sederhana.

jpjacobs.dll
sumber
10
Jawaban ini sepenuhnya dibantah oleh jawaban Stuart P. Bentley di bawah ini, di mana fungsi tersebut dipanggil dengan konstruktor tabel. Ini adalah salah satu kekuatan Lua: meskipun tidak memiliki banyak embel-embel, blok bangunan dasar Lua memungkinkan Anda melakukan hal-hal yang tidak terbatas, benar-benar luar biasa untuk ukuran kecil dan kesederhanaan bahasanya.
Colin D Bennett
@ColinDBennett Terima kasih telah angkat bicara: akan muncul OP membaca komentar Anda dan, Desember itu, mengubah jawaban yang diterima sesuai. (Dan sekarang, "Jawaban Stuart P. Bentley di atas", demi kejelasan: wink :)
Stuart P. Bentley
21

Secara teknis, ada b = b == nil and 7 or b(yang harus digunakan dalam kasus di mana falseada nilai yang valid seperti yang false or 7dievaluasi ke 7), tetapi itu mungkin bukan yang Anda cari.

Stuart P. Bentley
sumber
1
Jika Anda tidak memeriksa false, cara yang lebih sederhana adalah menempatkan variabel terlebih dahulu dan default terakhir. b = b or 7
Rebs
2
Karena OP menyebutkan bahwa dalam pertanyaan mereka, saya pikir itu akan berlebihan untuk disebutkan (pertanyaannya adalah tentang cara menentukan variabel default selain b = b or 7 ).
Stuart P. Bentley
6

Satu-satunya cara yang saya temukan sejauh ini yang masuk akal adalah dengan melakukan sesuatu seperti ini:

function new(params)
  params = params or {}
  options = {
    name = "Object name"
  }

  for k,v in pairs(params) do options[k] = v end

  some_var = options.name
end

new({ name = "test" })
new()
NineBlindEyes
sumber