2011-02-06 5 views
33

あなたが共有できるRubyブロックの最も良い説明は何ですか?Rubyブロックのベスト解説?

ブロックを取ることができる使用法と書き込みコードの両方がありますか?

+1

ブロックの概念を紹介していますか、それとも網羅的なリファレンスですか? – Phrogz

+16

あなたは、回答を必要としない、受け入れるつもりはない、議論に参加するつもりはないという質問をして、担当者のためにトローリングしていますか?あなたが返信するかどうかがわかります。 – Phrogz

+0

これは役に立つスレッドです:http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ – Lucio

答えて

6

本「Programming Ruby」には、explanation of blocks and using themという本があります。 1.9+で

、ブロックに渡されたパラメータリストは、ローカル変数を定義することができ、より洗練されたなった:

do |a,b;c,d| 
    some_stuff 
end 

;c,dから値を受けていないブロック、内部に二つの新しいローカル変数を宣言呼び出されたルーチンのyield文。 Ruby 1.9+では、変数がブロック外に存在する場合、ブロック内の同じ名前の変数によってブロックされないことが保証されています。これは新しい動作です。 1.8はそれらにぶつかるだろう。

def blah 
    yield 1,2,3,4 
end 

c = 'foo' 
d = 'bar' 

blah { |a, *b; c,d| 
    c = 'hello' 
    d = 'world' 
    puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}", "d: #{d}" 
} 

puts c, d 
# >> a: 1 
# >> b: 2,3,4 
# >> c: hello 
# >> d: world 
# >> foo 
# >> bar 

パラメータのリストで働く「スプラット」オペレータ*は、もあります:

do |a,*b| 
    some_stuff 
end 

は「A」に複数の値の最初のを割り当てます、そしてすべての残りの部分は、捕獲されるだろう配列のように扱われる "b"の中にある。 *a変数を次のようになります。

do |*a,b| 
    some_stuff 
end 

bに渡される最後の1を除くすべての変数で渡さをキャプチャします。そして、同様に前の2つに:

do |a,*b,c| 
    some_stuff 
end 

aに最初の値、cへの最後の値とbへのすべて/任意の中間値を割り当てます。

私はそれがかなり強力で滑らかだと思います。例えば

def blah 
    yield 1,2,3,4 
end 

blah { |a, *b| puts "a: #{a}", "b: #{b.join(',')}" } 
# >> a: 1 
# >> b: 2,3,4 

blah { |*a, b| puts "a: #{a.join(',')}", "b: #{b}" } 
# >> a: 1,2,3 
# >> b: 4 

blah { |a, *b, c| puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}" } 
# >> a: 1 
# >> b: 2,3 
# >> c: 4 
19

Why's (poignant) guide to rubyより:

中括弧で囲まれた任意のコードである ブロック。

2.times { print "Yes, I've used chunky bacon in my examples, but never again!" }です。

ブロックを使用すると、 命令のセットをグループ化して、 をプログラムに渡すことができます。 中括弧は、 コードを引き取ってまとめている カニのピンチャーの外観を示しています。 この2つのペンチを見るときは、内部にコード を押し込んだ を覚えておいてください。それはだ のような彼らはひそかに静止 操作のために、あなたの手のひらに を隠すことができキラキラ 透明ケースに詰め込ま 小さな鉛筆や顕微鏡紙、 すべてを詰めていますショッピングモールで販売 それらのほとんどのハローキティボックス。ブロックが のように多くのsquintingを必要としないことを除いて。中括弧 中括弧は の単語doとendのために取引することができます。 ブロックが1行よりも長い場合はいいです。

loop do 
    print "Much better."  
    print "Ah. More space!" 
    print "My back was killin' me in those crab pincers." 
end 

ブロック引数はパイプで 文字を囲み、カンマで区切られた変数の セットです。

|x|, |x,y|, and |up, down, all_around| are examples. 

ブロックの引数は、ブロックの先頭に を使用しています。上記の例で

{ |x,y| x + y } 
、| X、Y |議論です。議論の後、私たちは コードを少し持っています。式x + yは、2つの引数を一緒に加算します。私は のようにパイプの文字 をトンネルを表すものと考えています。彼らは に、 変数が滑り落ちるシュートの出現を示します。 (xは ダウンスプレッドワシになり、一方できれいに は彼女の足を横切る)。このシュートは、ブロック間の通路である と、その周りの ワールドとして機能します。このシュート(またはトンネル) をブロックに渡した変数は です。

+16

