?
このドキュメントでは、 php中國語ネットマニュアル リリース
例:
class Foo < Super def test : end : end
語法:
class 標(biāo)識符 [`<' superclass ] 表達(dá)式.. end
語法:ruby 1.7 特性
class 標(biāo)識符 [`<' superclass ] 表達(dá)式.. [rescue [error_type,..] [=> evar] [then] 表達(dá)式..].. [else 表達(dá)式..] [ensure 表達(dá)式..] end
用來定義類的內(nèi)容。類名(標(biāo)識符)由大寫字母開頭。ruby 1.7 特性:在version 1.7中,可以添加rescue/ensure部分。
類定義實際上就是把類賦值給由類名指定的常數(shù)(在Ruby中,類也是一個對象,它是Class類的實例)。
若某個類已經(jīng)被定義過,此時又用相同的類名進行類定義的話,就意味著對原有的類的定義進行追加。但是若顯式地標(biāo)出新類的超類與原有類的超類不同時,就表示將使用原有的類名定義一個新的類(這將覆蓋與類同名的常數(shù),因此會出現(xiàn)警告)。
class Foo < Array def foo end end # 追加定義(即使顯式地標(biāo)明超類是Array,其結(jié)果也是一樣) class Foo def bar end end # 定義新的類(因為超類不同) class Foo < String end # => warning: already initialized constant Foo
在類定義表達(dá)式中,self指的是該類本身,這與頂層沒有什么不同,只是默認(rèn)的調(diào)用限制有些許差異??梢栽陬惗x表達(dá)式中寫入任何表達(dá)式,在定義類時這些表達(dá)式將被執(zhí)行。
類定義中可以出現(xiàn)嵌套。下例中,嵌套外側(cè)的Foo類和內(nèi)側(cè)的Bar類之間根本沒有什么繼承關(guān)系之類的功能上的聯(lián)系(除了常數(shù)Bar是Foo中的常數(shù)Foo:Bar之外)。
class Foo class Bar end end
ruby 1.8 特性:如果Foo類已經(jīng)定義過了的話,還可以這么寫。
class Foo end class Foo::Bar end
類的嵌套就是指,把與類有關(guān)的類和模塊放在該類的外側(cè),使它們構(gòu)成一個整體,借以表達(dá)某種包含關(guān)系。
# 把與NET有關(guān)的類置入NET內(nèi)部 # 常使用模塊來作為嵌套的外側(cè)部分 # (Net沒有實例。這主要是為了能夠包含(include)Net) module Net class HTTP end class FTP end end obj = Net::HTTP.new # 或者 include Net obj = HTTP.new # 下列用法在內(nèi)部類中也可使用 # 使用者只要包含(include)了File::Constants # 就可以直接使用RDONLY,而不必寫File::RDONLY等。 class File module Constants RDONLY = 0 WRONLY = 1 end include Constants end File.open("foo", File::RDONLY) # 或者 include File::Constants File.open("foo", RDONLY) # 上面的只是例子。實際上,使用File.open時可以寫得更簡單 # 可以這么寫,F(xiàn)ile.open("foo", "r")
類定義表達(dá)式?jīng)]有返回值。ruby 1.7 特性:類定義表達(dá)式將返回最后被計算的式子的值。若最后的式子不返回值,就返回nil。
例:
class << obj def test : end : end
語法:
class `<<' expr 表達(dá)式.. end
語法:ruby 1.7 特性
class `<<' expr 表達(dá)式.. [rescue [error_type,..] [=> evar] [then] 表達(dá)式..].. [else 表達(dá)式..] [ensure 表達(dá)式..] end
與類定義的語法結(jié)構(gòu)相同,它定義特定對象的功能。在其內(nèi)部定義的方法和常數(shù)只對該特定對象有效。ruby 1.7 特性:在version 1.7中,還可以使用rescue/ensure部分。
特殊類定義表達(dá)式將返回最后被計算的式子的值。若最后的式子不返回值,就返回nil。
例:
module Foo def test : end : end
語法:
module 標(biāo)識符 表達(dá)式.. end
語法:ruby 1.7 特性
module 標(biāo)識符 表達(dá)式.. [rescue [error_type,..] [=> evar] [then] 表達(dá)式..].. [else 表達(dá)式..] [ensure 表達(dá)式..] end
用來定義模塊的內(nèi)容。模塊名(標(biāo)識符)由大寫字母開頭。ruby 1.7 特性:在version 1.7中,還可以使用rescue/ensure。
模塊定義實際上就是把模塊賦值給由模塊名指定的常數(shù)(在Ruby中,模塊也是一個對象,它是
若某個模塊已經(jīng)被定義過,此時又用相同的模塊名來定義模塊的話,就意味著對原有的模塊定義進行追加。
模塊定義表達(dá)式?jīng)]有返回值.ruby 1.7 特性:模塊定義表達(dá)式將返回最后被計算的式子的值.若該式子不返回值,則返回nil.
例:
def fact(n) if n == 1 then 1 else n * fact(n-1) end end
語法:
def 方法名 [`(' [arg ['=' default]] ... [`,' `*' arg] [',' '&' arg]`)'] 表達(dá)式.. [rescue [error_type,..] [=> evar] [then] 表達(dá)式..].. [else 表達(dá)式..] [ensure 表達(dá)式..] end
在定義語句所在的區(qū)域內(nèi)定義一個方法.也就是說,若在類/模塊的定義部分內(nèi)定義一個方法的話,該方法就屬于這個類/模塊.若在頂層定義了一個方法的話,您就可以在任何地方調(diào)用它.這種方法其實就是其他語言中所說的"函數(shù)".
方法名中,除了可以使用通常的標(biāo)識符以外,還可以使用可重載的操作符(例:==,+,-等等.請參考操作符表達(dá)式).
若給形參指定了默認(rèn)表達(dá)式的話,在方法調(diào)用過程中如果實參被省略時,該默認(rèn)表達(dá)式的值就會變成默認(rèn)值(方法調(diào)用時,在方法定義內(nèi)計算默認(rèn)表達(dá)式的值).
若最后一個形參的前面帶"*"的話,所有剩下的實參將被轉(zhuǎn)為數(shù)組后傳遞給該參數(shù).
例:
# 沒有參數(shù)的方法。以下省略 end def foo end # 有參數(shù)的方法 def foo(arg, arg2) # 有默認(rèn)參數(shù)的方法 def foo(arg = nil) # 帶塊 def foo(arg, &block) # 參數(shù)一應(yīng)俱全 def foo(arg, arg2, arg3 = nil, *rest, &block) # 操作符表達(dá)式 def ==(other) def +(other) def *(other)
若最后一個形參前面帶"&"的話,表示傳遞給該參數(shù)的塊是一個過程對象(Proc).這是定義迭代器的一種方法.(定義迭代器的典型方法是調(diào)用yield.還可以使用Proc.new/proc等方法.)當(dāng)沒有給出塊時,塊參數(shù)的值為nil.
在方法定義中,只能以下列順序指定形參.其中任何一項都是可選的.
例: 定義迭代器
# 使用 yield def foo # block_given? 是內(nèi)部函數(shù) # 用來判斷方法有沒有塊 if block_given? yield(1,2) end end # 使用 Proc.new def bar if block_given? Proc.new.call(1,2) # proc.call(1,2)也是一樣(proc是內(nèi)部函數(shù)) end end # 應(yīng)用:定義一個既能接受Proc對象 # 又能接受塊的迭代器 def foo(block = Proc.new) block.call(1,2) end foo(proc {|a,b| p [a,b]}) foo {|a,b| p [a,b]} # 使用塊參數(shù) def baz(&block) if block block.call(1,2) end end
我們再舉幾個特殊的例子.
# 單相+/- def +@ def -@ # 給要素賦值 def foo=(value) # obj.foo = value # [] と []= def [](key) # obj[key] def []=(key, value) # obj[key] = value def []=(key, key2, value) # obj[key, key2] = value # 后引號表示法 def `(arg) # `arg` 或 %x(arg)
因為后引號表示法與方法密切相關(guān),所以可以進行再定義.通常情況下,不應(yīng)該對該方法進行再定義.偶爾OS(SHELL)命令的運作不太正常時,可以使用這種方法.
為了捕捉在方法運行時發(fā)生的異常,可以使用同begin一樣的rescue,else或ensure語句.
方法定義表達(dá)式不會返回值.ruby 1.7 特性:方法定義表達(dá)式返回nil.
除了特殊方法定義以外,方法定義表達(dá)式不能進行嵌套.
ruby 1.7 特性: 在1.7 以后的版本中,就可以進行嵌套了.只有嵌套外側(cè)的方法被執(zhí)行時,嵌套方法才會被定義.除此以外,它和普通的方法定義表達(dá)式?jīng)]有區(qū)別.請參考下例.
class Foo def foo def bar p :bar end end def Foo.method_added(name) puts "method \"#{name}\" was added" end end obj = Foo.new obj.bar rescue nil # => undefined method `bar' for #<Foo:0x4019eda4> obj.foo # => method "foo" was added obj.foo # => warning: method redefined; discarding old bar Foo.new.bar # => :bar (在其他實例中,嵌套方法也已完成定義)
在version 1.6之前的版本中,若想達(dá)到相同的目的就必需使用instance_eval(此時特殊方法已被定義,因此稍有不同).
class Foo def foo instance_eval <<-END def bar p :bar end END end end obj = Foo.new def obj.singleton_method_added(name) puts "singleton method \"#{name}\" was added" end # => singleton method "singleton_method_added" was added obj.bar rescue nil # => undefined method `bar' for #<Foo:0x4019eda4> obj.foo # => singleton method "bar" was added obj.foo # => warning: method redefined; discarding old bar # => singleton method "bar" was added Foo.new.bar # => undefined method `bar' for #<Foo:0x4019eda4>
還可以這么寫.
class Foo def foo instance_eval { def bar p :bar end } end end
調(diào)用方法時,將按照下列順序依此計算各個表達(dá)式.
在方法內(nèi),根據(jù)實際情況來計算這些部分,包括參數(shù)的默認(rèn)表達(dá)式在內(nèi).
方法的返回值就是傳給return的值.若沒有調(diào)用return時,將返回在ensure部分之前最后計算的式子的值.
若最后的式子(例如while等)沒有返回值,則返回nil.
在定義某方法之前,是不能使用該方法的.例如
foo def foo print "foo\n" end
調(diào)用未定義的方法會引發(fā)NameError異常.
例:
def foo.test print "this is foo\n" end
語法:
def 表達(dá)式 `.' 標(biāo)識符 [`(' [參數(shù) [`=' default]] ... [`,' `*' 參數(shù) ]`)'] 表達(dá)式.. [rescue [error_type,..] [=> evar] [then] 表達(dá)式..].. [else 表達(dá)式..] [ensure 表達(dá)式..] end
特殊方法就是專屬于某個對象的方法.特殊方法的定義可以嵌套.
類的特殊方法將被該類的子類所繼承.換言之,類的特殊方法所起到的作用,與其他面向?qū)ο笙到y(tǒng)中的類方法的作用是相同的.
特殊方法定義表達(dá)式不會返回值.ruby 1.7 特性:特殊方法定義表達(dá)式返回nil.
Ruby中的類方法是指類的特殊方法.在Ruby中,類也是對象.因此它就可以像普通對象一樣來定義特殊方法.
因此,若能在類對象中定義方法的話,該方法就會成為類方法.具體的定義方法如下(模塊也一樣).
# 特殊方法方式. class Hoge def Hoge.foo end end # 在類定義的外側(cè)也行 def Hoge.bar end # 若使用下面的方法的話,即使類名改變了,也不必更改方法定義 class Hoge def self.baz 'To infinity and beyond!' end end # 特殊類方式.適合于大批量地定義方法 class << Hoge def bar 'bar' end end # 若把模塊extend到類的話,模塊的實例方法 # 就會變成類方法 module Foo def foo end end class Hoge extend Foo end
請參考Object#extend來了解extend.
調(diào)用方法時,會受到以下三種限制,即public
、private
、protected
.
public
類型,則沒有任何限制.
private
類型,則只能在函數(shù)中調(diào)用.
protected
類型,則只能在該方法所屬對象的方法定義表達(dá)式內(nèi)使用. 例: protected的可用性
class Foo def foo p caller.last end protected :foo end obj = Foo.new # 不可直接調(diào)用 obj.foo rescue nil # => -:11 - private method `foo' called for #<Foo:0x401a1860> (NameError) # 也不能在類定義中調(diào)用 class Foo Foo.new.foo rescue nil # => -:15 - protected method `foo' called for #<Foo:0x4019eea8> # 可以在方法定義表達(dá)式中調(diào)用 def bar self.foo end end Foo.new.bar # => ["-:21"] # 還可以在特殊方法定義表達(dá)式中調(diào)用 def obj.bar self.foo rescue nil end obj.bar # => ["-:27"]
默認(rèn)情況下,若def表達(dá)式位于類定義以外(頂層),則該方法屬于private類型.若在類定義之中,則該方法屬于public類型.可以使用Module#public,Module#private或Module#protected來改變它們的類型.但是,initialize方法和initialize_copy(ruby 1.8 特性)方法總是private類型,這與它們的位置無關(guān).
例:
def foo # 默認(rèn)為 private end class C def bar # 默認(rèn)為 public end def ok # 默認(rèn)為 public end private :ok # 變?yōu)?privat def initialize # initialize 是 private end end
使用private
和 protected
的目的是相同的(將對象隱藏起來,從外部不能調(diào)用).但是在下例中,不能使用private,而必須使用protected.
class Foo def _val @val end protected :_val def op(other) # other 也假定 Foo 的實例 # 如果_val 是 private的話,就只能以函數(shù)的形式來調(diào)用 # 所以不能這么用 self._val + other._val end end
例:
alias foo bar alias :foo :bar alias $MATCH $&
語法:
alias 新方法名 舊方法名 alias 新全局變量名 舊全局變量名
給方法或全局變量添加別名.可以給方法名指定一個標(biāo)識符或Symbol(不能寫obj.method這樣的表達(dá)式).alias的參數(shù)不會被計算.
若想在方法定義內(nèi)部添加別名時,請使用Module類的Module#alias_method方法.
給方法添加別名時,別名方法將繼承此刻的原始方法.此后,即使原始方法被重新定義,別名方法仍然保持著重定義前的老方法的特性.若您改變了某方法的內(nèi)容后,又想使用修改前的方法時,別名會非常有用.
# 定義 foo 方法 def foo "foo" end # 設(shè)定別名(避開方法定義) alias :_orig_foo :foo # 再定義 foo (利用以前的定義) def foo _orig_foo * 2 end p foo # => "foofoo"
給全局變量設(shè)定alias就意味著定義一個完全相同的變量.當(dāng)你向一個賦值時,另一個也會有所反映.附加庫的importenv.rb正是利用了這個特性,給內(nèi)部變量添加了英文名.ruby 1.7 特性:在1.6版本中,只能給特定的內(nèi)部全局變量添加別名.到了1.7版本時,這項限制被取消了.
# 在給特殊變量添加別名之后,當(dāng)其中一個發(fā)生變化時,另一個也會有所反應(yīng) $_ = 1 alias $foo $_ $_ = 2 p [$foo, $_] # => [2, 2] # 這是通常的變量的別名,它并非真正意義上的別名. # 這是1.6版本以前 # 的限制 $bar = 3 alias $foo $bar $bar = 4 p [$foo, $bar] # => [3, 4]
但是,您不能給正則表達(dá)式中的變量$1,$2,...等添加別名.另外,有些全局變量(請參考內(nèi)部變量)對于解釋器來說是舉足輕重的,若重新定義它們的話,有時會影響解釋器的工作.
alias
表達(dá)式返回 nil.
例:
undef bar
語法:
undef 方法名[, 方法名[, ...]]
取消方法定義.可以向方法名指定一個標(biāo)識符或Symbol(不能寫obj.method這樣的表達(dá)式).undef的參數(shù)不會被計算.
若想在方法定義的內(nèi)部取消定義時,請使用Module類的Module#undef_method方法.
undef會取消方法名和方法定義之間的關(guān)系,然后把該方法名關(guān)聯(lián)到一個特殊的定義上.若在此時進行方法調(diào)用的話,即使超類中有同名方法,也會引發(fā)NameError異常.(另外,Module#remove_method方法只負(fù)責(zé)取消關(guān)系,這點差別非常重要.)
用alias添加別名或用undef取消定義時,會修改類的接口,而不受超類的限制.但有時方法會向self發(fā)出消息,若不小心處理的話可能會導(dǎo)致原有方法失效.
undef
表達(dá)式返回 nil.
例:
defined? print defined? File.print defined?(foobar) defined?($foobar) defined?(@foobar) defined?(Foobar)
語法:
defined? 表達(dá)式
若表達(dá)式尚未定義,則返回偽.若已經(jīng)定義,則返回一個字符串,字符串的內(nèi)容是該表達(dá)式的種類.
不論是未定義的方法,被undef的方法,還是被Module#remove_method刪除的方法,defined?都將返回偽.
還可以使用下列特殊用法.
defined? yield
若yield調(diào)用可用,則返回真(字符串"yield").它的作用同block_given?一樣,可以判斷能否以帶塊方式來調(diào)用某方法.
defined? super
若super可行,則返回真(字符串"super").
defined? a = 1 p a # => nil
返回"assignment".雖然沒有賦值,但已經(jīng)定義了局部變量.
/(.)/ =~ "foo" p defined? $& # => "$&" p defined? $1 # => "$1" p defined? $2 # => nil
只有設(shè)定了前面的匹配值以后,測試$&, $1, $2才會返回真.
def Foo(a,b) end p defined? Foo # => nil p defined? Foo() # => "method" Foo = 1 p defined? Foo # => "constant"
若沒在以大寫字母開頭的方法名后添加"()"時,該方法名會被當(dāng)做常數(shù)處理.
下列就是defined?的所有的返回值.