루비의 Raii (또는 루비에서 자원을 관리하는 방법)
-
03-07-2019 - |
문제
나는 당신이 물체가 파괴 될 때 일어나는 일을 제어 할 수 없다는 것이 디자인으로 알고 있습니다. 또한 일부 클래스 메소드를 파이널 라이저로 정의한다는 것을 알고 있습니다.
그러나 C ++의 RAII에 대한 Ruby 관용구 (자원은 생성자에서 초기화되고 소멸자에서 닫힙니다)입니까? 사람들은 오류 나 예외가 발생하더라도 객체 내부에서 사용되는 자원을 어떻게 관리합니까?
사용 보장하다 공장:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
그러나 수업의 사용자 전체 시작 구속기 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 ++처럼?
해결책
그래서 사용자는 "전체 시작 구속기 chacha를해야한다는 것을 기억해야합니다" 결합시키다 rescue
/ensure
~와 함께 yield
.
class SomeResource
...
def SomeResource.use(*resource_args)
# create resource
resource = SomeResource.new(*resource_args) # pass args direct to constructor
# export it
yield resource
rescue
# known error processing
...
ensure
# close up when done even if unhandled exception thrown from block
resource.close
end
...
end
클라이언트 코드는 다음과 같이 사용할 수 있습니다.
SomeResource.use(connection_string) do | resource |
resource.do_something
... # whatever else
end
# after this point resource has been .close()d
사실 이것은 방법입니다 File.open
운영 - 첫 번째 답변을 최대한 혼란스럽게합니다 (글쎄 나의 직장 동료).
File.open("testfile") do |f|
# .. process - may include throwing exceptions
end
# f is guaranteed closed after this point even if exceptions are
# thrown during processing
다른 팁
어때 yield
블록에 리소스를 구입 하시겠습니까? 예시:
File.open("testfile") do |f|
begin
# .. process
rescue
# .. handle error
end
end
아니면 내가 아직도 이것을하고있는 문제는 C ++처럼?
예, C ++ 리소스 거래는 스택의 모든 것에 대해 암시 적으로 발생하기 때문에입니다. Stack Unound = Resource Destroyed = Destructors 호출 및 거기에서 물건을 해제 할 수 있습니다. 루비에는 소멸자가 없기 때문에 "다른 모든 것이 완료되면"그 자리가있는 곳에서 몇 번의 사이클을 지연시킬 수 있기 때문에 "다른 모든 일이 완료되면"아무것도 없습니다. 당신은 최종화기를 가지고 있지만 "림보"라고 불립니다 (모든 것이 사용 가능하지는 않습니다). GC에서 호출됩니다.
따라서 더 나은 릴리스 자원에 대한 핸들을 보유하고 있다면 명시 적으로 해제해야합니다. 실제로 이런 종류의 상황을 처리하는 올바른 관용구는
def with_shmoo
handle = allocate_shmoo
yield(handle)
ensure
handle.close
end
보다 http://www.rubycentral.com/pickaxe/tut_exceptions.html
Ruby에서는 An을 사용할 것입니다 ensure
성명:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
이는 Python, Java 또는 C# 사용자에게 Try / Catch / Minall과 같은 작동한다는 점에서 친숙합니다.