「中括弧で囲まれたコードはブロックです」 **ハッシュ**です。 – Meltemi

+1

これらの例が返すものについては説明しません。理解できません。 –

+0

私の家庭教師になってください!このような明快な方法で説明していただきありがとうございます。 – Benjamints

3

ブロックはRubyでコードをグループ化する方法です。ブロックを書くには2通りの方法があります。 1つはdo..endステートメントを使用し、もう1つは中括弧でコードを囲んでいます:{}。ブロックはRubyプログラミング言語のオブジェクトとみなされ、デフォルトではすべての関数が暗黙のブロック引数を受け入れます。 ||

 
2.times { puts 'hi' } 
2.times do 
    puts 'hi' 
end 

ブロックは垂直バーの内側にカンマで区切られた引数のリストを受け取ることができます。

は、ここで同じことを行うブロックの2つの例です。例えば:(ルビー1.9.2で)

 
[1,2].map{ |n| n+2 } # [3, 4] 

ブロックは、明示的にローカル変数を持つことができます。

 
x = 'hello' 
2.times do |;x| 
    x = 'world' 
    puts x 
end 

=> world 
=> world 

ローカル変数は、パラメータと組み合わせることができます。

 
[1,2].map{ |n;x| n+2 } 

すべての機能を受け取ることができます既定のブロック引数:

 
def twice 
    yield 
    yield 
end 

twice { puts 'hello' } 
=> hello 
=> hello 

do..endブロックと{}ブロックの違いは何ですか?慣習では、{}ブロックは1行にあります。エンドブロックは複数の行にまたがっています。なぜなら、このように読みやすいためです。主な違いは、しかし優先としなければならない。

 
array = [1,2] 

puts array.map{ |n| n*10 } # puts (array.map{ |n| n*10 }) 
=> 10 
=> 20 

puts array.map do |n| n*10 end # (puts array.map) do |n| n*10 end 
=> <Enumerator:0x00000100862670> 
2

ブロックは、いくつかの厄介な制限と匿名のファーストクラスの手続きのための軽量リテラルです。彼らはほとんどすべての他のプログラミング言語での作業として、Rubyで同じように動作している前述の制限を、モジュロ:

  • ブロックが唯一の引数リストに
  • ブロックが表示されることが最大1つを表示することができ引数リストに(そして、それは最後の引数でなければなりません)
+0

丁寧な答えですが、Procオブジェクトとの関係は不可欠ですね。 – maerics

+0

@maerics Blocksの網羅的なリソースにとって不可欠なことは?はい。ブロックの説明には不可欠です(私は初心者のためにそれらを紹介すると解釈します)。間違いなく、IMO。 – Phrogz

+0

ありがとうございます。 '{puts" hello "}"がうまくいかない理由を理解するのを助ける唯一の答えはあなたのものです。全く許されない?それは変だ。 –

27

私はわずかに変更さthis answerから私自身の説明を、アップ提供:Rubyで

「ブロック」とは、「一般的なプログラミング用語と同じではありませんコードブロック "o r "コードブロック"。

下記(無効)Rubyコードが実際に働いたことがしばらくふり:

def add10(n) 
    puts "#{n} + 10 = #{n+10}" 
end 

def do_something_with_digits(method) 
    1.upto(9) do |i| 
    method(i) 
    end 
end 

do_something_with_digits(add10) 
#=> "1 + 10 = 11" 
#=> "2 + 10 = 12" 
... 
#=> "9 + 10 = 19" 

をそのコードが無効であるが、その方法にはいくつかのコードを意図通過し、その方法は、あるコードを実行有しますRubyではさまざまな方法で可能です。それらの方法の1つが「ブロック」です。

Rubyのブロックは、メソッドに非常によく似ています。いくつかの引数をとり、それらのコードを実行することができます。 foo{ |x,y,z| ... }またはfoo do |x,y,z| ... endが表示されている場合は、3つのパラメータをとり、...を実行するブロックです。 (あなたもupto方法は、上記ブロックを渡されていることを表示される場合があります。)

をブロックはRubyの構文の特殊な一部であるため、すべてのメソッドは、ブロックを渡すことが許可されています。メソッドがブロックを使用するかどうかは、メソッドに依存します。たとえば:

def say_hi(name) 
    puts "Hi, #{name}!" 
end 

say_hi("Mom") do 
    puts "YOU SUCK!" 
end 
#=> Hi, Mom! 

