[英]equivalent of Python's “with” in Ruby
在 Python 中, with
語句用於確保始終調用清理代碼,無論拋出異常或返回函數調用。 例如:
with open("temp.txt", "w") as f:
f.write("hi")
raise ValueError("spitespite")
在這里,即使引發了異常,文件也已關閉。 更好的解釋是here 。
Ruby 中是否有與此結構等效的結構? 或者你可以編寫一個代碼,因為 Ruby 有延續?
Ruby 對文字匿名過程(在 Ruby 中稱為塊)具有語法上的輕量級支持。 因此,它不需要為此提供新的語言功能。
因此,您通常所做的是編寫一個方法,該方法接受一個代碼塊,分配資源,在該資源的上下文中執行該代碼塊,然后關閉該資源。
像這樣的東西:
def with(klass, *args)
yield r = klass.open(*args)
ensure
r.close
end
你可以這樣使用它:
with File, 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
但是,這是一種非常程序化的方法。 Ruby 是一種面向對象的語言,這意味着在File
上下文中正確執行代碼塊的責任應該屬於File
類:
File.open 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
這可以實現如下:
def File.open(*args)
f = new(*args)
return f unless block_given?
yield f
ensure
f.close if block_given?
end
這是由 Ruby 核心庫、標准庫和第三方庫中的許多類實現的通用模式。
與通用 Python 上下文管理器協議更接近的對應是:
def with(ctx)
yield ctx.setup
ensure
ctx.teardown
end
class File
def setup; self end
alias_method :teardown, :close
end
with File.open('temp.txt', 'w') do |f|
f.write 'hi'
raise 'spitespite'
end
請注意,這與 Python 示例幾乎沒有區別,但它不需要向該語言添加新語法。
Ruby 中的等效項是將塊傳遞給 File.open 方法。
File.open(...) do |file|
#do stuff with file
end #file is closed
這是 Ruby 使用的習慣用法,您應該熟悉這種習慣用法。
你可以在 Ruby 中使用 Block Arguments 來做到這一點:
class Object
def with(obj)
obj.__enter__
yield
obj.__exit__
end
end
現在,您可以將__enter__
和__exit__
方法添加到另一個類並像這樣使用它:
with GetSomeObject("somefile.text") do |foo|
do_something_with(foo)
end
可以在 Ruby 中以原子方式寫入文件,如下所示:
File.write("temp.txt", "hi")
raise ValueError("spitespite")
編寫這樣的代碼意味着不可能不小心打開文件。
我只會為其他人添加更多解釋; 應該歸功於他們。
確實,在 Ruby 中,清理代碼就像其他人所說的,在ensure
子句中; 但是用塊包裝東西在 Ruby 中無處不在,這就是最有效的方式,也是最符合 Ruby 精神的方式。 翻譯時,不要直接逐字翻譯,你會得到一些很奇怪的句子。 同樣,不要期望 Python 的所有內容都與 Ruby 一一對應。
從您發布的鏈接:
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
some code
Ruby 方式,像這樣(伙計,我可能做錯了:D):
def controlled_executor
begin
do_setup
yield
ensure
do_cleanup
end
end
controlled_executor do ...
some_code
end
顯然,您可以向controlled executor
(以通常方式調用)和 yield(在這種情況下,您還需要向塊添加參數)添加參數。 因此,為了實現你上面引用的內容,
class File
def my_open(file, mode="r")
handle = open(file, mode)
begin
yield handle
ensure
handle.close
end
end
end
File.my_open("temp.txt", "w") do |f|
f.write("hi")
raise Exception.new("spitesprite")
end
您始終可以使用try..catch..finally
塊,其中finally
部分包含要清理的代碼。
編輯:對不起, begin..rescue..ensure
:你想要開始begin..rescue..ensure
。
我相信你正在尋找確保。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.