Ruby 中的 RAII(或者,如何在 Ruby 中管理资源)
我知道这是设计使然,你无法控制对象被销毁时会发生什么。 我还知道将某些类方法定义为终结器。
然而,C++ 的 RAII 的 ruby 习惯用法是这样的吗(资源在构造函数中初始化,在析构函数中关闭)? 即使发生错误或异常,人们如何管理对象内部使用的资源?
使用ensure有效:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
但是该类的用户必须记住每次需要调用open方法时都执行整个begin-rescue-ensure chacha。
例如,我将有以下类:
class SomeResource
def initialize(connection_string)
@resource_handle = ...some mojo here...
end
def do_something()
begin
@resource_handle.do_that()
...
rescue
...
ensure
end
def close
@resource_handle.close
end
end
如果异常是由其他类引起并且脚本退出,则resource_handle将不会关闭。
或者问题更多的是我仍然这样做太像C++了?
I know it's by design that you can't control what happens when an object is destroyed. I am also aware of defining some class method as a finalizer.
However is the ruby idiom for C++'s RAII (Resources are initialized in constructor, closed in destructor)? How do people manage resources used inside objects even when errors or exceptions happen?
Using ensure works:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
but users of the class have to remember to do the whole begin-rescue-ensure chacha everytime the open method needs to be called.
So for example, I'll have the following class:
class SomeResource
def initialize(connection_string)
@resource_handle = ...some mojo here...
end
def do_something()
begin
@resource_handle.do_that()
...
rescue
...
ensure
end
def close
@resource_handle.close
end
end
The resource_handle won't be closed if the exception is cause by some other class and the script exits.
Or is the problem more of I'm still doing this too C++-like?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这样用户就不必“必须记住执行整个 begin-rescue-ensure chacha”,将
rescue
/ensure
与结合起来产量。
客户端代码可以按如下方式使用它:
事实上,这就是
File.open
的操作方式 - 充其量使第一个答案令人困惑(嗯,这对我的同事来说)。So that users don't "have to remember to do the whole begin-rescue-ensure chacha" combine
rescue
/ensure
withyield
.Client code can use it as follows:
In fact this is how
File.open
operates - making the first answer confusing at best (well it was to my work colleagues).将资源
yield
给一个块怎么样? 例子:How about
yield
ing a resource to a block? Example:是的,因为在 C++ 中,堆栈上的所有内容都会隐式进行资源释放。 堆栈展开=资源被破坏=调用析构函数,并且可以从那里释放东西。 由于 Ruby 没有析构函数,因此不存在“当其他所有事情都完成时再执行此操作”的地方,因为抓取收集可能会比您所处的位置延迟几个周期。 你确实有终结器,但它们被称为“inlimbo”(并不是所有东西都可用),并且它们在 GC 上被调用。
因此,如果您持有某个最好释放的资源的句柄,则需要显式释放它。 事实上,处理这种情况的正确习惯用法是
Yes it is since in C++ resource deallocation happens implicitly for everything on the stack. Stack unwound = resource destroyed = destructors called and from there things can be released. Since Ruby has no destructors there is no "do that when everything else is done with" place since grabage collection can be delayed several cycles from where you are. You do have finalizers but they are called "in limbo" (not everything is available to them) and they get called on GC.
Therefore if you are holding a handle to some resource that better be released you need to release it explicitly. Indeed the correct idiom to handle this kind of situation is
http://www.rubycentral.com/pickaxe/tut_exceptions.html
请参阅Ruby 中的 ,您可以使用
ensure
语句:这对于 Python、Java 或 C# 用户来说很熟悉,因为它的工作方式类似于 try / catch / finally。
See http://www.rubycentral.com/pickaxe/tut_exceptions.html
In Ruby, you would use an
ensure
statement:This will be familiar to users of Python, Java, or C# in that it works like try / catch / finally.