Rubyにおけるblockの本質を理解する


Rubyの特徴は2つあります.
  • Moduleは、マルチ継承の問題を優雅に解決する
  • Blockブロック呼び出し
  • この2つの特性はいずれもRubyオリジナルではないが、明らかにこの2つの特性を適切に発揮し、最近のC#もそれらを改善して支持している.
    しかし、この2つの特性こそ、RubyBeginnerを常に困惑させている.これも私が勉强の过程の中でよく出会う问题で、私はBlockの牛を解く过程を列挙して、自分の过程に対して1つの记录を作ると思っています.
    前言
    Rubyでは、いわゆる「Block」は多種あるが、Blockはコンピュータ科学理論の中で「過程」と呼ばれている.
    仕方がない、ruby設計哲学の一つは、現実世界と似ていて、一つの問題はいくつかの異なる方法で解決することができる.
    では、より少ない符号化のために、より「RubyLike」の符号化のために、始めましょう.
    スタート
    1.それは何ですか.
    (Blockがどうなっているのかまだ分からない場合は、RubyProgrammingの第2版のホの本をかじることをお勧めします)
    まず一つのニーズから始めましょう
    配列がソートをサポートし、使用できる例を見てみましょう.
    では、使い方を見てみましょう.
    
    #     
    ["p","bc","de"].sort do |i,j|
      i.size <=> j.size
    end
    #     
    ["p","bc","de"].sort do |i,j|
      i <=> j
    end
    

    blockを用いるソートというsort法が強いことがわかる.わかりやすいです.
    Cに詳しいなら、Cの関数ポインタに似ているような感じがするかもしれませんが、確かに、私が始めたときもそうでしたが、よく考えてみると、Cの関数ポインタの使用は本当にリスクが高く、複雑でいろいろなタイプの変換があります.
    関数式プログラミングを知っていれば、このblockはいわゆる「高次関数」パラメータのように感じられますが、うーん、確かに、ほとんどの場合、それを
    メソッドのパラメータでよい、このパラメータは式ではなく、完全なコードであることができる.
    2.どのような形式がありますか.
    (リード、block、Proc、lamba、Methodって聞いたでしょ?)
    次に、それらの形式を見てみましょう.
    block:
    blockはrubyが最もよく使う文法の一つであり、最も「RubyLike」でもあるが、その使い方は以上簡単に紹介した.
    私たちは自分の方法を実現するblockを見ました.
    
    def method_with_block
      yield
    end
    method_with_block do puts 'call me' end
    

    so easyは、yieldというキーワードを使用して、いわゆるメソッドパラメータをサポートすることができます.blockパラメータをサポートしたい場合は、以下のこともできます.
    
    def method_with_block_parameter
      n = 'windy'
      yield(n)
    end
    method_with_block do |i| puts 'call me' + i end
    

    Proc:
    blockの同胞としてrubyの発展の過程で現れ、その出現の目的は簡単で、
    ブロックを多重化できる
    ニーズを見てみましょう.
    2つの配列arr 1,arr 2を長さで並べ替えてください.Procを利用してこのように書くことができます.
    size_code = Proc.new do |i,j|
      i.size <=> j.size
    end
    arr1.sort(&size_code)
    arr2.sort(&size_code)
    

    簡単ですね.パラメータに&この記号が付いていることに気づくことができます.&の目的も簡単です.ruby解釈器に教えてください.「ああ、これは一般的なパラメータではなく、「高次関数」です.
    また、細心の注意を払う人は、私がProcを書くのはいつもP大文字で、blockはいつも小文字であることに気づくことができます.これはなぜですか.
    1.Procは実際にRubyに内蔵されているクラスであり、blockは私たちがコードブロックと呼ぶ略記にすぎない.
    2.Procインスタンスはメソッドパラメータとして渡すことができ、blockは匿名のProcに似ている.
    ここで、blockとProcの基本的な違いは明らかになりました.重要な特性を追加します.
    1.blockとProcのジャンプコードはnextを使用します(returnではなく、次に言うlambdaは正反対です)
    2.blockとProcはいずれもメソッドで1回しか受け入れられない.すなわち、メソッドは複数のblockまたはProcを得ることができない(心配しないで、松本行弘も2つのblockを使う必要はないと言った)(また、実際にはhashまたは配列を渡して2つのProcインスタンスを得ることができる)
    3.戻り値、すなわち最後の文の戻り値がある.(私はrubyのすべての式の戻り値をよく知らなかったので、はっきりした学生が討論を歓迎しています)
    lambda:
    Lambdaを使ってrubyをもっと面白くして、外国人の話でfunnyと呼んで、私たちをもっと困惑させて、こんなに多くの形式をして何をしますか?
    まずlambda自体についてお話ししますが、rubyは多くの言語を混ぜ合わせた特徴であり、lambdaは例外ではなくlisp自体から得られた命名であることがわかります.Lambdaはみんな聞いたことがあるようです.ええ、ギリシャのアルファベットです.λまぁ(11番目)
    私が言いたいのは、それはただのキーワードで、ある意味を表すために、ruby言語の神が設計したのです.(特にありませんが…)
    由来は分かりましたが、使用を見てみましょう.
    上記のProcの例に準じて、lambdaの例を書き続けます.
    size_code_lambda = lambda do |i,j|
      i.size <=> j.size
    end
    
    arr1.sort(&size_code_lambda)
    arr2.sort(&size_code_lambda)
    

    うん、違いない?
    ええ、ここは本当に違いません.ああ、それは何をしますか.
    実はsizeを使うことができますcode_lambda.classを見て、Procの対象でもあることに気づきましたか?
    ええと、どうしたんですか.実はあなたが&伝達を使うとき、rubyはすべてProcに変換してあげましたが、このProcオブジェクトは彼Procオブジェクトではなく、違いがあります.
    もう1つの例を見てみましょう
    うっかりするとsortがいくつかのパラメータを伝えることができることが分からなかった.
    こう書きました(もし、kが1つ増えたら):
    size_code_lambda = lambda do |i,j,k|
      i.size <=> j.size
    end
    arr1.sort(&size_code_lambda)
    

    うん、異常を報告した.
    Procのコードで走ってくれないか?大丈夫です.
    では、最初の違いをまとめます.
    1.lambdaはコード伝達パラメータをチェックし始めたが、Procは手伝ってくれなかった.
    Procがチェックしない以上、何を送ってくれますか?すぐに検証できます.
    size_code = Proc.new do |i,j,k|
      puts k,k.class
      i.size <=> j.size
    end
    arr1.sort(&size_code)
    # nil, NilClass
    

    うん、空の値.そうですね.△予想通りでしょう.
    続けてみると、コードブロックから戻って実行を続けたい場合があります.どうすればいいですか.
    returnを試してみましょう.
    一例
    
    def methods(&code)
      code.call
      puts 'methods end'
    end
    
    a_proc = Proc.new { puts 'call proc' ; return ; }
    
    a_lambda = lambda { puts 'call lambda' ; return ; }
    methods(&a_proc) # => unexpected return (LocalJumpError)
    methods(&a_lambda) # => methods end
    
    

    出力はまったく違いますね.では、2つ目の違いがあります.
    2.lambdaではreturnを使用するが、Proc/blockでは使用できない.
    では、何を使って返すか、そのホの本を読んでから知っておくべきで、nextを使えばいいです.
    では、少し印象を深めて、質問をします.Procがreturnを使用するのはなぜLocalJumpErrorに戻ったのでしょうか.
    実は簡単で、Procは当時コードブロックを定義したコンテキスト環境、すなわち閉パッケージを保持しています.ここでLocalJumpErrorを返すのは、私たちが定義したコンテキストが再びreturnできないためです.
    言い換えれば、Procのreturnは実際にはprocの上位環境に直接returnされている.
    ここにはテクニックがあります
    Procで高次ジャンプを実現
    次のようになります.
    
    def go
      a = Proc.new do 
        puts 'proc'
        return
      end
      
      methods(&a)
      
      puts 'end go'
    end
    
    def methods(&a)
      puts 'methods'
      a.call
      puts 'end methods'
    end
    
    go
    # =>methods
    # proc
    

    Procとlambdaの違いを完全に理解しました.
    さて、区別はやっと終わりましたが、どうやって使えばいいのでしょうか.
    1.lambdaはもっと完全な方法のようで、匿名にすぎず、そのパラメータは「神」にチェックされ、returnの時は自分の「方法」から戻る.
    2.Procはただ1つの過程で、頼りなくて、パラメータが間違っている時ただ捨てられてあるいはランダムに1つのnilを拾ってあなたにあげて、returnの時原始の父の環境から戻ります.
    rubyの発展過程によると、lambdaはblock/Procより少し遅く出てきて、lambdaの文法はもちろんprocよりもっと良い(私を驚かせない角度から)が、procは消えていない原因は、互換性である一方で、その「魔法」と少し関係がある.
    だから、使うならblockが優先的に使われるべきで、それはもっと簡潔です.
    オブジェクト伝達が必要な場合は、lambdaをもっと使うことをお勧めします.驚くことはありません.パラメータをチェックすることもできますが、喜んでいませんか.
    Procの高次ジャンプの使い方に出会ったら、分かるといいですね.
    ここを見ると、基本的にこのまとめの栄養は何もありません.あなたも心に理解しているような気がします.しかし、私はやはり実際の状況を明らかにしたいと思っています.
    LambdaはProcの一例にすぎません...(rubyの勉強の深さが高すぎる原因はここにあるので、興味のある人は研究したり検討したりしてもいいです)
    最後に、lambdaがこのように方法(Method)に似ている以上、簡単にMethodを言います.
    Methodもrubyのクラスで、その名前は私たちにすべてを教えてくれました.例を見てください.
    
    def a
      puts 'a'
    end
    
    puts method(:a).class
    
    method(:a).call
    # => Method
    # a
    

    Methodクラスはlambdaによく似ています名前以外は...
    さあ、私は料理を休んでもいいです.あなたたちも今まで...