Yield 在 Ruby 跟 Rails 中

紅寶鐵軌客
Join to follow...
Follow/Unfollow Writer: 紅寶鐵軌客
By following, you’ll receive notifications when this author publishes new articles.
Don't wait! Sign up to follow this writer.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.
寫程式中、折磨中、享受中 ......
952   0  
·
2020/09/23
·
4 mins read


我是個寫 C 出身的工程師,現在開始學寫 Ruby & Rails,雖然 C 寫的很普普,但是還是有影響, ruby 中總是有些東西,對我來說,很難懂,ruby 的 yield 就是一個例子。

Ruby 的 Yield

Yield 在 Ruby 中是個 keyword,我花了至少一個小時,才總算搞清楚 yield 的來源以及其含義,我個人是這樣,如果不能理解,就是不懂,就算能用,也不過就是隻猴子學樣吧了,自己都難過,所以,特別把它記錄下來,不然很快就又忘了。

在英文中,Yield 這字是:「收成」、「獲得」⋯⋯ ,作為動詞,大家最熟悉的應該就是「讓路」,在美國,就是這個路標:

在台灣也有個相似的:

是的,在 Ruby 中,yield 就是「讓路」,但是要讓給誰能?讓我們來看這個 code:

# 參考來源:https://ithelp.ithome.com.tw/articles/10203982

autumn = ["September", "October", "November"]

def autumn_month (array, start = 1)
  counter = start
  array.each do |item|
    ## yield 來了 ##
    puts "#{yield counter} #{item}"
    counter=counter.next
  end
end

# 列出秋天的月份
autumn_month( autumn, 9 ) {|mth| "#{mth}. " }

9.  September
10.  October
11.  November

這個例子很有趣的清楚說明了 yield,我們先來看看這碼的流程:

  1. 先宣告一個 autumn array
  2. 再宣告 autumn_month() 的方法
  3. 執行 autumn_month() 方法

就這麼簡單,但是,請注意,在 #3 中,執行 autumn_month 方法的時候,後面跟了一個 ruby block {|mth| "#{mth}. " },這個是重點,這個 ruby block 也就是當碰到 yield 讓路時,會先執行(先行)的 ruby block! 還是不懂,沒關係,我也搞好久才懂,模擬一下就懂了:

  1. 執行 autumn_month() 方法,帶入參數 ( autumn, 9 ),後面跟著 {|mth| "#{mth}. " } 這個 ruby block。
  2. autumn_month() 方法中,counter 被設定為 9,然後準備印出(puts) autumn array 的內容
  3. 印出(puts)時,裡面有個 yield,因為碰到「讓路」,所以這段碼要先暫停,讓路給 {|mth| "#{mth}. " } ,這個已經在等的 ruby block。
  4. ruby 的 yield 不只會讓路,還可以傳值,所以:yield counter => yield(counter) => 傳出 counter 的值到等待中的 ruby block => 所以 mth = counter => ruby block 的內容變成{|counter| "#{counter}. " } => "#{counter}. "
  5. 禮讓先行完成後,就輪回到 puts "#{yield counter} #{item}",這時 yield counter 已經變成 "#{counter}. "了,所以 puts "#{yield counter} #{item}" => puts "#{counter}. #{item}",就這樣,魔術完成了!

從上面這個很有趣的例子中,我們可以看到,yield 是個很有趣的指令,它可以在呼叫方法時,將一段「程式碼」置入,所以,yield 一定要有相對應的  ruby block,如果我們在寫 yield 時,不確定有沒有相對應的  ruby block,就可以用 yield(value) if block_given?

在 ruby 中,類似 block 的還有 lambdas 跟 proc,三者之間有很大的相似,但是細節卻大不同,這也是 ruby 對我來說,另一個很難搞懂的地方,有時,從一個老 C programmer 來看,還會覺得超怪,說真的,我是有些排斥用 lambdas 跟 proc,心想,就不用它們,只用block 就可以打天下了,好像是有可能呢,不過,排斥總不是好事,大該寫了一些:

  • lambdas 跟 proc:都是 block 的 wrapper,讓我們把一個 block 變成一個變數:a object - an instance of the Proc class.
  • lambdas 跟 proc:都是 Proc class,但是內部的 return 大不同⋯⋯
  • lambda 會檢查 arguments 數目,proc 不會,
  • 我覺得下面這篇文章介紹 lambdas 跟 proc 很棒,清楚地說出重點:

Procs and Lambdas — Today I was refreshing my knowledge and learning something new about proc and lambda in Ruby and want...
DEV Community

Rails 的 Yield

在 Rails 的 layout 中,也有 yield,主要是在 app/views/layouts/application.html.erb 中,在這個 layout 中,就有一個<%= yield %>

那,Ruby 跟 Rails 中的這兩個  yield 是相同的嗎?是的,Rails 就是 Ruby 寫的,而 yield 是 Ruby 的 keyword,所以當然就是同一個, 只是在 Rails 中,是由 Controller 來在處理 View 時,它會先取用 Layout(預設是 app/views/layouts/application.html.erb),當碰到<%= yield %> 時、會將 Controller 相對應的 view 塞到其中,例如:index.html.erb,就這樣。

希望有幫助。


WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.


Article info

This article is part of:
分類於:
標籤:
合計:1012字


Share this article:
About the Author

很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯




Join the discussion now!
Don't wait! Sign up to join the discussion.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.