2016年1月26日 星期二

Ruby &block lambda proc yield 使用

基本 Lambda 
hello = lambda { puts "Hello" }
hello.call
Result : Hello

log = lamba { |str|  puts "[Log] #{str}"}
log.call ("Test message")
Result : [Log] Test message

Lambda Factory 模式
def times_n (n)
    lambda { |x| x * n }
end
a=times_n(10)
a.call(5)
Result : 50
b=times_n(15)
b.call(10)
Result : 150
[1,2,3].collect(&b)
Result : 
[
    [0] 150,
    [1] 300,
    [2] 450
]

Block 區塊建立與呼叫
sub_block = lambda { | x |  puts x }
sub_block.call ('Hi')
Result : Hi

def my_lambda (&aBlock)
    aBlock
end
b = my_lambda { puts "Hello world !" }
b.call
Result : Hello world !

下列三個相等 
b = Proc.new {|x| puts x }
b = proc {|x| puts x }
b = lambda {|x| puts x}

proc 與 lambda 差異 
add_lambda = lambda {|x , y|  x + y}
add_lambda.call(4)
Result : ArgumentError: wrong number of arguments (1 for 2)
add_lambda.call(4,5,6)
Result : ArgumentError: wrong number of arguments (3 for 2)
add_proc =  proc {|x,y| x + y }
add_proc.call(4)
Result : ArgumentError: wrong number of arguments (1 for 2)
add_proc.call(4,5,6)
Ruby 1.8 Result : ArgumentError: wrong number of arguments (3 for 2)
Ruby 1.9 Result : 9 #多餘的參數會變成 nil 

接收程式碼區塊的方法
def call_twice
    puts "I'm about to call your block"
    yield
    puts "I'm about to call your block again"
    yield
end
call_twice { puts "callback block." }
Result : 
I'm about to call your block
callback block.
I'm about to call your block again
callback block.

def repeat(n)
    if block_given? 
      n.times { yield } 
    else
      raise ArgumentError.new(" I can't repeat a block you don't give me !")
    end
end
repeat(3) { puts "hi"}
Result : 
hi
hi
hi
repeat(5)
Result : ArgumentError:  I can't repeat a block you don't give me !

def call_twice 
    puts "Calling your block "
    ret1 = yield ('first')
    puts "Calling your block again"
    ret2 = yield ('second')
    puts "ret1: #{ret1} , ret2: #{ret2}"
end
call_twice {|x| x == 'first' ? 1 : 2}
Result : 
Calling your block
Calling your block again
ret1: 1 , ret2: 2

將區塊參數連繫到變數
下列三個方式結果都相等
方法一
def repeat (n)
    n.times { yield } if block_given?
end
repeat (2) { puts "Hi" }
方法二
def repeat (n , &block )
    n.times { block.call } if block 
end
repeat (2) { puts "Hi" }
方法三
def repeat (n , &block )
    n.times { yield  } if block 
end
repeat (2) { puts "Hi" }

以上差異 主要是 可以 省略掉 Kernek#block_given? 的使用 .

def biggest (collection , &block ) 
    block ? collection.select(&block).max  : collection.max
end
array = [1 ,2 ,3 ,4 ,5] 
biggest(array) { | i | i  < 3  }
Result : 2
biggest(array) { |i| i  !=5  }
Result : 4
biggest(array)
Result : 5

Ruby 1.9 以上 新寫法

proc = ->
(a, *b, &block)
   p a
   p b   
   block.call if block
}
proc.(1,2,3,4,5) { puts  'Yes' }
Result :
1
[2, 3, 4, 5]
Yes

很厲害的方式:
def my_if(condition, then_clause, else_clause)
  if condition
    then_clause.call
  else
    else_clause.call
  end
end

5.times do |val|
  my_if (val < 3),
  -> { puts "#{val} is small" },
  -> { puts "#{val} is big" }
end

Result:

0 is small
1 is small
2 is small
3 is big
4 is big

【下列文章您可能也有興趣】

沒有留言: