Elixir - Xử lý lỗi
Elixir có ba cơ chế lỗi: lỗi, ném và thoát. Hãy cùng chúng tôi khám phá chi tiết từng cơ chế.
lỗi
Lỗi (hoặc ngoại lệ) được sử dụng khi những điều đặc biệt xảy ra trong mã. Một lỗi mẫu có thể được truy xuất bằng cách cố gắng thêm một số vào một chuỗi -
IO.puts(1 + "Hello")
Khi chương trình trên được chạy, nó tạo ra lỗi sau:
** (ArithmeticError) bad argument in arithmetic expression
:erlang.+(1, "Hello")
Đây là một lỗi có sẵn mẫu.
Tăng lỗi
Chúng ta có thể raiselỗi sử dụng các chức năng tăng. Chúng ta hãy xem xét một ví dụ để hiểu giống nhau -
#Runtime Error with just a message
raise "oops" # ** (RuntimeError) oops
Các lỗi khác có thể được đưa ra với raise / 2 chuyển tên lỗi và danh sách các đối số từ khóa
#Other error type with a message
raise ArgumentError, message: "invalid argument foo"
Bạn cũng có thể xác định lỗi của riêng bạn và nêu ra những lỗi đó. Hãy xem xét ví dụ sau:
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
Khắc phục lỗi
Chúng tôi không muốn các chương trình của mình bị thoát đột ngột nhưng các lỗi cần được xử lý cẩn thận. Đối với điều này, chúng tôi sử dụng xử lý lỗi. Chúng tôirescue lỗi sử dụng try/rescuexây dựng. Chúng ta hãy xem xét ví dụ sau để hiểu giống nhau -
err = try do
raise "oops"
rescue
e in RuntimeError -> e
end
IO.puts(err.message)
Khi chương trình trên được chạy, nó tạo ra kết quả sau:
oops
Chúng tôi đã xử lý các lỗi trong câu lệnh cứu bằng cách sử dụng đối sánh mẫu. Nếu chúng tôi không sử dụng lỗi nào và chỉ muốn sử dụng nó cho mục đích nhận dạng, chúng tôi cũng có thể sử dụng biểu mẫu -
err = try do
1 + "Hello"
rescue
RuntimeError -> "You've got a runtime error!"
ArithmeticError -> "You've got a Argument error!"
end
IO.puts(err)
Khi chạy chương trình trên, nó tạo ra kết quả sau:
You've got a Argument error!
NOTE- Hầu hết các chức năng trong thư viện tiêu chuẩn Elixir được thực hiện hai lần, một lần trả về các bộ giá trị và lần khác làm tăng lỗi. Ví dụ,File.read và File.read!chức năng. Đầu tiên trả về một tuple nếu tệp được đọc thành công và nếu gặp lỗi, tuple này được sử dụng để đưa ra lý do gây ra lỗi. Cái thứ hai nêu ra lỗi nếu gặp lỗi.
Nếu chúng ta sử dụng phương pháp tiếp cận hàm đầu tiên, thì chúng ta cần sử dụng trường hợp cho mẫu phù hợp với lỗi và thực hiện hành động theo đó. Trong trường hợp thứ hai, chúng tôi sử dụng phương pháp giải cứu thử đối với mã dễ bị lỗi và xử lý lỗi cho phù hợp.
Ném
Trong Elixir, một giá trị có thể được ném và sau đó sẽ được bắt lại. Ném và Bắt được dành riêng cho các trường hợp không thể lấy giá trị trừ khi sử dụng ném và bắt.
Các trường hợp này khá phổ biến trong thực tế ngoại trừ khi giao tiếp với các thư viện. Ví dụ: bây giờ chúng ta hãy giả sử rằng mô-đun Enum không cung cấp bất kỳ API nào để tìm một giá trị và chúng ta cần tìm bội số đầu tiên của 13 trong danh sách các số -
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)
Khi chương trình trên được chạy, nó tạo ra kết quả sau:
Got 26
Lối ra
Khi một quy trình chết vì “nguyên nhân tự nhiên” (ví dụ: các ngoại lệ chưa được xử lý), nó sẽ gửi một tín hiệu thoát. Một quá trình cũng có thể chết bằng cách gửi một tín hiệu thoát rõ ràng. Chúng ta hãy xem xét ví dụ sau:
spawn_link fn -> exit(1) end
Trong ví dụ trên, quá trình được liên kết đã chết bằng cách gửi một tín hiệu thoát có giá trị là 1. Lưu ý rằng lối ra cũng có thể được “bắt” bằng cách sử dụng try / catch. Ví dụ -
val = try do
exit "I am exiting"
catch
:exit, _ -> "not really"
end
IO.puts(val)
Khi chương trình trên được chạy, nó tạo ra kết quả sau:
not really
Sau
Đôi khi cần đảm bảo rằng tài nguyên được dọn dẹp sau một số hành động có thể gây ra lỗi. Cấu trúc try / after cho phép bạn làm điều đó. Ví dụ, chúng ta có thể mở một tệp và sử dụng mệnh đề sau để đóng nó - ngay cả khi có sự cố.
{:ok, file} = File.open "sample", [:utf8, :write]
try do
IO.write file, "olá"
raise "oops, something went wrong"
after
File.close(file)
end
Khi chúng tôi chạy chương trình này, nó sẽ báo lỗi cho chúng tôi. Nhưngafter câu lệnh sẽ đảm bảo rằng bộ mô tả tệp được đóng khi có bất kỳ sự kiện nào như vậy.