def touch_down
yield [3, 7] # 傳遞陣列給區塊
puts "touchdown!"
end
# 區塊參數用括號接收陣列元素
touch_down do |(first_down, second_down)|
puts "#{first_down} yards on the run"
puts "#{second_down} yards passed"
end
# 輸出:
# 3 yards on the run
# 7 yards passed
# touchdown!
args = [1, 2, 3]
first, *rest = args
first # => 1
rest # => [2, 3]
# 巢狀解構
(a, b), c = [[1,2], 3]
a # => 1
b # => 2
c # => 3
# 忽略不需要的值
_, second, *tail = [1,2,3,4]
second # => 2
tail # => [3,4]
items = { apples: 2, oranges: 3 }
items.fetch(:apples) # => 2
items.fetch(:bananas) # => KeyError (拋出異常)
items.fetch(:bananas, 0) # => 0 (預設值)
items.fetch(:bananas) { |k| "No #{k}!" } # => "No bananas!" (區塊形式)
# vs []
items[:bananas] # => nil (靜默失敗)
items.fetch(:bananas) # => KeyError (明確失敗)
# 實務:必要設定檢查
config = { host: 'localhost' }
port = config.fetch(:port) { raise "Missing required config: port" }
# 區塊形式:鍵不存在時自動執行區塊並儲存結果
smash = Hash.new { |hash, key| hash[key] = "a #{key} just got SMASHED!" }
smash[:plum] = "cannot smash."
smash[:plum] # => "cannot smash." (已存在,不執行區塊)
smash[:watermelon] # => "a watermelon just got SMASHED!" (執行區塊並儲存)
smash[:watermelon] # => "a watermelon just got SMASHED!" (直接回傳快取)
# 費波納契數列快取(經典範例)
fib = Hash.new { |h, n| h[n] = n < 2 ? n : h[n-1] + h[n-2] }
fib[10] # => 55
fib[20] # => 6765 (極快,動態規劃)
cars = %w[beetle volt camry]
# 依長度排序
cars.sort_by { |car| car.size } # => ["volt", "camry", "beetle"]
# 多重排序鍵:先長度,再字母序
cars.sort_by { |car| [car.size, car] }
# 結合 Symbol#to_proc (Ruby 1.9+)
cars.sort_by(&:size)
cars.sort_by(&:length)
# 降序
cars.sort_by { |car| -car.size }
cars.sort_by(&:size).reverse
# 需 require 'active_support/all' 或在 Rails 專案中
"brain".present? # => true
"".present? # => false
" ".present? # => false (空白也視為 blank)
nil.present? # => false
# 相反
"brain".blank? # => false
"".blank? # => true
# 物件通用
[].blank? # => true
{}.blank? # => true
0.blank? # => false (數字 0 不為 blank)
false.blank? # => true
| 方法 | 適用物件 | 空值判斷 | 備註 |
|---|---|---|---|
| nil? | 所有物件 | 只有 nil 為 true | Ruby 核心 |
| empty? | String, Array, Hash | 長度/大小為 0 | Ruby 核心 |
| blank? | 所有物件 (ActiveSupport) | nil, false, 空字串, 空白字串, 空集合 | Rails 常用 |
| present? | 所有物件 (ActiveSupport) | !blank? | Rails 常用 |
| exists? | ActiveRecord::Relation | 資料表是否有紀錄 | 不載入物件,效能佳 |
User.create(name: "Alice").tap do |user|
puts "Created user: #{user.id}"
user.update!(last_login: Time.current)
end
# 回傳 user 物件,可繼續鏈式
# Ruby 2.5+ yield_self, 2.6+ then
"hello".then { |s| s.upcase }.then { |s| s + "!" } # => "HELLO!"
# 實務:條件轉換
value = get_value
result = value.then { |v| v * 2 if v > 10 }
data = { user: { profile: { settings: { theme: 'dark' } } } }
data.dig(:user, :profile, :settings, :theme) # => "dark"
data.dig(:user, :profile, :missing, :key) # => nil (不拋出錯誤)
# 陣列也支援
matrix = [[1,2], [3,4]]
matrix.dig(1, 0) # => 3
[[:a, 1], [:b, 2]].to_h # => {a: 1, b: 2}
{a: 1, b: 2}.to_h # => {a: 1, b: 2} (Hash 回傳自己)
# 結合 map
%i[a b c].map { |k| [k, k.to_s.upcase] }.to_h # => {:a=>"A", :b=>"B", :c=>"C"}
{a: 1, b: 2, c: 3}.values_at(:a, :c) # => [1, 3]
%w[a b c d e].values_at(0, 2, 4) # => ["a", "c", "e"]
{a: 1, b: 2}.fetch_values(:a, :b) # => [1, 2]
{a: 1}.fetch_values(:a, :c) # => KeyError
%w[apple banana].map(&:upcase) # => ["APPLE", "BANANA"]
[1,2,3].select(&:odd?) # => [1, 3]
users.map(&:name) # 呼叫每個物件的 name 方法
Hash.new { |h,k| ... } 避免重複計算(Memoization)sort_by 比 sort { |a,b| ... } 快(Schwartzian transform)&:method 比 { |x| x.method } 略快且簡潔fetch 比 [] + || 更明確語意這些技巧展現了 Ruby 表達力的核心:區塊語法、解構賦值、安全存取、函數式鏈式操作。掌握 Hash#fetch、預設值 Hash、sort_by、dig、tap/then、&:symbol 等慣用寫法,能寫出更安全、簡潔、高效的 Ruby 程式碼。ActiveSupport 的 blank?/present? 是 Rails 專案標準用法,純 Ruby 專案可自行實作或引入 active_support/core_ext。