2012-03-15 7 views
6

私は同じ結果をもたらす2つの例があります。ブロックでブロックが関数(ルビー)よりも便利なときは?

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    end 
end 

def self.with_params(object_id, &block) 
    find_object_by_id 
    calculate_params_hash 
    block.call(params_hash) 
end 

と方法:

def self.do_something(object_id) 
    some_stuff(self.get_params(object_id)) 
end 

def self.get_params(object_id) 
    find_object_by_id 
    calculate_params_hash 
    params_hash 
end 

第2の解決策は、より簡単なようだが、私は、私たちのアプリケーションコードの最初の1のいくつかの使用法を発見しました。私の質問は、どのような状況で最初のものがお勧めですか?それぞれの賛否両論は何ですか?

+0

私の例では、Procオブジェクトを使用する理由がないと思います。 Procオブジェクトの全体のポイントは、それらをレキシカル環境で永続化し、引数として他の関数に渡すことです。 –

+0

はタグとして "proc"を追加しました。 –

+0

'some_stuff(params)'は何を返しますか?何も返されますか? – nkm

答えて

2

を返し、あなたの例のようにブロックと機能の主な違いは、ブロックは、関数呼び出しのコンテキスト内でを実行していることです。

あなたの例のようにしたのであれば:

def self.do_something(object_id) 
    x = "boogy on" 
    self.with_params(object_id) do |params| 
    some_stuff(params) 
    puts x 
    end 
end 

ブロック内のコードは、ブロックの外側で定義された変数xにアクセスすることができます。これはクロージャと呼ばれます。 2番目の例のように関数を呼び出すだけであれば、これを行うことはできません。

ブロックに関するもう1つの興味深いことは、それらが外部関数の制御フローに影響する可能性があることです。したがって、次のようにすることができます。

def self.do_something(object_id) 
    self.with_params(object_id) do |params| 
    if some_stuff(params) 
     return 
    end 
    end 

    # This wont get printed if some_stuff returns true. 
    puts "porkleworkle" 
end 

ブロック内のsome_stuff呼び出しがtrue値を返すと、ブロックが返されます。これは、ブロックから出て、dosomethingメソッドから出ます。 porkleworkleは出力されません。

あなたの例では、どちらにも依存しないので、関数呼び出しを使用するほうがはるかにクリーンです。

しかし、ブロックを使用してこれらの機能を利用できるようにすることは非常に貴重です。

3

通常、人々は別のコードの中でコードを実行したいときにブロックを使用します。例:これらのブロックは、彼らの語彙的文脈に閉鎖されている

DB.with_shard_for_user(user_id) do |db| 
    # perform operations on a user's shard 

end # shard is reverted back to original value 

File.new(filename) do |file| 
    # work with file 
end # file is closed automatically 

User.transaction do 
    # run some operations as a single transaction 
end 

(彼らはブロックが宣言されているところから、変数をキャプチャし、ブロックが呼び出されたときの場所にそれらを持ち越さ)。

ブロックを受け入れる方法の概略的な構造。

def transaction 
    open_transaction # pre- part 

    yield if block_given? # run provided code 

    commit_transaction # post- part 
rescue 
    rollback_transaction # handle problems 
end 

最初の例では、ブロックの使用が不適切(IMHO)になっている可能性があります。明白な理由がなく複雑すぎる。

1

with_params()を呼び出すと、データを送信するだけでなく、実行するためのコードもいくつか用意されています。もし、その後ブロックはすべて同じかwith_params(ある場合

... 
self.with_params(object_id) do |params| 
    even_more_stuff(params) 
end 
... 

)ただ1つの場所から呼び出されます。

... 
self.with_params(object_id) do |params| 
    some_other_stuff() 
    some_stuff(params) 
end 
... 

とどこか別の場所:異なるブロックがwith_params()の呼び出しに送信された場合を参照してください。ブロックを削除することを検討するかもしれません。

要約:メソッド(ブロック)とデータ(hey with_params)をメソッドに渡したい場合はブロックを使用し、このデータ(object_id)を取得し、このコードを実行します)あなたがそれをしている間。

ところで、あなたは、2つの例では異なることをやっている:with_params()ブロックを評価した後

some_stuff(params_hash) 

を返します。 get_params()だけ

params_hash 
1

ブロックはコードに完全に依存しますが、関数には独自のコードがあります。

状況によってコードが状況によって異なる場合は、ブロックを使用してください。 そうでない場合は、関数をビルドしてブロックボックスとして使用します。

関連する問題