2012-01-06 12 views
6

私の背景はPHPとC#ですが、私は本当にRoRを学びたいと思います。その目的のために、私は公式の文書を読み始めました。いくつかのコード例についていくつか質問があります。 単純なRubyの質問 - イテレータ、ブロック、シンボル

最初

はイテレータである:私は yieldが意味することを理解

class Array 
    def inject(n) 
    each { |value| n = yield(n, value) } 
    n 
    end 

    def sum 
    inject(0) { |n, value| n + value } 
    end 

    def product 
    inject(1) { |n, value| n * value } 
    end 
end 

「ここに関連したブロックを実行します。」私を投げているのはeach|value| n =です。

public int sum(int n, int value) 
{ 
    return Inject((n, value) => n + value); 
} 

しかし、最初の例では、私に混乱している:彼らはC#スタイルのラムダを模倣するように見えるように、他のブロックは私に多くの意味をなします。

もう1つは記号です。いつ私はそれらを使いたいですか?そして、なぜ私が何か行うことはできません。injectの定義について

class Example 
    attr_reader @member 

    # more code 
end 

答えて

3

は、nは累積値を表し、これは、すべての反復の結果がn変数に蓄積されていることを意味します。これは、あなたの例のように、配列内の要素の合計または積である可能性があります。

yieldはブロックの結果を返します。これはnに格納され、次の繰り返しで使用されます。これが結果を「累積的」にするものです。

a = [ 1, 2, 3 ] 
a.sum # inject(0) { |n, v| n + v } 
# n == 0; n = 0 + 1 
# n == 1; n = 1 + 2 
# n == 3; n = 3 + 3 
=> 6 

合計を計算するには、a.reduce :+と書くこともできます。これは任意のバイナリ操作で機能します。あなたのメソッドがsymbolという名前の場合、a.reduce :symbolと書くのは、a.reduce { |n, v| n.symbol v }と同じです。

attr実際には会社の方法です。フードの下では、彼らは動的にメソッドを定義します。これは、渡されたシンボルを使用して、インスタンス変数の名前とメソッドを処理します。 :member@memberインスタンス変数になり、membermember =メソッドになります。

attr_reader @memberを書くことができない理由は、@member自体がオブジェクトではなく、シンボルに変換できないためです。実際にはrubyに、selfオブジェクトのインスタンス変数@memberの値をフェッチするように指示します。これはクラススコープでクラス自体です。

class Example 
    @member = :member 
    attr_accessor @member 
end 

e = Example.new 
e.member = :value 
e.member 
=> :value 

を解除インスタンス変数にアクセスするnilをもたらし、そしてattr方法ファミリはシンボルのみを受け付けているので、あなたが得ることに注意してください:TypeError: nil is not a symbol説明するために

Symbolの使用に関しては、の種類のを文字列のように使用できます。等号は常に文字列とは異なり、同じオブジェクトを参照するため、優れたハッシュキーを作成します。メソッドに渡すことができる

:a.object_id == :a.object_id 
=> true 
'a'.object_id == 'a'.object_id 
=> false 
彼らはまた、一般的にメソッド名を参照するために使用している

、およびcan actually be converted to Procs、。これは、array.map &:to_sのようなものを書くことができます。

シンボルの解釈の詳細については、this articleを参照してください。

1

を、あなたは基本的に連鎖したブロックを設定しています。具体的には、{|value| n = yield(n, value)}の変数nは、本質的にinjectに渡されたブロックのアキュムレータです。たとえば、productの定義の場合、inject(1) {|value| n * value}は、配列がmy_array = [1, 2, 3, 4]であるとします。 my_array.productを呼び出すと、injectをn = 1で呼び出すことから始めます。eachは、injectで定義されたブロックになります。injectに渡されたブロックは、n(1)と配列の最初の値よく、この場合)。このブロック{|n, value| n * value}は1 == 1 * 1を返します。これはinjectのn変数に設定されています。次に、それぞれから2が得られ、injectブロックで定義されたブロックはyield(1, 2)となり、2を返してnに代入します。次の3はeachから得られ、ブロックは値(2,3)を返し、次の値としてnに格納される6を返します。本質的には、特殊化ルーチン(sumおよびproduct)で実行される計算の全体的な値に依存しないトラッキングは、汎化を可能にします。それがなければ、例えば、

