RAII في روبي (أو كيفية إدارة الموارد في روبي)
-
03-07-2019 - |
سؤال
أعلم أنه من خلال التصميم الذي لا يمكنك التحكم في ما يحدث عند كائن تدميرها.أنا على علم أيضا من تحديد بعض أسلوب فئة كما finalizer.
ومع ذلك هو روبي لغة C++'s RAII (الموارد تهيئة في منشئ مغلقة في destructor)?كيف الناس إدارة الموارد المستخدمة داخل الكائنات حتى عندما الأخطاء أو الاستثناءات يحدث ؟
باستخدام ضمان يعمل:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
ولكن المستخدمين من فئة يجب أن نتذكر أن تفعل كل begin-الإنقاذ-ضمان 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++-مثل ؟
المحلول
بحيث يمكن للمستخدمين لا "يجب أن نتذكر أن تفعل كل begin-الإنقاذ-ضمان 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++ الموارد deallocation يحدث ضمنا على كل شيء على المكدس.كومة المساس بها = الموارد دمرت = destructors دعا من هناك أشياء يمكن الافراج عنهم.منذ روبي لا المتلفات لا يوجد "تفعل ذلك عندما يتم كل شيء آخر مع" منذ grabage مجموعة يمكن أن يتأخر عدة دورات من أين أنت.لديك finalizers ولكن يطلق عليها "في طي النسيان" (ليس كل ما هو متاح لهم) وهم على GC.
لذلك إذا كنت عقد مؤشر إلى بعض الموارد من الأفضل أن يكون صدر تحتاج إلى الإفراج عنها صراحة.بل الصحيح لغة التعامل مع هذا النوع من الوضع
def with_shmoo
handle = allocate_shmoo
yield(handle)
ensure
handle.close
end
انظر http://www.rubycentral.com/pickaxe/tut_exceptions.html
في روبي, يمكنك أن تستخدم ensure
بيان:
f = File.open("testfile")
begin
# .. process
rescue
# .. handle error
ensure
f.close unless f.nil?
end
هذا سوف تكون مألوفة لمستخدمي Python, Java أو C# في أنه يعمل مثل try / catch / أخيرا.