روبي:أن كتلة تؤثر على المتغيرات المحلية في الأسلوب ؟
سؤال
أنا مجرد تعلم روبي و محاولة لفهم نطاق تنفيذ التعليمات البرمجية في كتل.على سبيل المثال, كنت تريد أن تكون قادرة على خلق كتلة يؤثر على الطريقة التي يتم إرفاق مثل:
def test(&block)
block.call() if block_given?
puts "in test, foo is #{foo}"
puts "in test, bar is #{bar}"
end
test() {
foo="this is foo"
bar="this is bar"
}
في هذه الحالة أنا لا أريد أن تعديل كتلة على الإطلاق-أنا أريد أن أكون قادرا على الكتابة باستخدام بسيطة متغير المراجع و لا المعلمات. فقط عن طريق إجراء تغييرات في 'اختبار' الطريقة في المثال أعلاه, هل من الممكن الوصول إلى تعريف المتغيرات في المنطقة ؟
مرة أخرى ، والهدف من ذلك هو ترك كتلة معدلة ، ولكن تكون قادرة على الوصول إلى إنشاء المتغيرات من داخل 'اختبار' بعد كتلة ينفذ.
المحلول
أولاً، block.call()
يتم مع yield
, ، ولا تحتاج إلى &block
المعلمة بهذه الطريقة
لا يمكنك عادةً أن تفعل ما تريد، فالكتل تكون مرتبطة عند إنشائها، وداخل الكتلة يمكنك رؤية المتغيرات المحلية المحددة في تلك اللحظة؛أسهل طريقة للقيام بما تريد، وهي ليست الطريقة التي ستستخدم بها الكتل بشكل طبيعي، هي:
def test()
foo = yield if block_given?
puts "in test, foo is #{foo}"
end
test() {
foo="this is foo"
}
ولكن هذا مجرد أثر جانبي لأن foo
يتم "إرجاعها" بواسطة الكتلة.إذا قمت بذلك بدلاً من ذلك:
def test()
foo = yield if block_given?
puts "in test, foo is #{foo}"
end
test() {
foo="this is foo"
"ha ha, no foo for you"
}
ستلاحظ أنه يفعل شيئًا مختلفًا.
وهنا المزيد من السحر:
def test(&block)
foo = eval "foo", block.binding
puts foo
block.call
foo = eval "foo", block.binding
puts foo
end
foo = "before test"
test() {
foo = "after test"
"ha ha, no foo for you"
}
هذا من شأنه أن يعمل نوعًا ما، لكنه ينكسر إذا قمت بإزالته foo = "before test"
لأن foo
يصبح متغيرًا محليًا في الكتلة وغير موجود في الربط.
ملخص:لا يمكنك الوصول إلى المتغيرات المحلية من كتلة، فقط المتغيرات المحلية حيث تم تعريف الكتلة والقيمة المرجعة للكتلة.
حتى هذا لن ينجح:
def test(&block)
eval "foo = 'go fish'", block.binding
block.call
bar = eval "foo", block.binding
puts bar
end
بسبب ال foo
في الربط يختلف عن المحلي في الكتلة (لم أكن أعرف ذلك، شكرًا).
نصائح أخرى
لا، لا يمكن أن تؤثر الكتلة على المتغيرات المحلية في المكان الذي يتم استدعاؤها فيه.
الكتل في روبي هي الإغلاق, مما يعني أنهم يلتقطون النطاق من حولهم عند إنشائهم.المتغيرات التي تكون مرئية عند إنشاء الكتلة هي تلك التي تراها.لو كان هناك أ foo
و bar
في الجزء العلوي من التعليمات البرمجية الخاصة بك، خارج أي طريقة، تلك الكتلة كان تغيير تلك عندما تم استدعاؤه.
يمكنك أن تفعل ما تريد من خلال أن تكون أكثر إسهابًا:
class Test
def foo(t)
@foo = t
end
def bar(t)
@bar = t
end
def test(&block)
self.instance_eval &block if block_given?
puts "in test, foo is #{@foo}"
puts "in test, bar is #{@bar}"
end
end
Test.new.test() {
foo "this is foo"
bar "this is bar"
}
يمكنك إنشاء طرق مثل attr_accessor
من شأنها أن تولد أداة ضبط مناسبة (ملف foo
و bar
طُرق).
def test(&block)
foo = yield
puts "in test, foo is #{foo}"
end
test { "this is foo" }
طباعة in test, foo is this is foo
قيمة العائد قيمة كتلة.
يمكنك أيضا تمرير المعلمات إلى العائد الذي ثم يمكن الوصول إليها من قبل كتلة باستخدام |param آخر| في كتلة بداية.
أيضا, تحقق من procs.
foo = "this is foo"
p = Proc.new { "foo is #{foo}" }
p.call
طباعة "foo is this is foo"
def test(p)
p.call
end
test p
طباعة "foo is this is foo"
def test2(p)
foo = "monkey"
p.call
end
test2 p
طباعة "foo is this is foo"