上記の方法は、侮辱を発行する準備ができているブロックが渡されますが、この方法は、ブロックを呼び出すことがないため、唯一の素敵なメッセージが印刷されます。

def say_hi(name) 
    puts "Hi, #{name}!" 
    if block_given? 
    yield(name) 
    end 
end 

say_hi("Mridang") do |str| 
    puts "Your name has #{str.length} letters." 
end 
#=> Hi, Mridang! 
#=> Your name has 7 letters. 

私たちは、ブロックが一緒にか渡されたかどうかを確認するためにblock_given?を使用します。ここでは、我々はメソッドからブロックを呼び出す方法です。この場合、私たちは引数をブロックに戻しました。ブロックに何を渡すかを決めるのはあなたの方法です。たとえば:

def say_hi(name) 
    puts "Hi, #{name}!" 
    yield(name, name.reverse) if block_given? 
end 

say_hi("Mridang"){ |str1, str2| puts "Is your name #{str1} or #{str2}?" } 
#=> Hi, Mridang! 
#=> Is your name Mridang or gnadirM? 

それだけでいくつかのクラスは、わずか1ブロックに作成されたインスタンスを渡すために(あなたがサポートしたいと良いもの、及び1)大会です。

これは、引数としてのブロックの捕捉、ブロックのパラメータの非スプラット処理などについては網羅的ではありませんが、Blocks-Are-Lambdasのイントロとしての役割を果たす予定です。

26

Rubyブロックは、他のコードで使用できるコードを表すProc objectsを作成する方法です。Procオブジェクトは、オプションで引数と戻り値(例えば、{|x,y| x+y})を取る可能性のある、中括弧{}(または複数行ブロックの場合はdo...endフレーズ、中括弧より優先度が低い)間の命令です。 procsのはfirst-class objectsであり、明示的に構成又は方法擬似引数として暗黙的に達成することができる。

  1. 建設Procオブジェクト(またはlambdaキーワードを使用して)として:方法擬似として渡さ

    add1 = Proc.new {|x| x+1} # Returns its argument plus one. 
    add1.call(1) # => 2 
    
  2. 特定の&最後の引数の砂糖演算子を明示的に使用するか、block_given?/yieldのペアを暗黙的に使用するかのいずれかを指定します。

    def twice_do(&proc) # "proc" is the block given to a call of this method. 
        2.times { proc.call() } if proc 
    end 
    twice_do { puts "OK" } # Prints "OK" twice on separate lines. 
    
    def thrice_do() # if a block is given it can be called with "yield". 
        3.times { yield } if block_given? 
    end 
    thrice_do { puts "OK" } # Prints "OK" thrice on separate lines. 
    

第2の形式は、通常Visitor patternsに使用されます。特殊ブロック引数には、callまたはyieldメソッドへの引数としてデータを渡すことができます。誰もが(実際または他のlangs)C#の背景から、この質問に来るために、これは役立つかもしれない

+4

中括弧が優先されます。 'do'の優先順位は低くなります。メソッドの呼び出しに括弧で囲まれていないパラメーターがある場合、ブロックのブレース・フォームは全体の呼び出しではなく、最後のパラメーターにバインドされます。 doフォームは呼び出しにバインドされます。 – Green

+0

なぜdownvote? – maerics

+2

英語、してください! ...... "RubyブロックはProcオブジェクトの構文リテラルです...." - ブロックが何であるか分からない人は、 "Procオブジェクトの構文リテラル"が何を意味するのかわからないでしょう。あたかも読者が5歳であるかのように説明しよう。 – BKSpurgeon

6

Rubyのブロックは、C#でラムダ式と匿名メソッドのようなものです。 C#が代理人(そしてRubyがProcsと呼ぶ)を呼び出すのは、それらが基本的に値として渡せる関数であるということです。 RubyとC#の両方で、クロージャとして動作することもできます。

ルビー:{ |x| x + 1 }

C#:x => x + 1

ルビー:{ |name| puts "Hello there #{name}" }

C番号:name => { Console.WriteLine("Hello there {0}", name); }

C#とRubyの両方は、上記の例を記述するための代替方法を提供します。

ルビー:

do |name| 
    puts "Hello there #{name}" 
end 

C番号:RubyとC#の両方で

delegate(string name) 
{ 
    Console.WriteLine("Hello there {0}", name); 
} 

、複数のステートメントをRubyでは、許可され、上記2番目の構文は、このために必要とされます。

これらの概念は、関数型プログラミングの背後にある考え方の影響を受けた他の多くの言語で利用できます。