將依次搜索特殊方法、本類中定義的方法和超類(包括Mix-in進來的模塊。寫成 類名.ancestors。)中定義的方法,并執行所找到的第一個方法。若沒有找到方法時,將按照同樣的順序來搜索method_missing。
module Indexed def [](n) to_a[n] end end class String include Indexed end p String.ancestors # [String, Indexed, Enumerable, Comparable,遺憾的是上述代碼返回的是10,而并非預期的"b\n"。這是因為系統在String類中搜索[],在遇到Indexed中定義的方法之前就已經完成了匹配,所以如此。若直接在Class String中重定義[]的話,就會如您所愿了。
5.2 +和-是操作符嗎?+和-等是方法調用,而并非操作符。因此可進行overload(重定義)。
class MyString < String def +(other) print super(other) end end但以下內容及其組合(!=、!~)則是控制結構,不能進行重定義。
=, .., ..., !, not, &&, and, |, or, ~, ::重定義(或者定義)操作符時,應該使用形如+@或-@這樣的方法名。
=是訪問實例變量的方法,您可以在類定義中使用它來定義方法。另外,+或-等經過適當的定義之后,也可以進行形如+=這樣的自賦值運算。
def attribute=(val) @attribute = val end 5.3 Ruby中有函數嗎?Ruby中看似函數的部分實際上都是些省略被調(self)的方法而已。例如
def writeln(str) print(str, "\n") end writeln("Hello, World!")中看似函數的部分實際上是Object類中定義的方法,它會被發送到隱藏的被調self中。因此可以說Ruby是純粹的面向對象語言。
對內部函數這種方法來說,不管self如何,它們總是返回相同的結果。因此沒有必要計較被調的問題,可以將其看作函數。
5.4 可以在外部使用對象的實例變量嗎?不能直接使用。若想操作實例變量,必須事先在對象中定義操作實例變量的方法(aclearcase/" target="_blank" >ccessor)。例如
class C def name @name end def name=(str) # name 后面不能有空格! @name = str end end c = C.new c.name = '山田太郎' p c.name #=> "山田太郎"另外,您還可以使用Module#attr、attr_reader、 attr_writer、attr_accessor等來完成這種簡單的方法定義。例如,您可以這樣來重寫上面的類定義。
class C attr_accessor :name end若您不愿定義訪問方法,卻想使用實例變量時,可以使用Object#instance_eval。
5.5 private和protected有什么不同?private意味著只能使用函數形式來調用該方法,而不能使用被調形式。所以,您只能在本類或其子類中調用private方法。
protected也是一樣,只能用在本類及其子類中。但是您既可以使用函數形式又可以使用被調形式來調用它。
在封裝方法時,該功能是必不可少。
5.6 能不能將實例變量變成public類型的變量?無法讓變量變成public類型的變量。在Ruby中訪問實例變量時,需要使用訪問方法。例如
class Foo def initialize(str) @name = str end def name return @name end end但是每次都這么寫的話,未免有些繁瑣。因此可以使用attr_reader、attr_writer、 attr_accessor等方法來完成這些簡單的方法定義。
class Foo def initialize(str) @name = str end attr_reader :name # 其效果等同于下面的代碼。 # def name # return @name # end end foo = Foo.new("Tom") print foo.name, "\n" # Tom您還可以使用attr_accessor來同時定義寫入的方法。
class Foo def initialize(str) @name = str end attr_accessor :name # 其效果等同于下面的代碼。 # def name # return @name # end # def name=(str) # @name = str # end end foo = Foo.new("Tom") foo.name = "Jim" print foo.name, "\n" # Jim若只想定義寫入方法的話,可以使用attr_writer。
5.7 怎樣指定方法的可見性?首先 Ruby把那些只能以函數形式(省略被調的形式)來調用的方法叫做private方法。請注意,這里的private定義與C++以及Java中的定義不同。
若將方法設為private類型之后,就不能在其它的對象中調用該方法了。因此,若您只想在本類或其子類中調用某方法時, 就可以把它設為private類型。
您可以這樣把方法設為private類型。
class Foo def test print "hello\n" end private :test end foo = Foo.new foo.test #=> test.rb:9: private method `test' called for #<Foo:0x400f3eec>您可以使用private_class_method將類方法變為private類型。
class Foo def Foo.test print "hello\n" end private_class_method :test end Foo.test #=> test.rb:8: private method `test' called for Foo(Class)同理,您可以使用public、public_class_method將方法設為public類型。
在默認情況下,類中的方法都被定義成public類型(initialize除外),而頂層中的方法會被定義成private類型。
5.8 方法名可以用大寫字母開頭嗎?可以。但要注意:即使方法調用中不帶參數,也不能省略方法名后的空括號。
5.9 為什么使用super時會出現ArgumentError?在方法定義中調用super時,會把所有參數都傳給上層方法,若參數個數不符合其要求,就會引發ArgumentError。因此,若參數個數不合時,應該自己指定參數然后再調用super。
5.10 如何調用上2層的同名方法?super只能調用上1層的同名方法。若想調用2層以上的同名方法時,需要事先對該上層方法進行alias操作。
5.11 重定義內部函數時,如何調用原來的函數?可以在方法定義中使用super。進行重定義之前,使用alias就可以保住原來的定義。也可以把它當作Kernel的特殊方法來進行調用。
5.12 何謂破環性的方法?就是能修改對象內容的方法,常見于字符串、數組或哈希表中。一般是這樣的:存在兩個同名的方法,一個會拷貝原對象并返回副本;一個會直接修改原對象的內容,并返回修改后的對象。通常后者的方法名后面帶有!,它就是破壞性的方法。但是有些不帶!的方法也是具有破環性的,如String#concat等等。
5.13 那些情況下會產生副作用?若在方法中對實參對象使用了破環性的方法的時候,就會產生副作用。
def foo(str) str.sub!(/foo/, "baz") end obj = "foo" foo(obj) print obj #=> "baz"此時,參數對象的內容被修改。另一方面,如果在程序中確有必要的話,也會對某對象發送具有副作用的消息,那就另當別論了。
5.14 能讓方法返回多個值嗎?在Ruby中確實只能指定一個方法返回值,但若使用數組的話,就可以返回多個值了。
return 1, 2, 3上例中,傳給return的列表會被當作數組處理。這與下面的代碼可謂是異曲同工。
return [1, 2, 3]另外,若使用多重賦值的話,則可以達到返回多個值的效果。例如
def foo return 20, 4, 17 end a, b, c = foo print "a:", a, "\n" #=> a:20 print "b:", b, "\n" #=> b:4 print "c:", c, "\n" #=> c:17您也可以這樣處理。
原文轉自:http://www.anti-gravitydesign.com