سؤال

أريد أن أكون قادرا على كتابة لامدا/Proc في روبي البرمجية تسلسل بحيث لا يمكن الكتابة على القرص ، ومن ثم تنفيذ لامدا في وقت لاحق.نوع من مثل...

x = 40
f = lambda { |y| x + y }
save_for_later(f)

في وقت لاحق, في تشغيل منفصل من روبي مترجم, أريد أن أكون قادرا على أن أقول...

f = load_from_before
z = f.call(2)
z.should == 42

المشير.تفريغ لا تعمل Procs.أنا أعرف بيرل قد البيانات::تفريغ::غاسل, و في اللثغة هذا هو تافهة.ولكن هل هناك طريقة للقيام بذلك في روبي ؟ وبعبارة أخرى ، ما من شأنه أن يكون تنفيذ save_for_later?

تحرير: جوابي أدناه هو جميل لكنه لا يغلق على المتغيرات الحرة (مثل x) و تسلسل لهم جنبا إلى جنب مع امدا.حتى في بلدي على سبيل المثال ...

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"

...سلسلة الانتاج لا يشمل تعريف x.هل هناك حل أن يأخذ هذا بعين الاعتبار ، ربما عن طريق التسلسلية رمز الجدول ؟ يمكنك الوصول إلى هذا في روبي ؟

تحرير 2:لقد قمت بتحديث جوابي لدمج التسلسلية المتغيرات المحلية.هذا يبدو مقبولا.

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

المحلول

استخدام Ruby2Ruby

def save_for_later(&block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}')
end

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"
g = eval(s)
# => #<Proc:0x4037bb2c@(eval):1>
g.call(2) 
# => 42

هذا شيء عظيم, ولكن لا إغلاق ما يزيد على المتغيرات الحرة (مثل x) و تسلسل لهم جنبا إلى جنب مع امدا.

إلى تسلسل المتغيرات أيضا, يمكنك تكرار عبر local_variables و تسلسل لهم كذلك.ولكن المشكلة هي أن local_variables من داخل save_for_later يصل فقط c و s في الكود أعلاه-أيالمتغيرات المحلية إلى رمز التسلسل ، وليس المتصل.لذلك يجب دفع الاستيلاء على المتغيرات المحلية وقيمها إلى المتصل.

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

باستخدام هذا النهج بسيط, يمكنك الحصول على ما يلي:

def save_for_later(local_vars, &block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}')
end

x = 40
s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y }
# => "lambda { |y| _ = 40; x = 40;\n  (x + y)\n}"

# In a separate run of Ruby, where x is not defined...
g = eval("lambda { |y| _ = 40; x = 40;\n  (x + y)\n}")
# => #<Proc:0xb7cfe9c0@(eval):1>
g.call(2)
# => 42

# Changing x does not affect it.
x = 7
g.call(3)
# => 43

نصائح أخرى

استخدام sourcify

هذا سوف يعمل على روبي 1.8 أو 1.9.

def save_for_later(&block)
  block.to_source
end

x = 40
s = save_for_later {|y| x + y }
# => "proc { |y| (x + y) }"
g = eval(s)
# => #<Proc:0x00000100e88450@(eval):1>
g.call(2) 
# => 42

انظر جوابي أخرى من أجل التقاط المتغيرات الحرة.

التحديث:الآن يمكنك أيضا استخدام serializable_proc الأحجار الكريمة التي تستخدم sourcify ، ويلتقط المحلية سبيل المثال, صف المتغيرات العالمية.

تحقق من إجابات ل هذا السؤال .

روبي قد المشير الفئة التي لديها تفريغ الطريقة التي يمكنك الاتصال.

نلقي نظرة هنا:

http://rubylearning.com/satishtalim/object_serialization.html

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