माणिक ब्लॉक से बाहर कैसे टूटना है?


420

यहाँ है Bar#do_things:

class Bar   
  def do_things
    Foo.some_method(x) do |x|
      y = x.do_something
      return y_is_bad if y.bad? # how do i tell it to stop and return do_things? 
      y.do_something_else
    end
    keep_doing_more_things
  end
end

और यहाँ है Foo#some_method:

class Foo
  def self.some_method(targets, &block)
    targets.each do |target|
      begin
        r = yield(target)
      rescue 
        failed << target
      end
    end
  end
end

मैंने उठाया का उपयोग करने के बारे में सोचा, लेकिन मैं इसे सामान्य बनाने की कोशिश कर रहा हूं, इसलिए मैं किसी भी विशिष्ट चीज़ को नहीं डालना चाहता Foo

जवाबों:


747

कीवर्ड का उपयोग करें next। यदि आप अगले आइटम पर जारी नहीं रखना चाहते हैं, तो उपयोग करें break

जब nextकिसी ब्लॉक के भीतर उपयोग किया जाता है, तो यह ब्लॉक को तुरंत बाहर निकलने का कारण बनता है, पुनरावृत्ति विधि पर नियंत्रण लौटाता है, जो फिर ब्लॉक को फिर से शुरू करके एक नया चलना शुरू कर सकता है:

f.each do |line|              # Iterate over the lines in file f
  next if line[0,1] == "#"    # If this line is a comment, go to the next
  puts eval(line)
end

जब एक ब्लॉक में उपयोग किया जाता है, breakतो ब्लॉक से बाहर जाने वाले पुनरावृत्त से ब्लॉक को नियंत्रित करता है, और इट्रेटर के आह्वान के बाद पहली अभिव्यक्ति के लिए:

f.each do |line|             # Iterate over the lines in file f
  break if line == "quit\n"  # If this break statement is executed...
  puts eval(line)
end
puts "Good bye"              # ...then control is transferred here

और अंत में, returnएक ब्लॉक का उपयोग :

return हमेशा लौटने के लिए एन्क्लोज़िंग विधि का कारण बनता है, भले ही यह ब्लॉकों के भीतर कितना गहरा घोंसला हो, (लैम्ब्डा के मामले को छोड़कर):

def find(array, target)
  array.each_with_index do |element,index|
    return index if (element == target)  # return from find
  end
  nil  # If we didn't find the element, return nil
end

2
धन्यवाद, लेकिन अगला केवल सरणी में अगले आइटम पर जाता है। क्या बाहर निकलना संभव है?
user169930

आपको रिटर्न वैल्यू के साथ अगला कॉल करना होगा। "डि एफ; x = यील्ड; एक्स; एंड;" को "अगले 3 एफ करते हैं," ओ "डालते हैं; एंड" इस प्रिंट्स 3 (लेकिन नो "ओ") कंसोल पर।
मार्सेल जैकवर्थ

5
next, break, return, आप तुलना नहीं कर सकते
finiteloop

मैंने टिप्पणी का विस्तार करते हुए एक उत्तर जोड़ा @MarcelJackwerth ने उपयोग करने के बारे में जोड़ा nextयाbreak एक तर्क के साथ।
टायलर होलियन

8
एक कीवर्ड भी है redo , जो मूल रूप से केवल निष्पादन को वर्तमान पुनरावृत्ति के भीतर ब्लॉक के शीर्ष पर वापस ले जाता है।
Ajedi32

59

मैं बस एक ब्लॉक से बाहर तोड़ने में सक्षम होना चाहता था - एक फारवर्ड गोटो की तरह, वास्तव में लूप से संबंधित नहीं। वास्तव में, मैं उस ब्लॉक को तोड़ना चाहता हूं जो लूप को समाप्त किए बिना लूप में है। ऐसा करने के लिए, मैंने ब्लॉक को एक पुनरावृति लूप बनाया:

for b in 1..2 do
    puts b
    begin
        puts 'want this to run'
        break
        puts 'but not this'
    end while false
    puts 'also want this to run'
end

आशा है कि यह अगले गोगलर की मदद करता है जो विषय रेखा के आधार पर यहां उतरते हैं।


4
यह एकमात्र प्रतिक्रिया थी जिसने सवाल का जवाब दिया जैसा कि इसे रखा गया था। अधिक अंक का वर्णन करता है। धन्यवाद।
एलेक्स नी डे

यह ब्रेक और नेक्स्ट दोनों के लिए समान है। अगर असत्य को सच में बदल दिया जाए, तो अगली नज़र में बने रहेंगे और टूट जाएगा।
जी एलन मॉरिस III

