روبي:أن كتلة تؤثر على المتغيرات المحلية في الأسلوب ؟

StackOverflow https://stackoverflow.com/questions/422536

  •  05-07-2019
  •  | 
  •  

سؤال

أنا مجرد تعلم روبي و محاولة لفهم نطاق تنفيذ التعليمات البرمجية في كتل.على سبيل المثال, كنت تريد أن تكون قادرة على خلق كتلة يؤثر على الطريقة التي يتم إرفاق مثل:

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"

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