루비에서 "for"vs "each"


200

루비의 루프에 관한 간단한 질문이 있습니다. 컬렉션을 반복하는 두 가지 방법 사이에 차이점이 있습니까?

# way 1
@collection.each do |item|
  # do whatever
end

# way 2
for item in @collection
  # do whatever
end

이것들이 정확히 같은지 또는 미묘한 차이가 있는지 궁금합니다 (아마도 @collection0 일 때 ).

답변:


315

이것이 유일한 차이점입니다.

마다:

irb> [1,2,3].each { |x| }
  => [1, 2, 3]
irb> x
NameError: undefined local variable or method `x' for main:Object
    from (irb):2
    from :0

에 대한:

irb> for x in [1,2,3]; end
  => [1, 2, 3]
irb> x
  => 3

for루프를 사용하면 블록이 완료된 후에 반복자 변수가 계속 남아 있습니다. each루프를 사용하면 루프가 시작되기 전에 이미 로컬 변수로 정의되지 않은 한 루프가 아닙니다.

그 외에는 메소드의 for구문 설탕 일뿐 each입니다.

@collection입니다 nil모두 루프는 예외를 throw :

예외 : main : Object에 대한 정의되지 않은 지역 변수 또는 메소드`@collection '


3
x가 케이스에 남아있는 좋은 이유가 있습니까? 아니면이 나쁜 디자인입니까 : P? 나에게 이것은 대부분의 다른 언어와 비교할 때 직관적이지 않습니다.
cyc115

3
@ cyc115 for 시나리오를 x유지하는 이유 는 키워드가 새로운 범위를 만들지 않기 때문입니다. if , not , begin , for , while 등은 모두 현재 범위에서 작동합니다. 그러나 블록을 허용합니다. 블록은 항상 현재 범위 위에 자체 범위를 추가합니다. 추가 범위를 사용할 수 없으므로 블록에서 새 변수를 선언하면 (새로운 범위) 블록 외부에서 액세스 할 수 없습니다. #each
3limin4t0r

43

자세한 설명은 " For 루프의 악 "을 참조하십시오 (변수 범위 지정을 고려하면 약간의 차이가 있습니다).

사용 each은 Ruby의 관용적 인 사용으로 간주됩니다 .


@zachlatta : 알려 주셔서 감사합니다. 기사의 webarchive.org 변형을 가리 키도록 링크를 편집하겠습니다!
ChristopheD

1
graysoftinc.com/early-steps/the-evils-of-the-loop 는 이제 JEG2 사이트가 다시 온라인 상태가되면서 새로운 링크입니다.
pnomolos

30

첫 번째 예

@collection.each do |item|
  # do whatever
end

더 관용적 입니다. Ruby는 forand 같은 루핑 구문을 지원하지만 while일반적으로 블록 구문이 선호됩니다.

또 다른 미묘한 차이점은 for루프 내에서 선언 한 모든 변수는 루프 외부에서 사용할 수있는 반면 반복자 블록 내의 변수 는 사실상 비공개입니다.


while그리고 until실제로 고유 한 값을 생성하는 예를 들어, 또는 REPL의에 대한 각 등으로 대체 할 수없는 매우 구체적인 용도가 않습니다.
최대


2

차이가없는 것처럼 보이며 아래를 for사용합니다 each.

$ irb
>> for x in nil
>> puts x
>> end
NoMethodError: undefined method `each' for nil:NilClass
    from (irb):1
>> nil.each {|x| puts x}
NoMethodError: undefined method `each' for nil:NilClass
    from (irb):4

Bayard가 말했듯이, 각각은 관용적입니다. 더 많은 것을 숨기고 특별한 언어 기능이 필요하지 않습니다. Telemachus의 의견

for .. in .. 반복자를 루프 범위 밖에서 설정하므로

for a in [1,2]
  puts a
end

a루프가 완료된 후 정의 된 잎 . 어디로 each하지 않습니다. 어떤 사용을 선호하는 또 다른 이유는 each임시 변수가 짧은 기간을 살고 있기 때문에.


