許多從 Java、C# 轉向 Ruby 的開發者,最容易踩的坑就是 private 關鍵字的語義差異。本文延續上一篇主題,進一步闡述 Ruby 中 private 方法的「隱式接收者」規則、與 protected 的實際區別,並提供除錯技巧與設計建議。
Ruby 官方文件定義:
Private methods cannot be called with an explicit receiver. The receiver is always
self.
這意味著:
method_name → 合法(隱式 self)。self.method_name → 非法(顯式指定 self)。private 方法 → 合法(隱式 self 指向子類別實例)。other.private_method → 非法(顯式指定 other)。class Parent
protected
def secret
"parent secret"
end
end
class Child < Parent
def call_sibling(other_child)
other_child.secret # 合法:protected 允許同類別/子類別實例互呼
end
end
c1 = Child.new
c2 = Child.new
c1.call_sibling(c2) # => "parent secret"
若將 secret 改為 private,上述 other_child.secret 會拋出 NoMethodError。
事實上,send(:method_name)、instance_eval { method_name } 皆可繞過限制呼叫 private 方法(不推薦用於生產碼,僅供測試/除錯)。
self. 呼叫module M
private
def m; puts "m" end
end
class C
include M
def call_m
# self.m # 錯誤
m # 正確
end
end
Test.private_instance_methods(false).include?(:test_print) # => true
Test.protected_instance_methods(false) # => []
| 場景 | 建議可見性 | 理由 |
|---|---|---|
| 內部演算法、工具方法,不希望外部直接呼叫 | private | 隱藏實作細節,子類別仍可複用 |
| 同類別/子類別實例之間需互相呼叫(如比較、排序、複製) | protected | 允許顯式接收者,但限於同層級 |
| 對外公開的 API、介面 | public | 無限制 |
Ruby 的存取控制設計哲學是「信任開發者,靠慣例而非強制」。private 只是阻擋「顯式派發」,並不切斷繼承關係。掌握「隱式 self」這一核心概念,即可輕鬆駕馭 Ruby 的封裝機制,寫出既安全又靈活的程式碼。