web-dev-qa-db-ja.com

do block vsブレース{}の使用

Rubyを初めて使用する場合は、初心者用手袋を着用してください。

次の2つのスニペットに違いはありますか(あいまいまたは実用的)?

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

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

ブレース構文を使用すると、ブロックを1行に配置できることがわかります

my_array.each { |item| puts item }

しかし、それ以外に、ある構文を他の構文よりも使用する説得力のある理由はありますか?

111
Alan Storm

Ruby cookbook は、ブラケット構文の優先順位がdo..endよりも高いことを示します

ブラケット構文はdo..end構文よりも優先順位が高いことに注意してください。次の2つのコードスニペットを検討してください。

1.upto 3 do |x|
  puts x
end

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

2番目の例は、括弧が使用されている場合にのみ機能します。1.upto(3) { |x| puts x }

98
YOU

これは少し古い質問ですが、_{}_と_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
_
69
bkdir

一般的に、慣例では、メソッド呼び出しや比較などの小さな操作を行うときに{}を使用するので、これは完全に理にかなっています。

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を使用し、ブロックロジックがシンプルで単純/単一のコード行の場合は{}

39
nas

Rubyのブロックに対してdo end{ }を選択するための2つの一般的なスタイルがあります。

最初の非常に一般的なスタイルは、Ruby on Railsによって普及し、単一行と複数行の単純なルールに基づいています。

  • 単一行ブロックには中括弧{ }を使用します
  • 複数行ブロックにはdo endを使用します

これは、do/endが1ライナーでひどく読み取りますが、複数行ブロックの場合、閉じている}を独自の行にハングさせたままにすることは、Rubyでendを使用する他のすべてと矛盾するため、モジュール、クラスおよびメソッド定義(defなど)および制御構造(ifwhilecaseなど)

あまり見られない2番目のスタイルは、セマンティック、または「 Weirich Braces 」として知られ、後期の偉大なルビイストJim Weirichによって提案されました。

  • 手続き型ブロックにはdo endを使用します
  • 機能ブロックには中括弧{ }を使用します

これは、ブロックがその戻り値で評価される場合、チェーン可能である必要があり、{}ブレースがメソッドチェーンに適していることを意味します。 。

一方、ブロックがその副作用について評価される場合、戻り値は重要ではなく、ブロックは「実行中」です「何か、それで連鎖する意味がありません。

構文のこの区別は、ブロックの評価に関する視覚的な意味と、戻り値を考慮する必要があるかどうかを伝えます。

たとえば、ここではブロックの戻り値がすべてのアイテムに適用されます。

items.map { |i| i.upcase }

ただし、ここではブロックの戻り値を使用していません。手続き的に動作しており、doing副作用があります:

items.each do |item|
  puts item
end

セマンティックスタイルのもう1つの利点は、ブロックに行が追加されたからといって、中かっこを実行/終了する必要がないことです。

観察として、偶然にもfunctionalブロックは1ライナーであり、proceduralブロック(例:config)は複数行です。したがって、Weirichスタイルに従うと、Railsスタイルとほぼ同じになります。

5
Andrew Vit

私は長年Weirichスタイルを使用していましたが、これから常にブレースを使用に移動しました。ブロックスタイルの情報を使用したことを覚えていないので、定義がちょっとあいまいです。例えば:

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

これらは性的または機能的ですか?

そして、私の意見では行数の問題は役に立たない。行が1行以上あるかどうか、そして行を追加または削除しただけでスタイルを変更する必要があるのはなぜですか?

1
iGEL