簡體   English   中英

相當於 Python 在 Ruby 中的“with”

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM