กำหนดค่าเริ่มต้นสำหรับอาร์กิวเมนต์ของฟังก์ชัน


86

ใน Lua wiki ฉันพบวิธีกำหนดค่าเริ่มต้นสำหรับอาร์กิวเมนต์ที่ขาดหายไป:

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

นั่นเป็นวิธีเดียวหรือไม่? myfunction (a,b=7,c=5)ดูเหมือนว่าสไตล์ PHP จะไม่ทำงาน ไม่ใช่ว่าวิธี Lua ใช้ไม่ได้ฉันแค่สงสัยว่านี่เป็นวิธีเดียวที่จะทำได้

คำตอบ:


87

หากคุณต้องการอาร์กิวเมนต์ที่ตั้งชื่อและค่าเริ่มต้นเช่น PHP หรือ Python คุณสามารถเรียกใช้ฟังก์ชันของคุณด้วยตัวสร้างตาราง:

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

(สิ่งนี้มีให้เห็นในหลาย ๆ ที่ใน Lua เช่นรูปแบบขั้นสูงของโมดูลโปรโตคอลและตัวสร้างของLuaSocketในIUPLua )

ฟังก์ชันอาจมีลายเซ็นดังนี้:

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

ค่าใด ๆ ที่หายไปจากตารางพารามิเตอร์จะถูกนำมาจาก__indexตารางใน metatable (ดูเอกสารประกอบเกี่ยวกับ metatables )

แน่นอนว่ารูปแบบพารามิเตอร์ขั้นสูงสามารถทำได้โดยใช้ตัวสร้างตารางและฟังก์ชันคุณสามารถเขียนอะไรก็ได้ที่คุณต้องการ ตัวอย่างเช่นนี่คือฟังก์ชันที่สร้างฟังก์ชันที่รับตารางอาร์กิวเมนต์ที่มีชื่อหรือตำแหน่งจากตารางที่กำหนดชื่อพารามิเตอร์และค่าเริ่มต้นและฟังก์ชันที่รับรายการอาร์กิวเมนต์ปกติ

ในฐานะคุณสมบัติที่ไม่ใช่ภาษาระดับการเรียกดังกล่าวสามารถเปลี่ยนแปลงได้เพื่อให้พฤติกรรมและความหมายใหม่:

  • ตัวแปรสามารถทำให้ยอมรับได้มากกว่าหนึ่งชื่อ
  • ตัวแปรตำแหน่งและตัวแปรคำหลักสามารถสลับกันได้และการกำหนดทั้งสองอย่างสามารถให้ความสำคัญกับอย่างใดอย่างหนึ่ง (หรือทำให้เกิดข้อผิดพลาด)
  • สามารถสร้างตัวแปรที่ไม่มีตำแหน่งของคำหลักเท่านั้นและตัวแปรที่ไม่มีตำแหน่งเท่านั้น
  • การสร้างตารางที่ค่อนข้างละเอียดสามารถทำได้โดยการแยกวิเคราะห์สตริง
  • รายการอาร์กิวเมนต์สามารถใช้คำต่อคำได้หากฟังก์ชันถูกเรียกใช้ด้วยสิ่งอื่นที่ไม่ใช่ 1 ตาราง

ฟังก์ชันที่มีประโยชน์บางอย่างสำหรับการเขียนตัวแปลอาร์กิวเมนต์ ได้แก่unpack(ย้ายไปที่table.unpack5.2), setfenv(เลิกใช้ใน 5.2 พร้อมกับโครงสร้างใหม่_ENV) และselect(ซึ่งส่งคืนค่าเดียวจากรายการอาร์กิวเมนต์ที่กำหนดหรือความยาวของรายการด้วย'#')


AI เพิ่งเริ่มใช้ lua ฉันจะทำให้มันง่ายในเวลานั้น แต่โพสต์ของคุณให้ข้อมูลมาก อาจมีประโยชน์ในภายหลัง ขอบคุณ.
ripat

1
ในกรณีส่วนใหญ่การทำให้เรียบง่ายเป็นวิธีที่จะไป อินเตอร์เฟส Meta-parameter นั้นจำเป็นจริงๆสำหรับอ็อบเจ็กต์ที่มีแอ็ตทริบิวต์ทางเลือกจำนวนมาก (เช่นอ็อบเจ็กต์ UI)
Stuart P. Bentley

