Ruby: Code Block
6111 ワード
コードブロックは何ですか?
コードブロックは、
匿名および非匿名コードブロック
デフォルトblockは匿名コードブロックであり、procは非匿名コードブロックである.Procを使用する利点は、繰り返し使用するために変数に保存できることです.blockはyieldキーワードで呼び出され、procはcallメソッドで呼び出されます.blockはメソッド呼び出し後(単一)、procはパラメータとしてメソッドに複数回入力することができる(複数回).
匿名と非匿名の相互転化
blockとprocは、
lambda vs proc
同じ点
両方とも
異なる点
Lambdaはprocよりも厳しく、匿名の方法のようだ.1.戻り値
Tips:
クローズドパッケージとは
閉包は関数式プログラミングにおける重要な特性である.私の理解は、彼が役割ドメインを貫通し、コードブロックコンテキストのローカル変数にアクセスできることです.
Wikipedia: ‘Closure is a function or a reference to a function together with a referencing environment. Unlike a plain function, closures allow a function to access non-local variables even when invoked outside of its immediate lexical scope.’
コードブロックのその他の実用的なテクニック 匿名コードブロック構文糖:
Play with Code Block非匿名コードブロックをパラメータとしてメソッドに入力し、匿名コードブロックに変換して使用する. は、匿名コードブロックを非匿名コードブロックに転送し、依然として匿名コードブロックとして使用する. は、方法をprocオブジェクトに変換し、匿名コードブロックに変換して方法によって使用する. 方法は、コードブロックが他の方法で使用されるように変換される. 計算機ウィジェット
コードブロックは、
{...}
またはdo..end
によって囲まれたコードである.コードブロックは通常、匿名メソッドに似たカスタム演算を実現するために使用されます.コードブロックは、指定された変数(匿名でない)にProc
オブジェクトとして付与されてもよい.以上の特性のため、コードブロックは、閉パケットなどの関数式プログラミングの特性を提供する.匿名および非匿名コードブロック
デフォルトblockは匿名コードブロックであり、procは非匿名コードブロックである.Procを使用する利点は、繰り返し使用するために変数に保存できることです.blockはyieldキーワードで呼び出され、procはcallメソッドで呼び出されます.blockはメソッド呼び出し後(単一)、procはパラメータとしてメソッドに複数回入力することができる(複数回).
# implicit code block
def calculation(a, b)
yield(a, b)
end
calculation(5, 6) { |a, b| a + b } # addition block #=> 11
calculation(5, 6) { |a, b| a - b } # subtraction block #=> -1
# explicit code block (lambda)
def calculation(a, b, operation)
operation.call(a, b)
end
addition_block = lambda { |a, b| a + b } # addition block
subtraction_block = lambda { |a, b| a - b } # subtraction block
calculation(5, 6, addition_block) # addition #=> 11
calculation(5, 6, subtraction_block) # subtraction #=> -1
匿名と非匿名の相互転化
blockとprocは、
&
シンボルによって互いに変換することができる:先頭バンド&
シンボルの全体(&foo
)は、&
シンボルを削除したfoo
変数およびそれに対応するprocオブジェクトを参照することによってブロックと見なすことができる.# implicit -> explicit
def calculation1(a, b, &block)
block.class #=> Proc
block.call(a, b)
end
calculation1(1, 2) { |a, b| a + b } # => 3
addition_lambda = -> (a, b) { a + b }
calculation1(1, 2, &addition_lambda) # => 3
# explicit -> implicit
def calculation2(a, b)
yield(a, b) if block_given?
end
calculation2(5, 5) { |a, b| a + b } # => 10
addition = -> (a, b) { a + b }
calculation2(5, 5, &addition) # => 10
lambda vs proc
同じ点
両方とも
Proc
類のオブジェクトproc { 'foo' }.class # => Proc
lambda { 'bar' }.class # => Proc
lambdaには文法糖があり、-> { 'bar' }
procと略記してもProc.new { 'foo' }
によりオブジェクトをインスタンス化してもよい.異なる点
Lambdaはprocよりも厳しく、匿名の方法のようだ.1.戻り値
return
、lambdaは現在のコードブロックから戻り、procは現在のコードブロックが存在する役割ドメインから戻る.2.コードブロックパラメータ検査、lambdaパラメータ検査はもっと厳格で、少なくなったら間違いを報告しますが、procはしません.Proc#lambda?
を呼び出すことで、彼らを区別することができます.Tips:
block/proc/lambda
は、lambdaにおけるnext
と同様に、return
のキーワードを使用してコードブロックを終了することができる.奇妙な戻り文法のため、procではreturn
の使用をできるだけ避けます.実際にそれをマスターしていない限り、本当にこの特性を使用する必要があります.def a_method
puts lambda { return "we just returned from the block" }.call
puts "we just returned from the calling method"
end
a_method
#---output---
# we just returned from the block
# we just returned from the calling method
def a_method
puts proc { return "we just returned from the block" }.call
puts "we just returned from the calling method"
end
result = a_method
puts result
#---output---
# we just returned from the block
クローズドパッケージとは
閉包は関数式プログラミングにおける重要な特性である.私の理解は、彼が役割ドメインを貫通し、コードブロックコンテキストのローカル変数にアクセスできることです.
Wikipedia: ‘Closure is a function or a reference to a function together with a referencing environment. Unlike a plain function, closures allow a function to access non-local variables even when invoked outside of its immediate lexical scope.’
コードブロックのその他の実用的なテクニック
Kernel#block_given?
:この方法は、呼び出し時に匿名コードブロックが受信されたか否かを判断するために使用される(ここでは、匿名コードブロックが送信されたか否かを判断するためにのみ使用され、非匿名コードブロックが送信されなかった場合、:block_given
はfalse
に戻る).最適な適用シーン:使用の目的は、通常、yield
を使用する前に匿名のコードブロックが操作できるかどうかを判断することです.匿名コードブロックが追加されず、yield
キーワードが使用されている場合、解釈器はLocalJumpError
の異常エラーを放出し、エラープロンプトno block is given
を伴う.だから毎回yield
を使う前に:block_given
で判断することを確保して、これで大丈夫です:D (1..3).map(&:to_s) #=> ["1", "2", "3"]
&
は、後続のsymbol :to_s
をトリガして、自身のSymbol#to_proc
メソッドを呼び出し、&
を介してprocを匿名のblockに変換してmapメソッドに渡す.Play with Code Block
def filter(array, block)
array.select(&block)
end
arr = [1, 2, 3 ,4 ,5]
choose = -> (n) { n < 3}
filter arr, choose # => [1, 2]
# explain: 'select' should receive implicit code block,
# the second parameter of the 'filter; method is lambda,
# so use '&block' to convert lambda to implicit block.
filter_block = lambda do |array, &block|
array.select(&block)
end
filter_block.call([1, 2, 3, 4]) { |number| number.even? } #=> [2, 4]
filter_block.call([1, 2.0, 3, 4.0]) { |number| number.integer? } #=> [1, 3]
def say; yield; end
def hi; "hi"; end
def hello; "hello"; end
say &method(:hi).to_proc # => "hi"
say &method(:hello).to_proc # => "hello"
def plus a, b
a + b
end
def plusplus a, b, c, d, &plus
block_given? ? yield(a+b, c+d) : 0
end
plusplus 1, 2, 3, 4, &method(:plus).to_proc # => 10
# complex example
def calculation(*operations, calculator_lambda)
operations.each do |operation|
num1 = operation[0]
num2 = operation[1]
operator = operation[2]
puts calculator_lambda.call(num1, num2, operator)
end
end
#
calculator_lambda = -> (a, b, op) do
next a + b if op == '+'
next a - b if op == '-'
next a * b if op == '*'
next a / b if op == '/'
raise 'invalid operator'
end
#
operation1 = [1, 2, '+'] # 1 + 2 = 3
operation2 = [6, 3, '/'] # 6 / 3 = 2
calculation(operation1, operation2, calculator_lambda)
#
#---output---
# 3
# 2