klass.instance_methods只返回某klass類(或模塊)中所定義的實例方法, 而klass.instance_methods(true)則會返回所有的實例方法, 包括從超類中繼承來的實例方法。(但僅限于public方法)
private_instance_methods與protected_instance_methods的參數的意義相同。
7.2 為什么rand總是生成相同的隨機數?在ruby 1.4.2以前的版本中, 每次執行程序時rand都會生成相同的隨機數。為了生成不同的隨機數, 每次都必須使用srand來給出不同的隨機數種子。若不帶參數地調用srand的話, 它將使用當時的時間作為種子, 因此可以產生出不同的隨機數。
7.3 怎樣從0到51中選出5個不重復的隨機數呢?下面的方法可以從0到n中選出m個隨機數,并以數組的形式返回結果。
def sample(n, m) if m.zero? [] else s = sample(n-1, m-1) t = rand(n+1) s.concat s.include?(t) ? [n] : [t] end end若不使用遞歸的話, 可以寫成這樣。
def sample(n, m) s = [] ((n-m)...n).each do |j| t = rand(j+2) s.concat s.include?(t) ? [j+1] : [t] end s end 7.4 Fixnum、Symbol、true、nil和false這些立即值與引用有什么不同?不能定義特殊方法。
另外, 表示同一個數字的Fixnum的實例通常都是相同的, 所以定義實例變量時, 它們的所指也是相同的。
7.5 nil和false有什么不同?對nil.methods - false.methods和false.methods - nil.methods執行情況的差異就說明了nil和false所帶方法的不同。
若某方法返回一個布爾值時,通常會返回true或false; 除此以外,方法通常返回值或nil。
通常情況下, 帶?的方法會返回布爾值, 當然也有例外(在標準配置中只有nonzero?)。
7.6 為什么讀入文件并修改之后, 原文件依然沒有變化?open("example", "r+").readlines.each_with_index{|l, i| l[0,0] = (i+1).to_s + ": "}上面的代碼并不能將行號添加到example中。這是因為該代碼并沒有修改原文件, 而只是修改了readlines讀入的字符串而已。必須將修改后的內容寫入文件才行。
io = open("example", "r+") ary = io.readlines ary.each_with_index{|l, i| l[0,0] = (i+1).to_s + ": "} io.rewind io.print ary io.close此時因為文件增大了, 所以沒有出現什么問題. 如果文件變小的話,就必須將下列代碼
io.flush io.truncate(io.pos)嵌入到io.close之前才行.
7.7 怎樣覆蓋同名文件?使用命令行選項-i或者將內部變量$-i設為""之后, 就可以覆蓋同名文件了。
您可以使用下列代碼。
$ ruby -i -ne 'print "#$.: #$_"' example若想保留原來的文件時, 可以-i.bak這樣。
7.8 寫文件后拷貝該文件,但所得副本并不完整,請問原因何在?open('file', 'w').print "This is a file.\n" system 'cp file copy'上述代碼之所以出錯,是因為拷貝文件時有一部分內容尚未被flush進file中所致。因此,請先close然后再進行拷貝。
f = open('file', 'w') f.print "This is a file.\n" f.close system "cp file copy" 7.9 在管道中將字符串傳給less后, 為什么看不到結果?f = open '|less', 'w' f.print "abc\n"上述代碼會立刻結束,您無法看到less的顯示結果。添加一個close,以便等待less完成顯示。
f = open '|less', 'w' f.print "abc\n" f.close第一行也可以寫成f = IO.popen 'less', 'w'。
7.10 無法引用的File對象將會何去何從?open("file").read中的File是無法引用的, 它會被后來的垃圾回收器所close和銷毀.
7.11 怎樣手動關閉文件?GC會自動關閉不再使用的File對象. 若您想自己關閉文件的話, 可以從下面4種方法中任選其一(按照代碼長度排列)。
File.foreach('filename') {|line| print line } File.readlines('filename').each {|line| print line } File.open('filename') {|f| f.each {|line| print line } } begin f = File.open('filename') f.each {|line| print line } ensure f.close if f end 7.12 如何按照更新時間的新舊順序來排列文件?Dir.glob("*").collect{|f| [File.mtime(f), f] }. sort{|a,b| b[0]<=>a[0] }.collect{|e| e[1] }上述代碼將會按照更新時間的新舊順序來排列當前目錄中(除了"."、".."以外)的文件, 并以數組的形式返回結果. 若想按照相反順序來排序的話, 就可以去掉sort后面的塊。
Dir.glob("*").sort{|a,b| File.mtime(b)<=>File.mtime(a)}盡管這樣可以完成排序, 但是每次都要訪問文件來獲取更新時間, 因而排序過程較慢。
為解決這個問題, 可以先生成一個對象, 它負責將每個文件的更新時間存入高速緩存, 這樣就可以提高處理速度。
cache = {} def cache.mtime(x) self[x] ||= File.mtime(x) end Dir.glob("*").sort{|a,b| cache.mtime(b) <=> cache.mtime(a)} cache = nil另外,在ruby 1.7中提供了Enumerable#sort_by方法, 使用它可以輕松完成上述任務。
Dir.glob("*").sort_by {|f| File.mtime(f)}.reverse 7.13 如何獲取文件中單詞的出現頻度?將哈希表的默認值設為0之后, 可以這樣處理。
freq = Hash.new(0) open("file").read.scan(/\w+/){|w| freq[w] += 1} freq.keys.sort.each {|k| print k, "--", freq[k], "\n"} 7.14 為什么條件表達式中的空字符串表示true呢?在Ruby中,只有nil和false表示假, 其他的都表示真。若想判斷某字符串是否為空時, 可以將它與""作比較,或者使用empty?, 或者將其length與0作比較 即可得出結果。
7.15 如何按照字典順序來排列英文字符串數組?您可以這樣排序
ary.collect{|f| [f.downcase, f]}.sort.collect{|e| e[1]}若downcase形式相等時, 則按照原來字符串來排序。
7.16 "abcd"[0]會返回什么?它將返回字符a的代碼97(Fixnum)。若想驗證它與a是否一致時,可以使用?a進行比較。
7.17 怎么把tab變成space?常用方法如下。
# 非破壞性的方法 def expand_tab( str ) str.gsub(/([^\t]{8})|([^\t]*)\t/n) { [$+].pack("A8") } end # 破壞性的方法 def expand_tab!( str ) 1 while str.sub!(/(^[^\t]*)\t(\t*)/) { $1 + ' ' *在正則表達式中, Regexp.quote('\\')就可以實現轉義。
若使用gsub的話, 在gsub(/\\/, '\\\\')中,進行句法分析時會將替換字符串變為'\\', 而實際替換還會將其解釋成'\', 所以必須寫成gsub(/\\/, '\\\\\\')才行。若使用\&來表示匹配字符串的話, 則可以寫成gsub(/\\/,'\&\&')。
另外, 若使用形如gsub(/\\/){'\\\\'}的塊的話, 就只會進行一次轉義, 因此可以得到預期的結果。
7.19 sub和sub!的區別在哪里?sub不會改變被調的狀態。首先,它會拷貝字符串, 然后在副本中進行替換操作,并返回結果(若沒有必要替換時,就直接返回副本)。
而sub!則會改變被調本身。若沒有進行替換的必要時, 將返回nil。
像sub!這種會修改被調本身的方法叫做破壞性的方法。在Ruby中, 若同時存在同名的破壞性方法和非破壞性方法時, 通常在破壞性方法名后添加!。
def foo(str) str = str.sub(/foo/, "baz") end obj = "foo" foo(obj) print obj #=> "foo" def foo(str) str = str.sub!(/foo/, "baz") end foo(obj) print obj #=> "baz"像sub!這樣的破壞性的方法可能會帶來非預期的效果, 請慎用。
7.20 \Z匹配什么?當字符串末尾字符不是\n時,\Z匹配于字符串的末尾字符;當字符串的末尾字符是\n時,它匹配于換行之前的部分。
若想讓它一直匹配于末尾字符,而不理會\n的問題時,應該使用\z。
7.21 范圍對象中的..和...有什么不同?..包含終點,而...不包含終點。
7.22 有函數指針嗎?若使用Proc.new、proc、lambda生成了Proc對象的話,就可以將其用作函數指針。
另外,Method和UnboundMethod對象也很類似于函數指針。
7.23 線程和進程fork有何異同?線程和進程fork分別具有以下特點:
進程間不能共享內存 線程和進程的切換都是不定時的 Ruby線程可運行于任何OS 若Ruby線程發生阻塞的話,整個都會停頓下來(non preemptive) Ruby線程不會引發系統顛簸(thrashing)(*)*系統顛簸是指,當進程或線程過多時,因處理它們的切換問題而消耗了過多的系統時間,所導致的系統無效。
通常不應該混用進程fork和線程。
因為Ruby線程采用分時機制,所以使用進程后并不會加快處理速度。由于Ruby線程是用戶線程,因此無法享受多處理機的好處。
7.24 如何使用Marshal?它可以將對象轉變為字節串(即serialize)。您可以將對象存入文件,以后再將其還原,或者通過網絡把它發送出去。例如,您可以這樣把obj對象轉為字節串
Marshal.dump(obj)該方法返回字符串,因此可以將其存入文件。
File.open('filename', 'w') {|f| f.write Marshal.dump(obj) }因為經常需要進行上述操作,所以Ruby提供了下列簡便方法。
Marshal.dump(obj, io)io表示可寫入的IO對象。另外使用上述方法處理較大的對象時,就省去了生成巨大字符串的麻煩。
另一方面,您可以像下面這樣來還原對象。首先是使用字符串進行還原的例子。
obj = Marshal.load(str)下面的是直接使用IO對象進行還原。
obj = Marshal.load(io) 7.25 Ruby有異常處理語句嗎?有。通常使用下列語句。
begin (發生異常之前所處理的事務) rescue (異常類) (發生異常時的處理) else (沒有異常時的處理) ensure (必須處理的事務) end在begin語句中,若發生異常就會執行rescue部分。若沒有異常就執行else部分。另外,不管有沒有異常,都必須執行ensure部分。rescue,else和ensure部分都是可以省略的。若rescue后面沒有給出異常類,就使用StandardError作為其默認值。此時將捕捉StandardError的子類。
該語句的值取決于執行ensure部分之前的值。
另外,您可以使用全局變量$!來獲得最后發生的異常,使用$!.class來了解該異常的種類。
7.26 如何使用trap?下面的代碼在捕捉到SIGPIPE信號時會執行塊的內容(隨即引發異常)。
trap("PIPE") {raise "SIGPIPE"} 7.27 如何統計文件的行數?若假定文件末尾也有個換行符的話,下面的方法可能是最簡單的。
open("filename").read.count("\n") 7.28 怎樣把數組轉化為哈希表?您可以這樣把數組array轉化為哈希表
h = Hash[*array]此時array中的奇數元素將成為哈希表h的鍵,而偶數元素將成為相對應的值。數組array中的元素個數必須是偶數。
array = [1,2,3,4] h = Hash[*array] p h => {1=>2, 3=>4}數組array前面的"*"表示展開參數。
7.29 將字符串變為Array時可以使用%w(...),那么將字符串變為Hash時能不能如法炮制呢?您不能像生成Array那樣來直接生成Hash,但您可以這樣
p h = Hash[*%w(1 foo 2 bar)] => {"1"=>"foo", "2"=>"bar"}先生成Array,然后將其轉化為Hash。(但此時哈希表的鍵和值都被限定為字符串)
7.30 為何無法捕捉NameError異常呢?在1.4以前的版本中,下列代碼中的rescue部分都可以正常運行,可是到了1.6版本就不行了。
begin foo rescue puts "TRAP : #$!" end -:2: undefined local variable or method `foo' for這是因為NameError異常類不再是StandardError的子類所致(若不指定異常類時,rescue將只負責捕捉StandardError旗下的異常類)。此時,必須顯式地指定NameError才行。
begin foo rescue NameError puts "**TRAP** : #$!" end ruby 1.6.7 (2002-03-20) [i586-linux] **TRAP** : undefined local variable or method `foo' for可是到了1.7版本時,NameError類又重新成為StandardError的子類。請您參考異常類中的類層次構造來了解默認情況下所能捕捉的異常的范圍。
7.31 為什么有suclearcase/" target="_blank" >cc卻沒有prev呢?雖然定義Integer#prev并不困難,但卻沒有succ實用。
另一方面,定義String#prev則比較困難。例如
'09'.succ == '9'.succ #=> true因為有時succ前和后的字符串并不是一一對應的,所以str.prev.succ == str.succ.prev未必成立。
原文轉自:http://www.anti-gravitydesign.com