루비 블록에서 헤어지는 방법?


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

나는 raise 사용에 대해 생각했지만 그것을 일반으로 만들려고 노력하고 있으므로에 특정 항목을 넣고 싶지 않습니다 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
고맙지 만 next는 배열의 다음 항목으로 만 이동합니다. 종료 할 수 있습니까?
user169930

리턴 값으로 다음에 호출해야합니다. "def f; x = yield; x를 넣습니다; end" "f 다음 3을 수행합니다;"o "를 넣습니다; end"콘솔에 3을 인쇄합니다 ( "o"는 없음).
Marcel Jackwerth

5
next, break, return, 당신은 비교할 수 없습니다
finiteloop

@MarcelJackwerth 가 인수 사용 next또는 사용에 대해 추가 한 의견에 대한 답변을 추가했습니다 break.
Tyler Holien 2016 년

8
redo기본적으로 현재 반복 내에서 블록의 맨 위로 실행을 이동 시키는 키워드라는 키워드도 있습니다 .
Ajedi32

59

루프와 관련이없는 순방향 고토와 같은 블록에서 벗어날 수 있기를 원했습니다. 실제로 루프를 종료하지 않고 루프에있는 블록을 중단하고 싶습니다. 이를 위해 블록을 1 회 반복 루프로 만들었습니다.

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

이것이 제목 줄을 기준으로 여기에 오는 다음 Google 직원에게 도움이되기를 바랍니다.


4
이것은 질문에 대한 유일한 답변이었습니다. 더 많은 포인트가 필요합니다. 감사.
Alex Nye

이것은 break와 next 모두에 동일하게 작동합니다. false가 true로 변경되면 다음은 모양을 유지하고 중단됩니다.
G. Allen Morris III

39

당신은 당신의 블록이 유용한 값 (예를 들어, 사용하는 경우 반환 할 경우 #map, #inject등), nextbreak도 인수에 동의합니다.

다음을 고려하세요:

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!
rkallensee

2
를 사용하여 특정 예제를 업데이트하십시오 break(아마도 하나 nextbreak..로 교체하십시오 .
Mike Graf

하나의 매우 흥미로운 것. break something작동 break(something)하지만 작동하지만 true && break(somehting)구문 오류가 발생합니다. 참고로 조건이 필요한 경우 if또는 unless사용해야합니다.
akostadinov


8

아마도 당신은 사용할 수있는 내장 배열에서 특정 항목을 찾는 대신하는 방법 each-ing 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
이와 같은 임의의 메소드를 Array 클래스에 추가하지 마십시오! 정말 나쁜 연습입니다.
mrbrdo

3
Rails는 왜 그렇게 할 수 없습니까?
wberry

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
break는 즉시 종료됩니다-next는 다음 반복으로 계속됩니다.
Ben Aubin

-3

루비 블록에서 벗어나려면 단순히 return키워드 를 사용하십시오return if value.nil?


2
return기능을 종료 하지 않습니까?
ragerdl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.