1
거기 변수 범위와 관련된 (yjerem, ChristopheD 및 수목원 언급 같은) 작은 차이.
Telemachus

잘못된, for사용하지 않습니다 each아래. 다른 답변을 참조하십시오.
akuhn

@akuhn 자세한 설명은이 질문 과 그 우수 답변을 참조하십시오 .
Sagar Pandya

2

절대 사용하지 for않으면 거의 추적 할 수없는 버그가 발생할 수 있습니다.

속지 마십시오. 이것은 관용적 코드 나 스타일 문제에 관한 것이 아닙니다. Ruby의 구현 for에는 심각한 결함이 있으므로 사용해서는 안됩니다.

다음은 for버그를 소개 하는 예입니다.

class Library
  def initialize
    @ary = []
  end
  def method_with_block(&block)
    @ary << block
  end
  def method_that_uses_these_blocks
    @ary.map(&:call)
  end
end

lib = Library.new

for n in %w{foo bar quz}
  lib.method_with_block { n }
end

puts lib.method_that_uses_these_blocks

인쇄물

quz
quz
quz

%w{foo bar quz}.each { |n| ... }인쇄물 사용

foo
bar
quz

왜?

A의 for루프 변수는 n한번에 단지 한 다음 정의는 모든 반복에 대한 용도가 있음을 정의한다. 따라서 각 블록 은 루프가 종료 될 때까지의 n값을 갖는 블록을 참조합니다 quz. 곤충!

에서 each루프 새로운 변수는 n가변 위의 예를 들어, 각 반복에 대해 정의 된 n별도의 세 번 정의된다. 따라서 각 블록 n은 올바른 값 을 가진 별도 를 참조 합니다.



0

루비에서 for 루프에 대해 구체적으로 설명하고 싶습니다. 다른 언어와 비슷한 구조처럼 보이지만 실제로는 루비의 다른 모든 반복 구조와 같은 표현입니다. 실제로 for는 각 반복자와 마찬가지로 Enumerable 객체와 함께 작동합니다.

전달 된 컬렉션은 각 반복자 메서드가있는 모든 개체 일 수 있습니다. 배열과 해시는 각 메소드를 정의하며 다른 많은 Ruby 객체도 정의합니다. for / in 루프는 지정된 객체의 각 메소드를 호출합니다. 반복자가 값을 생성함에 따라 for 루프는 각 값 (또는 각 값 세트)을 지정된 변수에 할당 한 다음 본문에서 코드를 실행합니다.

이것은 어리석은 예이지만 for 루프가 각 반복자가 수행하는 방식과 마찬가지로 각 메소드가있는 모든 객체에서 작동한다는 점을 보여줍니다.

class Apple
  TYPES = %w(red green yellow)
  def each
    yield TYPES.pop until TYPES.empty?
  end
end

a = Apple.new
for i in a do
  puts i
end
yellow
green
red
=> nil

그리고 이제 각 반복자 :

a = Apple.new
a.each do |i|
  puts i
end
yellow
green
red
=> nil

보시다시피, 둘 다 각 방법에 반응하여 값을 블록으로 되돌립니다. 여기에 모든 사람들이 언급했듯이 for 루프에서 각 반복자를 사용하는 것이 좋습니다. 나는 단지 for in 루프에 대해 마술이 없다는 점을 집으로 몰고 싶었습니다. 컬렉션의 각 메서드를 호출 한 다음 코드 블록에 전달하는 식입니다. 따라서 매우 드물게 사용되어야합니다. 각 반복자를 거의 항상 사용하십시오 (블록 범위의 추가 이점과 함께).


0
(1..4).each { |i| 


  a = 9 if i==3

  puts a 


}
#nil
#nil
#9
#nil

for i in 1..4

  a = 9 if i==3

  puts a

end
#nil
#nil
#9
#9

'for'루프에서 로컬 변수는 여전히 각 루프 후에 존재합니다. 'each'루프에서 각 루프 후에 로컬 변수가 새로 고쳐집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.