ฉันมาพร้อมกับสิ่งนี้:
(defn string-> จำนวนเต็ม [str & [base]] (จำนวนเต็ม / parseInt str (ถ้า (ศูนย์? ฐาน) 10 ฐาน))) (string-> จำนวนเต็ม "10") (string-> จำนวนเต็ม "FF" 16)
แต่ต้องเป็นวิธีที่ดีกว่านี้
ฉันมาพร้อมกับสิ่งนี้:
(defn string-> จำนวนเต็ม [str & [base]] (จำนวนเต็ม / parseInt str (ถ้า (ศูนย์? ฐาน) 10 ฐาน))) (string-> จำนวนเต็ม "10") (string-> จำนวนเต็ม "FF" 16)
แต่ต้องเป็นวิธีที่ดีกว่านี้
คำตอบ:
ฟังก์ชันสามารถมีหลายลายเซ็นได้หากลายเซ็นมีความแตกต่างกัน คุณสามารถใช้เพื่อระบุค่าเริ่มต้น
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
โปรดทราบว่าสมมติfalse
และnil
มีทั้งที่ถือว่าเป็นค่าที่ไม่(if (nil? base) 10 base)
อาจจะลงไปหรือต่อไป(if base base 10)
(or base 10)
recur
จะใช้งานได้เฉพาะใน arity เดียวกันเท่านั้น หากคุณพยายามเกิดซ้ำข้างต้นเช่นjava.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10)
)?
คุณยังสามารถทำลายrest
อาร์กิวเมนต์เป็นแผนที่ได้ตั้งแต่ Clojure 1.2 [ ref ] สิ่งนี้ช่วยให้คุณตั้งชื่อและระบุค่าเริ่มต้นสำหรับอาร์กิวเมนต์ของฟังก์ชัน:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
ตอนนี้คุณสามารถโทร
(string->integer "11")
=> 11
หรือ
(string->integer "11" :base 8)
=> 9
คุณสามารถดูการดำเนินการได้ที่นี่: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (ตัวอย่าง)
การแก้ปัญหานี้ยิ่งใกล้เคียงกับจิตวิญญาณของโซลูชันดั้งเดิมมากขึ้นแต่ก็สะอาดกว่าเล็กน้อย
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
รูปแบบคล้ายกันซึ่งสามารถใช้ประโยชน์or
รวมกับlet
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
ในขณะที่ในกรณีนี้เพิ่มเติมอย่างละเอียดก็จะเป็นประโยชน์ถ้าคุณต้องการที่จะมีค่าเริ่มต้นขึ้นอยู่กับค่าป้อนข้อมูลอื่น ๆ ตัวอย่างเช่นพิจารณาฟังก์ชันต่อไปนี้:
(defn exemplar [a & [b c]]
(let [b (or b 5)
c (or c (* 7 b))]
;; or whatever yer actual code might be...
(println a b c)))
(exemplar 3) => 3 5 35
แนวทางนี้สามารถขยายไปใช้ได้อย่างง่ายดาย อาร์กิวเมนต์ที่ตั้งชื่อ (เช่นเดียวกับในโซลูชันของ M. Gilliar) เช่นกัน:
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
หรือใช้ฟิวชั่นมากยิ่งขึ้น:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
or
or
จะแตกต่างจาก:or
ตั้งแต่or
ไม่ทราบความแตกต่างของและnil
false
มีอีกแนวทางหนึ่งที่คุณอาจต้องการพิจารณา: บางส่วนฟังก์ชันเนื้อหาเหล่านี้เป็นวิธีที่ "ใช้งานได้" และยืดหยุ่นกว่าในการระบุค่าเริ่มต้นสำหรับฟังก์ชัน
เริ่มต้นด้วยการสร้าง (ถ้าจำเป็น) ฟังก์ชันที่มีพารามิเตอร์ที่คุณต้องการให้เป็นค่าเริ่มต้นเป็นพารามิเตอร์นำหน้า:
(defn string->integer [base str]
(Integer/parseInt str base))
สิ่งนี้ทำได้เนื่องจากเวอร์ชันของ Clojure partial
ให้คุณระบุค่า "เริ่มต้น" ตามลำดับที่ปรากฏในข้อกำหนดฟังก์ชันเท่านั้น เมื่อเรียงลำดับพารามิเตอร์ตามที่ต้องการแล้วคุณสามารถสร้างเวอร์ชัน "เริ่มต้น" ของฟังก์ชันโดยใช้partial
ฟังก์ชัน:
(partial string->integer 10)
ในการทำให้ฟังก์ชันนี้สามารถเรียกใช้ได้หลาย ๆ ครั้งคุณสามารถใส่มันลงใน var โดยใช้def
:
(def decimal (partial string->integer 10))
(decimal "10")
;10
คุณยังสามารถสร้าง "ค่าเริ่มต้นในเครื่อง" โดยใช้let
:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
วิธีการฟังก์ชั่นบางส่วนมีข้อดีอย่างหนึ่งที่สำคัญกว่าคนอื่น ๆ คือผู้บริโภคของฟังก์ชันยังสามารถตัดสินใจเลือกสิ่งที่คุ้มค่าเริ่มต้นจะเป็นมากกว่าผู้ผลิตของฟังก์ชั่นโดยไม่จำเป็นต้องปรับเปลี่ยนการกำหนดฟังก์ชัน นี่คือภาพประกอบในตัวอย่างด้วยhex
ที่ฉันได้ตัดสินใจว่าฟังก์ชันเริ่มต้นdecimal
ไม่ใช่สิ่งที่ฉันต้องการ
ข้อดีอีกอย่างของวิธีนี้คือคุณสามารถกำหนดฟังก์ชันเริ่มต้นเป็นชื่ออื่น (ทศนิยมฐานสิบหก ฯลฯ ) ซึ่งอาจสื่อความหมายได้มากกว่าและ / หรือขอบเขตที่แตกต่างกัน (var, local) ฟังก์ชั่นบางส่วนสามารถผสมกับวิธีการบางอย่างข้างต้นได้หากต้องการ:
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(โปรดทราบว่าสิ่งนี้แตกต่างจากคำตอบของ Brian เล็กน้อยเนื่องจากลำดับของพารามิเตอร์ถูกย้อนกลับด้วยเหตุผลที่ระบุไว้ที่ด้านบนของการตอบกลับนี้)
คุณอาจดู(fnil)
https://clojuredocs.org/clojure.core/fnil
(recur s 10)
ใช้แทนการทำซ้ำชื่อฟังก์ชันrecur
string->integer
ซึ่งจะทำให้ง่ายต่อการเปลี่ยนชื่อฟังก์ชันในอนาคต ไม่มีใครรู้เหตุผลที่จะไม่ใช้recur
ในสถานการณ์เหล่านี้?