Ruby中yield和block的用法


       在ruby-koans中接觸到yield和block的使用,剛接觸有點疑惑,也有興趣往下挖掘看看yield block的神奇所在。

       1. yield佔位。首先截取ruby-koans中關於yield和block的用法的實例。

  def method_with_block
    result = yield
    result
  end

  def test_methods_can_take_blocks
    yielded_result = method_with_block { 1 + 2 }
    assert_equal 3, yielded_result
  end

  def test_blocks_can_be_defined_with_do_end_too
    yielded_result = method_with_block do 1 + 2 end
    assert_equal 3, yielded_result
  end


       在這段代碼中,我們可以看到在第一個函數通過引入yield定義了method with block 方法, 而在第2個方法中則調用函數 method_with_block, 按照ruby中對方法調用的用法,這裏我們的 { 1 + 2 } 和方法3中的 do 1 + 2 end 都是作爲參數傳遞給method_with_block方法。只不過這裏傳遞的參數不是我們常見的object,這裏傳遞的是一個block代碼塊。

既然是代碼塊,那我們的方法中應該怎麼去執行去使用這段代碼呢。此時yield出現了,他直接告訴代碼塊,快到我這裏來吧,我這有個坑,專門留給你的。於是這個被傳進來的代碼塊毅然的在yield所在的地方紮根。

紮根後代碼就做了以下事情,用僞代碼表示如下:

def method_with_block
result = { 1 + 2 }
result
end

yielded_result = method_with_block

終於method_with_block執行代碼塊後將結果3返回出來最後被賦值給yielded_result. 於是yield的使命完成了。

2. yield賦值

# ------------------------------------------------------------------

def method_with_block_arguments
yield("Jim")
end

def test_blocks_can_take_arguments
method_with_block_arguments do |argument|
assert_equal "Jim", argument
end
end

# ------------------------------------------------------------------

def many_yields
yield(:peanut)
yield(:butter)
yield(:and)
yield(:jelly)
end

def test_methods_can_call_yield_many_times
result = []
many_yields { |item| result << item }
assert_equal [:peanut, :butter, :and, :jelly], result
end

分析第一段代碼,argument 傳入到method_with_block_arguments. 通過yield("Jim"), argument被賦值爲“Jim”,複製後會繼續執行do end 之間的assert代碼。如果說第一種方式yield佔位成爲代碼注入的話,這部分則有點類似於回調。

3. block call 調用
def method_with_explicit_block(&block)
block.call(10)
end

def test_methods_can_take_an_explicit_block_argument
assert_equal 20, method_with_explicit_block { |n| n * 2 }

add_one = lambda { |n| n + 1 }
assert_equal 11, method_with_explicit_block(&add_one)
end

這一段的關鍵代碼在於block.call ,直接爲代碼塊傳入值,穿入後,代碼塊就執行,block應該稱之爲沒有方法名的函數體,直接被當作參數傳遞到函數中。只不過這個無名函數不能通過 函數名:參數 的形式調用,而是通過一個間接的call方法向其中傳入參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章