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

여기 있습니다 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.



답변

키워드를 사용하십시오 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


답변

루프와 관련이없는 순방향 고토와 같은 블록에서 벗어날 수 있기를 원했습니다. 실제로 루프를 종료하지 않고 루프에있는 블록을 중단하고 싶습니다. 이를 위해 블록을 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 직원에게 도움이되기를 바랍니다.


답변

당신은 당신의 블록이 유용한 값 (예를 들어, 사용하는 경우 반환 할 경우 #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


답변

break대신 키워드 를 사용하십시오return


답변

아마도 당신은 사용할 수있는 내장 배열에서 특정 항목을 찾는 대신하는 방법 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


답변

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


답변

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