465 Stimmen

Wie kommt man aus einer Rubinblockade heraus?

Hier ist 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

Und hier ist 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

Ich habe daran gedacht, raise zu verwenden, aber ich versuche, es generisch zu machen, also möchte ich nichts Spezielles einfügen Foo .

808voto

JRL Punkte 74309

Verwenden Sie das Schlüsselwort next . Wenn Sie nicht mit dem nächsten Punkt fortfahren möchten, verwenden Sie break .

いつ next innerhalb eines Blocks verwendet wird, wird der Block sofort beendet und die Kontrolle an die Iteratormethode zurückgegeben, die dann eine neue Iteration beginnen kann, indem sie den Block erneut aufruft:

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

Bei Verwendung in einem Block, break überträgt die Kontrolle aus dem Block, aus dem Iterator, der den Block aufgerufen hat, und zum ersten Ausdruck, der auf den Aufruf des Iterators folgt:

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

Und schließlich ist die Verwendung von return in einem Block:

return bewirkt immer, dass die umschließende Methode zurückkehrt, unabhängig davon, wie tief sie in Blöcken verschachtelt ist (außer im Fall von Lambdas):

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

70voto

Don Law Punkte 1271

Ich wollte nur in der Lage sein, aus einem Block auszubrechen - eine Art Vorwärts-Goto, nicht wirklich mit einer Schleife verbunden. Tatsächlich möchte ich einen Block, der sich in einer Schleife befindet, verlassen, ohne die Schleife zu beenden. Um das zu erreichen, habe ich den Block zu einer Schleife mit einer Iteration gemacht:

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

Ich hoffe, das hilft dem nächsten Googler, der aufgrund der Betreffzeile hier landet.

42voto

Tyler Holien Punkte 4501

Wenn Sie möchten, dass Ihr Block einen nützlichen Wert zurückgibt (z. B. bei der Verwendung von #map , #inject , usw.), next y break auch ein Argument akzeptieren.

Bedenken Sie Folgendes:

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

Die Entsprechung mit 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

Natürlich können Sie die benötigte Logik auch in eine Methode extrahieren und diese innerhalb Ihres Blocks aufrufen:

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

23voto

AShelly Punkte 33678

Verwenden Sie das Schlüsselwort break anstelle von return

8voto

August Lilleaas Punkte 52649

Vielleicht können Sie die eingebauten Methoden verwenden, um bestimmte Elemente in einem Array zu finden, anstatt die each -ing targets und alles von Hand zu machen. Ein paar Beispiele:

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"

Ein Beispiel dafür wäre die folgende Vorgehensweise:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X