可以在繼承鏈上呼叫 ” 最接近的上層 “ 的同名方法,而若是找不到符合的方法則會產生 NoMethodError exception
。聽起來很單純,但其實這關係到我們在 Day 16 談過的「方法的呼叫」,同名的方法很可能不止一個,尤其當你學會 Ruby,最終總會來到實作階段,在 Rails 裡大量用到的繼承、方法調用的技巧。
在這裡先記得兩個準則:「後進先出」,以及「有彎先轉」。
module Mod_A
def method
puts "from Mod_A"
end
end
module Mod_B
def method
puts "from Mod_B"
end
end
class SuperKlass
def method
puts "from SuperKlass"
end
end
class Klass < SuperKlass
include Mod_A
include Mod_B
def method
puts "from Klass"
super
end
end
obj = Klass.new
obj.method
# 印出以下內容
# from Klass
# from Mod_B
接著要回到昨天的話題,昨天在最後介紹了 Catch-All Argument ,單用一個 *
將所有的引數抓取,但抓取後不能自己操作,由於不能自己操作,所以我們會用 super
這個關鍵字讓繼承練的上層來代勞。
在之前的介紹中大家應該都知道了 Ruby 能省則省的小括號,但也有某些狀況省略不會得到你預期的結果,對於 super
這個方法就是個典型的例子, super
與 super()
可是兩件事情:
class Animal
def food(breakfast, lunch, dinner)
puts "#{breakfast}是一個好的開始 \n#{lunch}用來補充能量 #{dinner}可以讓我做個好夢 "
end
end
class Dog < Animal
def food(*)
puts "汪汪汪"
super
end
end
husky = Dog.new
husky.food("牛排", "罐罐", "餅乾")
# 印出以下內容
# 汪汪汪
# 牛排是一個好的開始
# 罐罐用來補充能量 餅乾可以讓我做個好夢
super
會將子層同名方法後的引數往上層的方法傳遞,如上例將 food 方法後的引數往上傳,而這邊使用 Catch-All Argument ,若是上層方法參數數量有改變,下層也不需更動。
super()
則是可以自由選擇傳哪些引數上去,所以當裡面沒有填參數時,當然就不會傳遞任何引數。
class Animal
def food(breakfast, lunch, dinner)
puts "#{breakfast}是一個好的開始 \n#{lunch}用來補充能量 #{dinner}可以讓我做個好夢 "
end
end
class Dog < Animal
def food(breakfast, lunch, dinner, guilt)
puts "汪汪汪"
super(breakfast, lunch, dinner)
puts "我還可以吃#{guilt}!!!"
end
end
husky = Dog.new
husky.food("牛排", "罐罐", "餅乾", "更多餅乾")
# 印出
# 汪汪汪
# 牛排是一個好的開始
# 罐罐用來補充能量 餅乾可以讓我做個好夢
# 我還可以吃更多餅乾!!!
這邊再補充一下,在類別裡我們如果要初始化,只能用 initialize
這個方法,那在同名方法中,想必它的發生率會最高,想像一下如果你今天繼承後想要擁有自己初始化的結果,同時也想要父類別的結果,當然你可以說我全部覆寫一次,覆寫最大,但你要記得維持乾燥這件事,「Don't repeat yourself」。
class Parent
def initialize (name)
@name = name
end
end
class Child < Parent
def initialize (age)
@age = age
end
end
這時你可以用 super
來調用。
class Child < Parent
def initialize (name, age)
super(name)
@age = age
end
end
此文同步刊登於CJ-Han的網站