def sum 
    n = 0 
    each {|val| n += val} 
end 

def product 
    n = 1 
    each {|val| n *= val} 
end 

これは大変反復的です。

attr_readerとそのファミリは、それ自体がdefine_methodを使用して、メタプログラミングと呼ばれるプロセスで適切なアクセッサルーチンを定義するメソッドです。それらは言語文ではなく、単純な古いメソッドです。これらの関数は、作成しているアクセサの名前を示すシンボル(またはおそらく文字列)を渡すことを想定しています。理論的には@memberのようなインスタンス変数を使用できますが、@memberポイントが渡されてdefine_methodで使用される値になります。これらの実装方法の例については、this pageにattr_ *メソッドのいくつかの例が示されています。

1
def inject(accumulator) 
    each { |value| accumulator = yield(accumulator, value) } 
    accumulator 
end 

これは単にブロックのを注入するaccumulatorの電流値と配列項目を得、その後、再びアキュムレータに結果を記憶しています。

class Example 
    attr_reader @member 
end 

attr_readerは、その引数は、セットアップしたいアクセサの名前であるだけの方法です。だから、不自然な方法であなたが呼び出されるgetterメソッドを作成するために

class Example 
    @ivar_name = 'foo' 
    attr_reader @ivar_name 
end 

を行うことができfooinject or reduce方法で

1

最初の例との混乱は、読者|value| nを1つの式として読んだことが原因である可能性がありますが、そうではありません。

この再フォーマットされたバージョンでは、あなたに明確であるかもしれない:

def inject(n) 
    each do |value| 
    n = yield(n, value) 
    end 
    return n 
end 

value配列の要素であり、それはinjectに渡されるものは何でもブロックにn個をもたらしている、nに設定され、その結果。それが明確でない場合は、eachメソッドを読んでください。このメソッドはブロックをとり、配列内の各アイテムをブロックします。それでは蓄積がどのように働くのかがはっきりしているはずです。

attr_readerは、アクセサーメソッドを生成する方法であると考えると奇妙ではありません。それ自体はアクセサではありません。変数の値である@memberの名前だけを扱う必要はありません。 :memberは、変数の名前である 'member'という文字列の内部バージョンです。

シンボルは軽量の文字列と考えることができます。すべてのラベルが同じオブジェクト(:foo.object_id == :foo.object_id)であるのに対し、という新しいボーナスが追加されます。これはそれぞれの 'foo'が新しいオブジェクトだからです。 irbでそれを試すことができます。ラベルやプリミティブな文字列と考えることができます。彼らは驚くほど便利で、たくさん出てきます。メタプログラミングのため、またはハッシュのキーとして。 object.send :fooを呼び出すと、それはおそらくいくつかのより多くのルビーを学ぶために'pickaxe' bookからいくつかの初期の章を読んで価値がobject.foo

を呼び出すのと同じである、他の場所で指摘したように、それはあなたが理解し、余分なものレールに感謝します追加します。

0

まずシンボルを使用する場所とそうでない場所を理解する必要があります。 シンボルは特に何かを表すために使用されます。例::名前、:年齢など。ここでは、これを使用して操作を実行するつもりはありません。 文字列は、データ処理にのみ使用されます。例: 'a = name'。ここでは、この変数「a」をルビの他の文字列演算に使用します。 さらに、symbolは文字列よりもメモリ効率が高く、不変です。だからこそRuby開発者は文字列よりもシンボルを好む。

injectメソッドを使用して合計を(1..5).to_a.inject(:+)と計算することもできます