Có, ensure
đảm bảo rằng mã luôn được đánh giá. Đó là lý do tại sao nó được gọi là ensure
. Vì vậy, nó tương đương với Java và C # finally
.
Luồng chung của begin
/ rescue
/ else
/ ensure
/ end
trông như thế này:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
rescue SomeOtherException => some_other_variable
# code that deals with some other exception
else
# code that runs only if *no* exception was raised
ensure
# ensure that this code always runs, no matter what
# does not change the final value of the block
end
Bạn có thể rời khỏi rescue
, ensure
hoặc else
. Bạn cũng có thể bỏ qua các biến trong trường hợp bạn sẽ không thể kiểm tra ngoại lệ trong mã xử lý ngoại lệ của mình. (Vâng, bạn luôn có thể sử dụng các biến ngoại lệ toàn cầu để truy cập ngoại lệ cuối cùng đã được đưa ra, nhưng đó là một chút hacky chút.) Và bạn có thể bỏ qua các lớp ngoại lệ, trong trường hợp tất cả các trường hợp ngoại lệ mà kế thừa từ StandardError
sẽ bị bắt. (Xin lưu ý rằng điều này không có nghĩa là tất cả các trường hợp ngoại lệ được bắt, bởi vì có những trường hợp ngoại lệ là trường hợp Exception
nhưng không phải StandardError
. Chủ yếu là trường hợp ngoại lệ rất nghiêm trọng thỏa hiệp sự toàn vẹn của chương trình như SystemStackError
, NoMemoryError
, SecurityError
, NotImplementedError
, LoadError
, SyntaxError
, ScriptError
, Interrupt
,SignalException
hoặc SystemExit
.)
Một số khối hình thành các khối ngoại lệ ngầm. Ví dụ, định nghĩa phương thức cũng là các khối ngoại lệ, vì vậy thay vì viết
def foo
begin
# ...
rescue
# ...
end
end
bạn chỉ viết
def foo
# ...
rescue
# ...
end
hoặc là
def foo
# ...
ensure
# ...
end
Điều tương tự áp dụng cho các class
định nghĩa và module
định nghĩa.
Tuy nhiên, trong trường hợp cụ thể mà bạn đang hỏi về, thực sự có một thành ngữ tốt hơn nhiều. Nói chung, khi bạn làm việc với một số tài nguyên mà bạn cần dọn sạch vào cuối, bạn sẽ làm điều đó bằng cách chuyển một khối cho một phương thức thực hiện tất cả việc dọn dẹp cho bạn. Nó tương tự như một using
khối trong C #, ngoại trừ việc Ruby thực sự đủ mạnh để bạn không phải chờ đợi các linh mục cao cấp của Microsoft từ trên núi xuống và thay đổi trình biên dịch của họ cho bạn. Trong Ruby, bạn có thể tự thực hiện nó:
# This is what you want to do:
File.open('myFile.txt', 'w') do |file|
file.puts content
end
# And this is how you might implement it:
def File.open(filename, mode='r', perm=nil, opt=nil)
yield filehandle = new(filename, mode, perm, opt)
ensure
filehandle&.close
end
Và bạn biết gì: cái này đã có sẵn trong thư viện lõi như File.open
. Nhưng đó là một mô hình chung mà bạn có thể sử dụng trong mã của riêng mình, để thực hiện bất kỳ loại dọn dẹp tài nguyên nào (à la using
trong C #) hoặc các giao dịch hoặc bất cứ điều gì khác mà bạn có thể nghĩ đến.
Trường hợp duy nhất không hoạt động, nếu có được và giải phóng tài nguyên được phân phối trên các phần khác nhau của chương trình. Nhưng nếu nó được bản địa hóa, như trong ví dụ của bạn, thì bạn có thể dễ dàng sử dụng các khối tài nguyên này.
BTW: trong C # hiện đại, using
thực sự không cần thiết, bởi vì bạn có thể tự thực hiện các khối tài nguyên theo kiểu Ruby:
class File
{
static T open<T>(string filename, string mode, Func<File, T> block)
{
var handle = new File(filename, mode);
try
{
return block(handle);
}
finally
{
handle.Dispose();
}
}
}
// Usage:
File.open("myFile.txt", "w", (file) =>
{
file.WriteLine(contents);
});
begin
khối.