do 블록 대 중괄호 {} 사용


112

루비를 처음 접한다면 초보자 장갑을 착용하십시오.

다음 두 스 니펫간에 차이 (모호하거나 실용적인)가 있습니까?

my_array = [:uno, :dos, :tres]
my_array.each { |item| 
    puts item
}

my_array = [:uno, :dos, :tres]
my_array.each do |item| 
    puts item
end

중괄호 구문을 사용하면 블록을 한 줄에 배치 할 수 있습니다.

my_array.each { |item| puts item }

하지만 그 외에 하나의 구문을 다른 구문보다 사용해야하는 설득력있는 이유가 있습니까?


5
좋은 질문입니다. 경험이 많은 루비가들이 선호하는 것에도 관심이 있습니다.
조나단 스털링




1
eval ( "my_array.each do | item |; puts item; end")과 같은 작업을 수행 할 때만 유용하지만 do 블록의 한 줄을 작성할 수도 있지만 eval 및 따옴표없이 irb 또는 pry에서 작동합니다. 선호하는 상황이 발생할 수 있습니다. 그래도 나에게 묻지 마십시오. 그것은 조사해야 할 또 다른 주제입니다.
Douglas G. Allen

답변:


100

Ruby 쿡북에 따르면 대괄호 구문이do..end

대괄호 구문은 do..end 구문보다 우선 순위가 높습니다. 다음 두 코드 스 니펫을 고려하십시오.

1.upto 3 do |x|
  puts x
end

1.upto 3 { |x| puts x }
# SyntaxError: compile error

두 번째 예는 괄호가 사용될 때만 작동합니다. 1.upto(3) { |x| puts x }


7
아, 알았어. 따라서 우선 순위 때문에 do를 사용하면 블록을 추가 매개 변수로 전달하지만 대괄호를 사용하면 블록을 메소드 호출 결과의 첫 번째 매개 변수로 전달합니다. 왼쪽.
Alan Storm

2
나는 종종 짧은 답변을 선호하지만 bkdir의 답변은 훨씬 더 명확합니다.
야 쿠트

70

이것은 조금 오래된 질문하지만 난에 대한 추가 비트를 설명하려고 싶습니다 {}do .. end

전에 말했듯이

대괄호 구문은 do..end보다 우선 순위가 높습니다.

그러나 이것이 어떻게 차이를 만드는지 :

method1 method2 do
  puts "hi"
end

이 경우 method1은의 블록으로 호출 do..end되고 method2는 method1에 인수로 전달됩니다! 이는method1(method2){ puts "hi" }

하지만 당신이 말한다면

method1 method2{
  puts "hi"
}

그러면 method2가 블록과 함께 호출되고 반환 된 값이 method1에 인수로 전달됩니다. 다음과 같습니다.method1(method2 do puts "hi" end)

def method1(var)
    puts "inside method1"
    puts "method1 arg = #{var}"
    if block_given?
        puts "Block passed to method1"
        yield "method1 block is running"
    else
        puts "No block passed to method1"
    end
end

def method2
    puts"inside method2"
    if block_given?
        puts "Block passed to method2"
        return yield("method2 block is running")
    else
        puts "no block passed to method2"
        return "method2 returned without block"
    end
end

#### test ####

method1 method2 do 
    |x| puts x
end

method1 method2{ 
    |x| puts x
}

#### 출력 ####

#inside method2
#no block passed to method2
#inside method1
#method1 arg = method2 returned without block
#Block passed to method1
#method1 block is running

#inside method2
#Block passed to method2
#method2 block is running
#inside method1
#method1 arg = 
#No block passed to method1

39

일반적으로 규칙은 {}메서드 호출이나 비교 등과 같은 작은 작업을 수행 할 때 사용 하는 것이므로 다음과 같이 완벽합니다.

some_collection.each { |element| puts element }

그러나 여러 줄로 이동하는 약간 복잡한 논리가 있으면 다음 do .. end과 같이 사용하십시오 .

1.upto(10) do |x|
  add_some_num = x + rand(10)
  puts '*' * add_some_num
