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