ฉันคิดว่าคำตอบนี้เป็นผู้ที่ช่วยแก้คำถามไม่ใช่คำตอบที่ถูกระบุว่ายอมรับในปัจจุบัน ขอบคุณสำหรับการตรัสรู้ :)
เลิกทำ

2
ควรสังเกตว่าx or defaultนิพจน์ที่ใช้ในการตอบกลับนี้ไม่ได้เทียบเท่ากับค่าเริ่มต้นของพารามิเตอร์จริง ๆ แต่เป็นเพียงวิธีแก้ปัญหาง่ายๆที่ใช้ได้เฉพาะเมื่อทั้งสองอย่างnilและfalseเป็นค่าพารามิเตอร์ที่ไม่ถูกต้อง สมมติว่าเริ่มต้นสำหรับพารามิเตอร์บูลีนxเป็นและโทรผ่านชัดเจนtrue falseจากนั้นx or trueให้trueแม้ว่าจะfalseผ่านไปอย่างชัดเจน จะมีเวอร์ชันที่ดีกว่าif x == nil then x = default endซึ่งสามารถอ่านได้มากกว่า มันยังไม่สามารถจัดการกับnilข้อโต้แย้งที่ชัดเจนได้
Jesper

เดี๋ยวก่อนนี่คือคำตอบที่ได้รับการยอมรับแล้ว! ดี. (สำหรับบันทึกและเพื่อใส่ความคิดเห็นของ @ Undo ในบริบทคำตอบของ jpjacobs ด้านล่างเป็นคำตอบที่ยอมรับมานานมาก: ฉันเกือบจะได้รับตรา Populist ที่สองแล้ว)
Stuart

46

ในความคิดของฉันไม่มีวิธีอื่น นั่นเป็นเพียงความคิดของชาวลัวะ: ไม่มีอะไรหรูหราและยกเว้นน้ำตาลที่มีปฏิกิริยาบางอย่างไม่มีวิธีง่ายๆในการทำสิ่งง่ายๆซ้ำซ้อน


10
คำตอบนี้ไม่สามารถพิสูจน์ได้อย่างสมบูรณ์โดยคำตอบของ Stuart P. Bentley ด้านล่างซึ่งฟังก์ชันนี้ถูกเรียกใช้ด้วยตัวสร้างตาราง นี่เป็นจุดแข็งอย่างหนึ่งของ Lua: แม้ว่าจะไม่มีความหรูหรามากมาย แต่โครงสร้างพื้นฐานของ Lua ช่วยให้คุณทำสิ่งต่างๆได้อย่างไร้ขีด จำกัด โดดเด่นอย่างแท้จริงสำหรับขนาดที่เล็กและความเรียบง่ายของภาษา
Colin D Bennett

@ColinDBennett ขอบคุณที่แจ้งให้ทราบ: ดูเหมือนว่า OP จะอ่านความคิดเห็นของคุณและในเดือนธันวาคมนั้นจะเปลี่ยนคำตอบที่ยอมรับตามนั้น (และตอนนี้มันคือ "คำตอบของ Stuart P. Bentley ข้างบน" เพื่อความชัดเจน: wink :)
Stuart P. Bentley

21

ในทางเทคนิคมีb = b == nil and 7 or b(ซึ่งควรใช้ในกรณีที่falseเป็นค่าที่ถูกต้องเมื่อfalse or 7ประเมินถึง 7) แต่นั่นอาจไม่ใช่สิ่งที่คุณกำลังมองหา


1
หากคุณไม่ได้ตรวจสอบfalseวิธีที่ง่ายกว่าคือใส่ตัวแปรก่อนและค่าเริ่มต้นสุดท้าย b = b or 7
Rebs

2
เนื่องจาก OP กล่าวถึงสิ่งนั้นในคำถามของพวกเขาฉันคิดว่ามันจะไม่จำเป็นที่จะพูดถึง (คำถามเกี่ยวกับวิธีกำหนดตัวแปรเริ่มต้นอื่น ๆ ที่ไม่ใช่ b = b or 7 )
สจวร์ตพี. เบนท์ลีย์

6

วิธีเดียวที่ฉันพบจนถึงตอนนี้ที่สมเหตุสมผลคือการทำสิ่งนี้:

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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.