Elixir - การจัดการข้อผิดพลาด
Elixir มีกลไกข้อผิดพลาดสามประการ: ข้อผิดพลาดการขว้างและการออก ให้เราสำรวจกลไกแต่ละอย่างโดยละเอียด
ข้อผิดพลาด
ข้อผิดพลาด (หรือข้อยกเว้น) ใช้เมื่อมีสิ่งพิเศษเกิดขึ้นในโค้ด สามารถเรียกดูข้อผิดพลาดตัวอย่างได้โดยพยายามเพิ่มตัวเลขลงในสตริง -
IO.puts(1 + "Hello")
เมื่อรันโปรแกรมข้างต้นจะเกิดข้อผิดพลาดดังต่อไปนี้ -
** (ArithmeticError) bad argument in arithmetic expression
:erlang.+(1, "Hello")
นี่คือตัวอย่างข้อผิดพลาดในตัว
เพิ่มข้อผิดพลาด
เราทำได้ raiseข้อผิดพลาดในการใช้ฟังก์ชันเพิ่ม ให้เราพิจารณาตัวอย่างเพื่อให้เข้าใจตรงกัน -
#Runtime Error with just a message
raise "oops" # ** (RuntimeError) oops
ข้อผิดพลาดอื่น ๆ สามารถเกิดขึ้นได้ด้วยการเพิ่ม / 2 ผ่านชื่อข้อผิดพลาดและรายการอาร์กิวเมนต์คำหลัก
#Other error type with a message
raise ArgumentError, message: "invalid argument foo"
คุณยังสามารถกำหนดข้อผิดพลาดของคุณเองและเพิ่มข้อผิดพลาดเหล่านั้น ลองพิจารณาตัวอย่างต่อไปนี้ -
defmodule MyError do
defexception message: "default message"
end
raise MyError # Raises error with default message
raise MyError, message: "custom message" # Raises error with custom message
การช่วยเหลือข้อผิดพลาด
เราไม่ต้องการให้โปรแกรมของเราหยุดทำงานอย่างกะทันหัน แต่จำเป็นต้องจัดการข้อผิดพลาดอย่างรอบคอบ สำหรับสิ่งนี้เราใช้การจัดการข้อผิดพลาด เราrescue ข้อผิดพลาดโดยใช้ไฟล์ try/rescueสร้าง. ให้เราพิจารณาตัวอย่างต่อไปนี้เพื่อทำความเข้าใจเช่นเดียวกัน -
err = try do
raise "oops"
rescue
e in RuntimeError -> e
end
IO.puts(err.message)
เมื่อรันโปรแกรมข้างต้นจะให้ผลลัพธ์ดังนี้ -
oops
เราได้จัดการข้อผิดพลาดในคำสั่งการช่วยเหลือโดยใช้การจับคู่รูปแบบ หากเราไม่ได้ใช้ข้อผิดพลาดใด ๆ และเพียงแค่ต้องการใช้เพื่อจุดประสงค์ในการระบุตัวตนเรายังสามารถใช้แบบฟอร์ม -
err = try do
1 + "Hello"
rescue
RuntimeError -> "You've got a runtime error!"
ArithmeticError -> "You've got a Argument error!"
end
IO.puts(err)
เมื่อรันโปรแกรมด้านบนจะให้ผลลัพธ์ดังนี้ -
You've got a Argument error!
NOTE- ฟังก์ชั่นส่วนใหญ่ในไลบรารีมาตรฐาน Elixir จะถูกใช้สองครั้งเมื่อคืนค่าทูเปิลและเวลาอื่น ๆ เพิ่มข้อผิดพลาด ตัวอย่างเช่นไฟล์File.read และ File.read!ฟังก์ชั่น. อันแรกส่งคืนทูเพิลหากอ่านไฟล์สำเร็จและหากพบข้อผิดพลาดทูเปิลนี้จะถูกใช้เพื่อให้เหตุผลของข้อผิดพลาด ข้อที่สองทำให้เกิดข้อผิดพลาดหากพบข้อผิดพลาด
หากเราใช้แนวทางฟังก์ชันแรกเราจำเป็นต้องใช้ case สำหรับรูปแบบที่ตรงกับข้อผิดพลาดและดำเนินการตามนั้น ในกรณีที่สองเราใช้วิธีการลองช่วยเหลือสำหรับรหัสที่มีแนวโน้มเกิดข้อผิดพลาดและจัดการข้อผิดพลาดตามนั้น
พ่น
ใน Elixir สามารถโยนมูลค่าและจับได้ในภายหลัง Throw and Catch สงวนไว้สำหรับสถานการณ์ที่ไม่สามารถดึงค่าได้เว้นแต่จะใช้ Throw and Catch
อินสแตนซ์ค่อนข้างผิดปกติในทางปฏิบัติยกเว้นเมื่อเชื่อมต่อกับไลบรารี ตัวอย่างเช่นสมมติว่าตอนนี้โมดูล Enum ไม่ได้ให้ API ใด ๆ สำหรับการค้นหาค่าและเราจำเป็นต้องค้นหาตัวคูณ 13 ตัวแรกในรายการตัวเลข -
val = try do
Enum.each 20..100, fn(x) ->
if rem(x, 13) == 0, do: throw(x)
end
"Got nothing"
catch
x -> "Got #{x}"
end
IO.puts(val)
เมื่อรันโปรแกรมข้างต้นจะให้ผลลัพธ์ดังนี้ -
Got 26
ออก
เมื่อกระบวนการตายด้วย“ สาเหตุตามธรรมชาติ” (เช่นข้อยกเว้นที่ไม่สามารถจัดการได้) ระบบจะส่งสัญญาณออก กระบวนการสามารถตายได้โดยการส่งสัญญาณออกอย่างชัดเจน ให้เราพิจารณาตัวอย่างต่อไปนี้ -
spawn_link fn -> exit(1) end
ในตัวอย่างข้างต้นกระบวนการที่เชื่อมโยงเสียชีวิตโดยการส่งสัญญาณออกที่มีค่า 1 โปรดทราบว่าทางออกสามารถ "จับ" ได้โดยใช้ try / catch ตัวอย่างเช่น -
val = try do
exit "I am exiting"
catch
:exit, _ -> "not really"
end
IO.puts(val)
เมื่อรันโปรแกรมข้างต้นจะให้ผลลัพธ์ดังนี้ -
not really
หลังจาก
บางครั้งจำเป็นต้องตรวจสอบให้แน่ใจว่าทรัพยากรได้รับการล้างข้อมูลหลังจากการดำเนินการบางอย่างที่อาจทำให้เกิดข้อผิดพลาด โครงสร้าง try / after ช่วยให้คุณทำเช่นนั้นได้ ตัวอย่างเช่นเราสามารถเปิดไฟล์และใช้ after clause เพื่อปิดไฟล์ได้แม้ว่าจะมีบางอย่างผิดพลาด
{:ok, file} = File.open "sample", [:utf8, :write]
try do
IO.write file, "olá"
raise "oops, something went wrong"
after
File.close(file)
end
เมื่อเรารันโปรแกรมนี้มันจะทำให้เรามีข้อผิดพลาด แต่after คำสั่งจะทำให้แน่ใจว่า file descriptor ถูกปิดเมื่อเกิดเหตุการณ์ดังกล่าว