سؤال

في بيثون ، with يتم استخدام العبارة للتأكد من أن رمز التنظيف يتم استدعاؤه دائمًا ، بغض النظر عن الاستثناءات التي يتم طرحها أو عودة الوظائف. فمثلا:

with open("temp.txt", "w") as f:
    f.write("hi")
    raise ValueError("spitespite")

هنا ، تم إغلاق الملف ، على الرغم من استثناء. تفسير أفضل هنا.

هل هناك ما يعادل هذا البناء في روبي؟ أو هل يمكنك رمز واحد ، لأن روبي لديه استمرار؟

هل كانت مفيدة؟

المحلول

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

ومع ذلك ، هذه طريقة إجرائية للغاية للقيام بذلك. روبي هي لغة موجهة نحو الكائن ، مما يعني أن مسؤولية تنفيذ كتلة من الكود بشكل صحيح في سياق أ 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 Core والمكتبات القياسية ومكتبات الطرف الثالث.


ستكون المراسلات الأكثر قربًا لبروتوكول مدير سياق بيثون العام:

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

هذا هو المصطلح الذي يستخدمه روبي وواحد يجب أن تشعر بالراحة معه.

يمكنك استخدام حجج الكتلة للقيام بذلك في روبي:

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  

سأضيف فقط بعض التفسيرات للآخرين ؛ يجب أن يذهب الائتمان إليهم.

في الواقع ، في روبي ، رمز التنظيف كما قال آخرون ، في ensure بند؛ لكن لف الأشياء في الكتل في كل مكان في روبي ، وهكذا يتم ذلك بشكل أكثر كفاءة وأكثر بروح روبي. عند الترجمة ، لا تترجم مباشرة كلمة مقابل كلمة ، ستحصل على بعض الجمل الغريبة للغاية. وبالمثل ، لا تتوقع كل شيء من بيثون إلى مراسلات فردية إلى روبي.

من الرابط الذي نشرته:

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 Way ، شيء من هذا القبيل (رجل ، ربما أفعل كل هذا خطأ: D):

def controlled_executor
  begin
    do_setup
    yield
  ensure
    do_cleanup
  end
end

controlled_executor do ...
  some_code
end

من الواضح أنه يمكنك إضافة حجج إلى كليهما controlled executor (ليتم استدعاؤها بطريقة معتادة) ، وللتجمد (في هذه الحالة تحتاج إلى إضافة حجج إلى الكتلة أيضًا). وبالتالي ، لتنفيذ ما نقلت أعلاه ،

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

من الممكن الكتابة إلى ملف ذري في روبي ، مثل ذلك:

File.write("temp.txt", "hi")
raise ValueError("spitespite")

يعني كتابة كود مثل هذا أنه من المستحيل ترك ملف مفتوح.

يمكنك دائما استخدام أ try..catch..finally كتلة ، حيث finally يحتوي القسم على رمز للتنظيف.

تحرير: آسف ، أخطاء إملائية: تريد begin..rescue..ensure.

أعتقد أنك تبحث عن يضمن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top