end

기본적으로 블록 논리가 여러 줄로 이동하고 동일한 줄에 맞출 수없는 do .. end경우 를 사용 하고 블록 논리가 단순하고 코드의 단순 / 한 줄이면 {}.


6
여러 줄 블록에 do / end를 사용하는 데 동의하지만 추가 메서드를 블록 끝에 연결하는 경우 중괄호를 사용합니다. 스타일 적으로 나는 do ... end.method (). method보다 {...}. method (). method ()를 좋아하지만 그저 나일 수도 있습니다.
The Tin Man

1
동의하지만, 블록이있는 메서드의 결과를 의미있는 변수에 할당 한 다음 result_with_some_condition = method{|c| c.do_something || whateever}; result_with_some_condition.another_method좀 더 쉽게 이해할 수 있도록 다른 메서드를 호출하는 것을 선호합니다 . 그러나 일반적으로 나는 열차 사고를 피할 것입니다.
nas

이 스타일이 왜 그렇게 인기가 있는지 궁금합니다. "우리는 항상 이런 식으로했다"는 것 외에 다른 이유가 있습니까?
iGEL

9

Ruby에서 블록에 대한 선택 do end과 선택을위한 두 가지 일반적인 스타일이 있습니다 { }.

첫 번째이자 매우 일반적인 스타일은 Ruby on Rails에 의해 대중화되었으며 단일 대 다중 라인의 간단한 규칙을 기반으로합니다.

  • { }한 줄 블록에 중괄호 사용
  • 사용 do end멀티 라인 블록

DO / 끝 닫는 떠나, 한 - 라이너에 심하게 읽지 만 여러 줄의 블록 때문에 의미가 있습니다 }자신의 줄에 매달려 다른 모든 것을 그 용도와 일관성이 end같은 모듈, 클래스 및 메소드 정의로 루비 ( def등 .) 및 제어 구조 ( if, while,case 등)

두 번째로 덜 자주 사용되는 스타일은 시맨틱 (Semantic) 또는 " Weirich Braces " 로 알려져 있으며 고인이 된 위대한 루비 이스트 Jim Weirich가 제안했습니다.

  • 사용하다 do end 절차 블록
  • { }기능 블록에 중괄호 사용

즉, 블록이 반환 값에 대해 평가 될 때 체인이 가능해야하며{} 중괄호가 메서드 체인에 더 적합합니다.

반면에 블록이 부작용에 대해 평가 될 때 되면 반환 값은 중요하지 않으며 블록은 단지 무언가를 "실행"하기 때문에 연결하는 것이 의미가 없습니다.

구문에서 이러한 구분은 블록 평가에 대한 시각적 의미와 반환 값에 대해 신경을 써야하는지 여부를 전달합니다.

예를 들어, 여기에서 블록의 반환 값은 모든 항목에 적용됩니다.

items.map { |i| i.upcase }

그러나 여기서는 블록의 반환 값을 사용하지 않습니다. 그것은 절차 적으로 운영하고 있어요 하고 그것으로 부작용을 :

items.each do |item|
  puts item
end

시맨틱 스타일의 또 다른 이점은 블록에 줄이 추가 되었기 때문에 수행 / 종료하기 위해 중괄호를 변경할 필요가 없다는 것입니다.

관찰하자면 우연히 기능 블록은 종종 한 줄이며 절차 적 블록 (예 : 구성)은 여러 줄입니다. 따라서 Weirich 스타일을 따르면 Rails 스타일과 거의 동일하게 보입니다.


1

몇 년 동안 Weirich 스타일을 사용했지만 항상 중괄호를 사용하기 위해이 스타일에서 벗어났습니다 . 블록 스타일의 정보를 사용한 적이 없었고 정의가 모호합니다. 예를 들면 :

date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }

이것은 procudual 또는 기능적입니까?

그리고 줄 수는 내 의견으로는 쓸모가 없습니다. 선이 1 개 이상 있는지, 그리고 선을 추가하거나 제거했다는 이유만으로 스타일을 정확히 변경해야하는 이유를 알고 있습니다.

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