39

यदि आप चाहते हैं कि आपका ब्लॉक एक उपयोगी मान लौटाए (जैसे उपयोग करते समय #map,#inject , आदि), nextऔरbreak भी एक तर्क स्वीकार करते हैं।

निम्नलिखित को धयान मे रखते हुए:

def contrived_example(numbers)
  numbers.inject(0) do |count, x|
    if x % 3 == 0
      count + 2
    elsif x.odd?
      count + 1
    else 
      count
    end
  end
end

बराबर का उपयोग next :

def contrived_example(numbers)
  numbers.inject(0) do |count, x|
    next count if x.even?
    next (count + 2) if x % 3 == 0
    count + 1
  end
end

बेशक, आप हमेशा एक विधि में आवश्यक तर्क निकाल सकते हैं और अपने ब्लॉक के अंदर से कॉल कर सकते हैं:

def contrived_example(numbers)
  numbers.inject(0) { |count, x| count + extracted_logic(x) }
end

def extracted_logic(x)
  return 0 if x.even?
  return 2 if x % 3 == 0
  1
end

1
के लिए तर्क के साथ संकेत के लिए धन्यवाद break!
13

2
w / एक विशिष्ट उदाहरण का उपयोग करते हुए आप अपडेट कर लें सकता है break(शायद सिर्फ अपने में से एक की जगह nextके साथ break..
माइक ग्राफ

एक बहुत ही दिलचस्प बात। break somethingकाम करता है, break(something)काम करता है, लेकिन true && break(somehting)एक सिंटैक्स त्रुटि देता है। सिर्फ आपकी जानकारी के लिए। शर्त आवश्यक है, तो ifया unlessजरूरतों को इस्तेमाल किया जा रहा।
अकोस्टैडिनोव


8

शायद आप उपयोग कर सकते हैं में निर्मित किसी सरणी में विशेष आइटम खोजने के बजाय, के लिए तरीके eachआईएनजी targetsऔर हाथ से सब कुछ कर। कुछ उदाहरण:

class Array
  def first_frog
    detect {|i| i =~ /frog/ }
  end

  def last_frog
    select {|i| i =~ /frog/ }.last
  end
end

p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"

एक उदाहरण कुछ इस तरह से होगा:

class Bar
  def do_things
    Foo.some_method(x) do |i|
      # only valid `targets` here, yay.
    end
  end
end

class Foo
  def self.failed
    @failed ||= []
  end

  def self.some_method(targets, &block)
    targets.reject {|t| t.do_something.bad? }.each(&block)
  end
end

2
मनमानी तरीकों को जोड़कर ऐरे क्लास की तरह न करें! यह वास्तव में बुरा अभ्यास है।
म्रब्रादो

3
रेल करता है, तो वह क्यों नहीं कर सकता है?
15

2
@wberry यह कहना नहीं है कि यह जरूरी होना चाहिए । ;) सामान्य तौर पर, हालांकि, बंदर पैचिंग कोर कक्षाओं से बचना सबसे अच्छा है, जब तक कि आपके पास एक बहुत अच्छा कारण न हो (यानी कुछ बहुत ही उपयोगी सामान्य कार्यक्षमता जो कि बहुत सारे अन्य कोड उपयोगी पाएंगे)। फिर भी, हल्के ढंग से चलना क्योंकि एक बार जब एक वर्ग भारी बंदर-पैच होता है, तो पुस्तकालयों के लिए एक-दूसरे पर चलना शुरू करना और कुछ बहुत ही अजीब व्यवहार करना आसान होता है।
blm768

2

nextऔर breakइस सरलीकृत उदाहरण में सही काम करने के लिए लगता है!

class Bar
  def self.do_things
      Foo.some_method(1..10) do |x|
            next if x == 2
            break if x == 9
            print "#{x} "
      end
  end
end

class Foo
    def self.some_method(targets, &block)
      targets.each do |target|
        begin
          r = yield(target)
        rescue  => x
          puts "rescue #{x}"
        end
     end
   end
end

Bar.do_things

आउटपुट: 1 3 4 5 6 7 8


2
ब्रेक तुरंत समाप्त होता है - अगला अगले पुनरावृत्ति के लिए जारी रहता है।
बेन ऑबिन

-3

माणिक ब्लॉक से बाहर तोड़ने के लिए बस returnकीवर्ड का उपयोग करेंreturn if value.nil?


2
returnफ़ंक्शन से बाहर नहीं निकलता है?
ragerdl
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.