Rails停尸房 ---- (個人筆記,非仇勿擾)

1.puts , print 和p

(1)puts 如果字符串不是以換行結束,puts 給它輸出的字符串加一個換行符
(2)print精確地輸出被要求輸出的東西,光標會停在被輸入內容的行尾
(3)p輸出一個inspect字符串,它可能包含關于它正在輸出的是什么的附加信息.

a =gets 
print a
puts a
p a

==>
輸入 abc
abc
abc
"abc\n"


2.require 和load的區別

當你的文件分散在多個文件時,作為一個程序來運行最常用的技術是require命令,它在一個文件運行過程中讀入另一個文件.

load是require的近親.它們的主要區別在于,如果執行下面代碼:
require "requiree.rb"
require "requiree.rb"

第二次執行require什么都不發生,而如果執行下面的代碼:
load  "requiree.rb"
load "requiree.rb"

Ruby 會兩次讀入該文件
(備注:在某些時候多次加載同一個文件是有用的,盡管我們很少如此.)

3.常用Ruby命令開關總結
[quote](1)-c 不執行程序,只檢查(check)程序文件語法

(2)-w 在程序執行過程中給出警告(warning)信息

(3)-e 執行(excute)在命令行引號內的代碼

(4)-v 顯示Ruby版本(version)信息,在詳信模(verbose)式下執行程序

(5)-l 行(line)模式: 如果沒有換行則在每一行輸出后輸出一個換行

(6)-rname 加載指定的擴張(require)

(7)- -version 顯示Ruby版本(version)信息
[/quote]
一般情況都是用組合命令,如 -cw, -ve

4.退出irb的命令

如果irb在一個循環或僵局中卡住了,Ctrl+c可以強制退出.而一般情況則使用Ctrl+d或exit

5.在引用擴展到時候,你會看到這樣的一句代碼, require 'cgi',而不是 require 'cgi.rb'

采用裸詞典方式引用擴展一方面是因為這樣較為美觀,但很重要的一個原因是因為并非所有的擴展都用.rb文件名后綴的.

6.庫和擴展到區別
(1)庫是一個廣義的術語,指一個編程命令和技術的集合,該集合可用require語句引入到你自己的程序中.

(2)擴展通常是指與Ruby一起發行的庫,而不是那些由第三方的程序員編寫切可以被別人在其應用程序中使用的庫.

(備注:有一個例外,那就是用C編寫的擴展通常都被稱為擴展,包括與Ruby一起發行的和那些作為外加物(add-on)編寫的)

7.如何讓Ruby告訴你它安裝的位置?

首先可以這樣用-r標志啟動irb,請求加載一個rbconfig的擴展

 irb -r rbconfig


這會是的irb預加載一些特定安裝的配置信息.這時候你就可以查詢相關的安裝位置了,如

irb(main):001:0> Config::CONFIG["bindir"]



8.一些有用的擴展和庫,你可以通過require來請求加載
[quote]
(1)cgi,rb -------- 方便CGI編程的工具
(2)fileutils.rb --------可在Ruby程序中容易地處理文件的工具
(3)tempfile.rb -------用于自動生成臨時文件的機制
(4)tk.rb ----- Tk圖形庫接口
........還有很多很多,果段時間再整理.....[/quote]

9.Ruby調式器
Ruby的調試設施(在庫文件debug.rb中)幫助你調試程序,它允許一次運行一條指令,然后暫停.在暫停期間,它會顯示一個提示符;在這個提示符下,你可以檢查變量的值,查看你一系列嵌套的命令中的位置,然后繼續執行.你也可以設置斷點-------在程序你想要調試器停止執行并顯示提示符的地方設置.
使用方法類似這樣ruby -rdebug y.rb
step命令則是告訴調試器運行下一條指令

10.性能分析
profiling的意思是測量程序的不同部分使用了多少系統資源--------主要是時間資源.(備注:一般情況下,在程序較長時,特別是多次循環執行指令的程序,它是很有必要作下分析的.)
使用方法類似這樣 ---> ruby -r profile y,rb

性能分析可以查出程序中哪些代碼使用了大量的資源從而導致程序變慢.它所提供的信息可用于優化程序的某個部分使其更高效地運行;或者,如果沒有相對容易的辦法克服資源瓶頸,那么你可能會用C重寫某些部分,以使其更快.

11.兩條備忘的rake命令(rake -T 可以查詢所有rake命令)
(1)rake db:migrate:redo   撤銷你最后的遷移任務,然后重新運行

(2)rake db:migrate:reset 刪除數據庫,創建數據庫,運行所有遷移任務

12.Rails編程事實上就是Ruby編程,但反過來是不成立的.

13.三個常用的對象固有方法:object_id 、respond_to?和send

(1)obeject_id 可用該方法唯一地標識對象
每個Ruby對象都有唯一的id值.想要看到對象的id值,可以調用對象的object_id方法
 obj = Object.new
puts "The id of obj is #{obj.object_id}."
str = "String are objects too, and this is a string!"
puts "The id of the string object str is #{str.object_id}."
puts "And the id of the integer 100 is #{100.object_id}"


這個例子只是普通的表明對象有唯一ID,現在可以看看下面這個例子

a = Object.new
b = a
puts "a's id is #{a.object_id} and b's id is #{b.object_id}."

盡管a和b是不同的變量,但它們引用的是同一個對象.但有時候你可能認為兩個對象是同一個,而實際上......
string1 = "Hello"
string2 = "Hello"

puts "string1's id is #{string1.object_id}"
puts "string2's id is #{string2.object_id}"

盡管這兩個字符串包含了同樣的文本,但是,從技術上來說,它們不是同一個對象.

(備注:盡管Ruby的object_id方法和ActiveRecord的id方法都返回數值,但它們是不同的.object_id給出對象在Ruby內部的值;ActiveRecord的id方法給出的是你正在處理的模型的數據庫表的id字段的值)

(2)respond_to? 可用它來查詢對象的能力

使用respond_to?方法可以事先判定對象是否能相應給定的消息.respond_to?方法存在于所有的對象中;對于任意的消息,可以詢問任何對象.是否它可以響應該消息.(respond_to?常與條件if邏輯一起出現)
  obj = Object.new
if obj.respond_to?("talk")
obj.talk
else
puts "Sorry, the object doesn't understand the 'talk' message."
end


(3)send 可用它來給對象發送消息

14.參數數目問題

*X記法意味著:在調用該方法的時候,可以提供任意數目的參數(包括不提供任何參數)
-->def opt_args(a,b,*c)是正確寫法,而def opt_args(a,*b,c)是不對的,不解析...

15.attr_*方法小結

(1) attr_reader 產生讀方法
attr_reader :venue 等價于
def venue
@venue
end


(2)attr_writer 產生寫方法
attr_writer :price 等價于
def price=(price)
@price = price
end


(3)attr_accessor 產生讀寫方法
attr_accessor 等價于
def price=(price)
@price = price
end
def price
@price
end


(4)attr 產生讀方法和可選的寫方法(如果第二個參數是true)
1.attr :venue 等價于(1)
2.attr :venue,:price 等價于(3)

16.模塊有時候被稱為混含子(mix-in),而mix-in操作由include語句實現.

17.object混含了一個更基礎的模塊:Kernel.如果方法查找已經到達了Kernel,但仍然沒有找到請求執行的方法,這就意味著該方法找不到.

解析下下面這幅圖,該方法查找路徑從類D開始,一直往上直到Kernel.這幅圖顯示的是:如果在那里沒有找到該方法,對該方法的搜索可以達到多遠.
圖中的消息“x”被發送給對象,方法搜索開始,在搜索過程中,會依次遇到箭頭所指向導各個類和模塊.
[img]http://dl.iteye.com/upload/picture/pic/65315/8476d949-ef80-3778-85d9-ac2e047c4feb.jpg[/img]

18.如何處理同名方法
需要遵循兩條規則 --->

(1)在任意給定的時刻,就一個給定的名字來說,類或模塊只能有一個對應的方法

(2)對象可以在多個類和/或模塊中查找方法,在找到第一個與方法名匹配的方法時停止查找.

19.super可以提升方法查找路徑
它可以在一個方法定義內部,獲取并執行在方法查找路徑上下一個匹配該方法名單方法

module M
def report <----(1)
puts "'report' method in module M"
end
end
class C
include M
def report <----(2)
puts "'report' method in class C"
puts "About to trigger the next higher-up report method..."
super <----(3)
puts "Back from the 'super' call."
end
end

c = C.new
c.report <----(4)

運行上面代碼,我們可以看到===>
'report' method in class C
About to trigger the next higher-up report method...
'report' method in module M
Back from the 'super' call.


C的實例接受到"report"消息(4).方法查找從c所屬的類C開始.很明顯,類C中有report方法(2).于是執行該方法

但是,在該方法中有一個對super的調用.這意味著雖然已經找到了對應于"report"消息的方法,但必須繼續查找下一個匹配.也就是(1)啦...


三種形式的super-->

[quote](1)以裸詞的方式(即super)調用時,自動向前傳遞調用super的方法所獲得的參數;
(2)用空參數表(即super())調用時,不給上一級方法傳遞任何參數,即使是當前方法的參數也不傳遞;
(3)用特定的參數(如super(a,b,c))調用時,傳遞這些指定的參數

20.About self
(1)Ruby編程的一個基石是默認對象或者當前對象在程序中可通過關鍵字self訪問它.

(2)在程序執行的任意時刻,有且只一個self.

(3)總有一個對象成為self,哪個對象是self取決于你在程序中的位置.

(4)關鍵字class、module和def標志著切換到新的self
[/quote]
21.self在需要圓點時不能省略
在一個場合,即使是發送消息給當前的self,也必須使用完整的"對象-圓點-對象"記法,那就是在調用寫方法(以等好結束的方法)的時候.如果想要調用venue=,那么必須使用self.venue= "Town Hall"而不是使用venue= "Town Hall".原因是Ruby總是將序列"裸詞=值"解析為對局部標量的賦值.為了調用當前對象的venue=方法,必須顯式地給出self.否則最終將得到一個名為venue的變量,而且寫方法也沒有被調用.

22. 代碼塊、迭代器和yield
在調用一個方法時(在任何時候,任何方法,不管帶不帶參數),可以選擇是否提供一個代碼塊.該代碼塊可以由任意多行當Ruby代碼塊構成.該代碼塊用大括號來封裝,比如:
object.method_name{
#code inside block
}
也可用do/end關鍵字封裝
object.method_method do
#code inside block
end


但是為什么要給方法調用添加一個代碼塊呢?這是為了讓方法可以匿名調用該代碼塊.

(1)yield關鍵字的應用
如果在調用方法時提供了代碼塊,那么該方法執行過程中可以將控制轉移到該代碼塊(暫停方法的執行),執行代碼塊中的代碼,然后再將控制返回到方法體中緊鄰yield調用之后的位置.
這就像一個反向的方法調用.調用一個方法導致控制從包含該調用的行轉移到該方法的定義體中.yield關鍵字導致從方法定義體中回到放置在方法調用之后的代碼塊中.

def demo_of_yield
puts "Executing the method body..."
puts "About to yield control to the block..."
yield
puts "Back from the block—finished!"
end

demo_of_yield { puts "> Control has been passed to the block!" }

Executing the method body...
About to yield control to the block...
> Control has been passed to the block!
Back from the block—finished!

不解析

(2)給代碼塊傳遞參數
代碼塊和方法有很多的共性.它們都是由代碼行構成;都可以執行,一個是通過直接的調用,另一個是通過匿名調用,
代碼塊是可以接受參數的,可以通過給yield提供參數來發送參數到代碼塊。要使用三個參數匿名調用一個代碼塊,可以這樣做;
yield(x,y,z)
但是,代碼塊指定它所能接受的參數的方式有所不同.方法是通過圓括號中列出代表參數的變量的名字來達到目的的.
def met(a,b,c)
而代碼塊采用不同的語法:不使用圓括號,而是使用一對管道符號(||):
some_method{|a, b, c|
# code here
}

(3)從代碼塊返回值
如果代碼塊不能返回值及不能接受參數,那么它的用途有限.
代碼塊的返回值(和方法返回值一樣)是代碼塊最后一個表達式的值.在方法中,代碼塊的返回值是可訪問的;它們就是yield的返回值.

def more_yielding
puts "The code block shall multiply a number by 10."
result = yield(3)
puts "The result of this operation is #{result}."
end

more_yielding {|x| x * 10 }


(4)執行多個迭代
方法匿名調用代碼塊的過程被稱為迭代,任何匿名調用代碼塊的方法被稱為迭代器.迭代暗示重復做某事.

def temp_chart(temps)
for temp in temps
converted = yield(temp)
puts "#{temp}\t#{converted}"
end
end

celsiuses = [0,10,20,30,40,50,60,70,80,90,100]
temp_chart(celsiuses) {|cel| cel * 9 / 5 + 32 }



23.關于for的更多內容
for的本質就是迭代器.for是調用一個特殊的迭代器each的一種可選方式
for x in [1,2,3,4]
puts x * 10
end
等價于
[1,2,3,4].each {|x| puts x * 10}

同理下面代碼也是等價的,只是出于習慣,大家都比較樂意使用for方法

<% for s in @students %>
dd<%= link_to s.name,
ddddd:controller => "student",
ddddd:action dd=> "grade",
ddddd:id ddddd=> s.id %>
<% end %>


等價于

<% @students.each do |s| %>
d<%= link_to s.name,
dd# etc.
<% end %>


24.常見的異常
(1)RuntimeError 這是raise方法拋出的默認異常 --> raise

(2)NoMethodError 對象收到一個找不到對應方法的消息 --->
a = Object,new
a.some_unknow_method_name

(3)NameError 解析器碰到一個不能解析為變量或方法名的標識符 -->
a =some_random_identifier

(4)IOError 讀關閉的流(stream),寫只讀的流, 或類似的操作 --->
STDIN.puts ("Don't write to STDIN!")

(5)Error::error 與文件IO相關的一族錯誤 -->
File.open(-12)

(6)TypeError 方法接收到它不能處理的參數 --->
a = 3 + "can't add a string to a number! "

(7)ArgumentError 傳遞參數的數目出錯 --->
def m(x)
end
m(1,2,3,4,5)

25用rescue塊來營救異常(注意不是老拋)
拋出異常并不一定意味著程序會終止.可以通過使用rescue關鍵字來處理異常------------解析問題并繼續執行.

通過使用rescue塊,將程序從異常中營救出來.有兩種生成的rescue塊的

(1)將想要保護的代碼塊用begin/end包圍起來(媽的,稍微靠近邊界點,就算過濾代碼了)

(2)要保護一個完整的方法定義,你僅僅需要將一條rescue子句放在方法定義體重最后的位置.

begin/end案例
print "Enter a number: "
n = gets.to_i

begin
result = 100 / n
rescue
puts "Your number didn't work. Was it zero???"
exit
end

puts "100/#{n} is #{result}."

如果運行此程序并輸入0,除法操作(100/n)會拋出一個ZeroDivisionError異常.因為是在一個rescue塊中進行此操作,所以控制將被傳遞給該塊的rescue部分.輸出一條錯誤信息,然后退出程序.

26.顯式拋出異常
為了拋出異常,可以使用raise加上想要拋出的異常的名字.還可以給raise提供第二個參數,作為拋出異常時的消息字符串.

def fussy_method(x)
raise ArgumentError, "I need a number under 10" unless x < 10
end

fussy_method(20)

-->
fussy.rb:2:in `fussy_method':
I need a number under 10 (ArgumentError)from fussy.rb:5

你也可以在此例中使用rescue


begin
fussy_method(20)
rescue ArgumentError
puts "That was not an acceptable number!"
end

通過營救ArgumentError,可以保證在拋出異常且還有其他錯誤發生時,不會捕捉到其他錯誤,這樣,就不會營救多余的錯誤而一不小心掩蓋了問題.

重新拋出異常是一個很有用的技術.其思想是:雖然代碼中有rescue塊處理異常,但是還可以把異常傳遞到調用代碼的位置做進一步處理.

def reraiser(filename)
file_handle = File.new(filename)
rescue Errno::ENOENT => e
puts "Something's wrong with your filename...."
raise e
end

reraiser("some_non_existent_filename")

outputs the following:

Something's wrong with your filename....
reraiser.rb:2:in `initialize': No such file
or directory - some_non_existent_filename
(Errno::ENOENT)

創建異常類
class MyNewException < Exception

end

raise MyNewException, "some new kind of error has occurred!"

首先,給異常類提供新名字,實現一種自文檔功能.

其次,該方法使得你可以指定你的營救操作.

class MyNewException < Exception
end

begin
puts "About to raise exception..."
raise MyNewException
rescue MyNewException => e
puts "Just raised an exception: #{e}"
end

The output from this snippet is as follows:
About to raise exception...
Just raised an exception: MyNewException

26.內建的和定制的to_*(轉換)方法
(1)to_s 轉換成字符串

(2)to_a 轉換成數組

(3)to_i 轉換成整數

(4)to_f 轉換成浮點數
.......
(5)編寫自己的to_*方法

class C
def initialize(name)
@name = name
end
def to_s
"A C object named #{@name}"
end
end

c = C.new("Emma")
puts c


(備注:puts 會自動調用to_s)

[常識普及,單引號字符串不能進行字符串的內插,也就是禁止#{...}]

28.字符串應用機制概要
[img]http://dl.iteye.com/upload/picture/pic/65317/44c72bb5-4343-354f-be80-87c4ebd13822.jpg[/img]


29.各種各樣的字符串操作
[img]http://dl.iteye.com/upload/picture/pic/65319/9314196e-a016-301d-9b78-052f4202ad21.jpg[/img]


30.數組摘錄
[quote](1)一次讀寫多個數組元素
>> a = ["red","orange","yellow","purple","gray","indigo","violet"]
=> ["red", "orange", "yellow", "purple", "gray", "indigo", "violet"]
>> a[3,2]
=> ["purple", "gray"]
>> a[3,2] = "green", "blue"
=> ["green", "blue"]
>> a
=> ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]

(2)對數組的頭或尾進行操作的特殊方法
給數組頭部添加一個對象-->
a = [1,2,3,4]
a.unshift(0)

the array a now looks like this: [0,1,2,3,4].

給數組尾部添加一個對象
a = [1,2,3,4]
a.push(5)

results in the array a having a fifth element: [1,2,3,4,5].

還可以用<<方法(兩個小于號)給數組尾部添加一個對象。
a = [1,2,3,4]
a << 5
備注(<<和push方面的不同之處在于,push可以帶多個參數.)
a = [1,2,3,4,5]
a.push(6,7,8)

adds three elements to a, resulting in: [1,2,3,4,5,6,7,8].

與unshift和push相反的是shift和pop.Shift從數組頭部刪除一個對象,從而把其他的對象依次向左移一個位置.而Pop從數組尾刪除一個對象.shift和pop都返回它們刪除的那個元素.
a = [1,2,3,4,5]
print "The original array: "
p a
popped = a.pop
print "The popped item: "
puts popped
print "The new state of the array: "
p a
shifted = a.shift
print "The shifted item: "
puts shifted
print "The new state of the array: "
p a

The output is as follows:

The original array: [1, 2, 3, 4, 5]
The popped item: 5
The new state of the array: [1, 2, 3, 4]
The shifted item: 1
The new state of the array: [2, 3, 4]

(3)concat和push的不同
>> [1,2,3].concat([4,5,6])
=> [1, 2, 3, 4, 5, 6]


>> [1,2,3].push([4,5,6])
=> [1, 2, 3, [4, 5, 6]]

(4)concat永久性的改變了接收者的內容.如果想將兩個數組合并成一個新數組,可以用+方法
來做這件事

>> a = [1,2,3]
=> [1, 2, 3]
>> b = a + [4,5,6]
=> [1, 2, 3, 4, 5, 6]
>> a
=> [1, 2, 3]

(5)另一個用來合并數組的方法是replace

>> a = [1,2,3]
=> [1, 2, 3]
>> a.replace([4,5,6])
=> [4, 5, 6]
>> a
=> [4, 5, 6]

(6)zip并行地遍歷兩個數組,產生一個新的數組,該數組包含從原來兩個數組中取出的成對待元素:

>> [1,2,3].zip([4,5,6])
=> [[1, 4], [2, 5], [3, 6]]

(7)flatten可以進行徹底的平坦化,不管有多少層

a = [0,2,4,6]
b = [1,3,5,7]
and you want to zip or interweave them:
numbers = a.zip(b)
At this point, numbers is an array of arrays: [[0,1],[2,3],[4,5],[6,7]]. But what
you want is an array of numbers from 0 to 7.

To achieve this, you can use flatten. Let’s rewind and pretend we did this in
the first place:

numbers = a.zip(b).flatten
flatten removes the nesting and leaves you with a flat array of the items that were
previously inside nested arrays. numbers is now [0,1,2,3,4,5,6,7]. Note that
flatten flattens completely, no matter how deeply nested the array is:
>> [1,2,[3,4,[5,6],7],[[[8,9]]]].flatten
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

(8)reverse方法

>>[1,2,3,4].reverse
=> [4, 3, 2, 1]

(9)join的返回值不是數組而是一個字符串,一個把數組中的所有元素串在一起表示的字符串:

>> ["abc", "def", 123].join
=> "abcdef123"
join takes an optional argument; if given, the argument is placed between each
pair of elements:
>> ["abc", "def", 123].join(", ")
=> "abc, def, 123"

(10)uniq對數組進行轉換.uniq返回一個新數組,該數組刪除了原來數組中所有重復元素.
>> [1,2,3,1,4,3,5,1].uniq
=> [1, 2, 3, 4, 5][/quote]

31.數組迭代、過濾和查詢
數組的迭代器方法通常會返回數組元素的子集、有關數組的某些信息或者一個通過對原有數組元素逐個進行轉換而得到的新數組.

(1)each 它迭代遍歷數組并且一次一個地通過匿名調用將數組元素傳遞給代碼塊.
[1,2,3,4,5].each {|x| puts x*10}
一個有用的each變體是each_with_index,在遍歷數組時,它每次通過匿名調用給代碼塊傳遞兩個值:當前數組元素及其數值索引
["a","b","c"].each_with_index{|x,i|puts "element #{i} is #{x}"}
(備注:它免去了使用一個顯示循環變量來跟蹤迭代的麻煩)

(2)find 找出數組中第一個作為參數匿名調用代碼塊返回真值的元素
>> [1,2,3,4,5,6,7,8,9,10].find{|n| n > 5}
==> 6
(備注:如果find找不到能通過代碼塊測試的元素,那么它返回nil.)

一個特殊的例子:
如果數組元素中有一個元素就是nil,而代碼塊要尋找一個等于nil的元素:
[1,2,3,nil,4,5,6].find{|x| x.nil? }
(請注意這里使用了內建的nil?方法,當接收者是nil對象時它返回真值).在這種情況下,find總是返回nil,不管這個搜索成功了還是失敗了!這意味著該測試是沒有用的;你不知道它是否成功搜索到要找的元素.可以用其它技術來繞過這種情況,例如include?方法,你可以使用該方法來判定數組中是否含nil元素.

(3)find_all 它返回一個數組,該數組包含原數組中能滿足代碼塊中條件的所有元素,而不僅僅只是第一個滿足條件的元素.如果沒找到滿足條件的元素,find_all返回一個空數組.
>> a = [1,2,3,4,5,6,7,8,9,10]
>>a.find_all{|item| item > 5 }
==>[6,7,8,9,10]
>>a.find_all{|x| x > 100 }
==>[]
(備注:select是find_all的同義詞;它們可以互換)

(4)reject 剔除條目,找出數組中那些作為參數匿名調用代碼塊返回假值的元素.
>>a.reject {|x| x > 5 }
==> [1,2,3,4,5]

(5)a.size(同義詞:length) 數組中元素的個數

(6)a.empty? a是空數組時為真,如果有元素則假

(7)a.include?(item) 數組a包含item時為真;否則為假.

(8)a.any?{|x| test }只要數組中有一個元素通過了代碼塊中的測試就是真;否則為假.

(9)a.all?{|item| test }只有數組中的每個元素都通過了代碼塊中的測試才是真;否則為假.

32.散列摘錄
(1)合并散列
破壞型操作通過update進行.如果第二個散列與第一個散列有相同的鍵,那第一個散列中的鍵-值對會被永久的刪除
h1 = {"Smith" => "John",
"Jones" => "Jane" }
h2 = {"Smith" => "Jim"}
h1.update(h2)
puts h1["Smith"]

==>Jim

非破壞型操作通過merge,這會得到第三個散列,而不會改變最初的散列.
h1 = {"Smith" => "John",
"Jones" => "Jane" }
h2 = {"Smith" => "Jim"}
h3 = h1.merge(h2)

puts h1["Smith"]
==>John

puts h3["Smith"]
==>Jim

(提醒:merge!是update的同義詞)

(2)散列轉換
轉換意味著對散列調用方法,且該操作的返回結果(即方法的返回值)是一個散列.
(提醒:數組是Ruby中最常見的,通用目的的集合對象;它們可用作容器存放操作的結果,即使這些操作并沒有涉及數組)

a.反轉散列
Hsah#invert交換鍵和值.值變成鍵,鍵變成值:(提醒:就我們所知,散列的值并不需要唯一,但鍵是唯一的,所以兩個相同的值變成鍵時,有一個鍵會被丟棄)

>> h = {1 => "one", 2 => "two", 3 => "two"}
>> h.invert
==> {"one" => 1, "two" => 3}
執行反轉時兩個two 的值只有一個能作為鍵保留下來;另一個會被拋棄

b.清空散列
Hash#clear清空散列

>>{1 => "one", 2 => "two"}.clear
==> {}
這是一個原地操作:空散列和收到clear的消息的散列是同一個散列.

c.替代散列的內容
散列有一個replace方法
>>{1 => "one", 2 => "two"}.replace({10 => "teb", 20 => "twe"})
=> {10 => "teb", 20 => "twe"}

33.散列的迭代、過濾和查詢
(1)each 在每一次迭代中,一個完整的鍵-值對通過匿名調用以一個兩元數組的形式傳給代碼塊:
>>{1 => "one", 2 => "two"}.each do |a,b|
puts "The word for #{a} is #{b}"
end
每次迭代執行代碼時,變量a和b被賦值為當前的鍵-值對里的鍵-值
Hash#each的返回值是散列----------each消息的接收者

(2)迭代遍歷所有的鍵或值
>>h = {1 => "one", 2 => "two"}
>>h.keys
==> [1,2]
>>h.values
==> ["one","two"]

34.正則表達式 =~和match的不同

它們的主要不同之處在于匹配時的返回值是不一樣的:=~ 返回匹配開始處的那個字符在字符串中的數值索引,而
match 返回MathData類的一個實例.

35.常見字符集的特殊轉義序列
\d ==> [0,9]
\w與任何數字、字母或下劃線(_)相匹配
\s與任何空白字符(空格、制表符、換行符)相匹配

$1包含的是正則表達式中從左側開始的第一對小括號內的子模式所匹配的子字符串.

? 0個或1個
× 0個或多個
+一個或多個

/\d{3}-\d{4}/可匹配 324-1234 {}可以明確指定子模式的具體重復次數,

同時也可以在{}指定一個范圍,

如/\d{1,10}/該模式與含有1~10個連續數字的任意字符串相匹配

單個數值后面跟一個逗號用于指定最小重復次數(n或更多此重復)

/\d{3,}/

36.正則表達式常用方法
String#scan
從左到右掃描一個字符串,重復地進行測試以尋找指定模式的各個匹配.結構返回到一個數組中.
>>"testing 1 2 3 testing 4 5 6".scan(/\d/)
==> ["1", "2", "3", "4", "5", "6"]
(提醒:scan會跳過字符串中與模式不匹配的部分繼續查找后續部分中的匹配)

String#split
它會將一個字符串分割為幾個子字符串,并返回到一個數組中.它可以采用一個正則表達式或者一個普通的字符串作為分割符來進行分割操作.
>>"Ruby".split(//)
==> ["R", "u", "b", "y"]

>>line = "first_name=david;last_name=black;country=usa"
>>record = line.split(/=|;/)
==>["first_name", "david", "last_name", "black", "country", "usa"]

sub/sub!和gsub/gsub!
sub和gsub的區別:gsub會遍歷整個字符串進行修改,而sub最多只進行一次修改.

(1)sub接受兩個參數,一個是正則表達式(或字符串)和一個替代字符串
>>"tryigraphical error".sub(/i/,"o")
==> "tryographical error"

(2)gsub
>>"capitalize every word".gsub(/\b\w/){|s|s.upcase}
==>"Capitalize Every Word"

grep 把與作為參數提供的正則表達式匹配的所有元素返回到一個數組
>>["USA", "UK", "France", "Germany"].grep(/[a-z]/)
==>["France", "Germany"]
(提醒:grep只能基于正則表達式的匹配來進行選擇,所以只能用來選擇字符串-------而且,它不會再字符串和數之間進行自動轉換.)
>>[1,2,3].grep(/1/)
==> []

37.eval方法族
"不管在執行程序之前從程序文件讀入了什么,現在開始執行這些代碼" -->eval say

將字符串作為代碼來求值得最直接的同時也是最危險的方法是eval方法.

(1)eval
>>eval("2+2")
==> 4
print "Method name:"
m = gets.chomp
eval("def #{m}; puts 'Hi!'; end")
eval(m)

==> Hi!


(2)instance_eval
該方法將self變為instance_eval調用的接收者,對字符串或代碼塊進行求值.
p self
a = []
a.instance_eval{ p self }


instance_eval常常用于訪問其他對象的私有數據--------特別是實例變量.

class C
def initialize
@x = 1
end

end
c = C.new
c.instance_eval {puts @x}

(3)class_eval(據說是最有用的eval族方法)
C = Class.new
C.class_eval do
def some_method
puts "Created in class_eval"
end
end
c = C.new
c.some_method

可以用class_eval做某些class關鍵字不能做到事:
a.在類定義的上下文中對字符串求值
b.為匿名類(但不包含單例類)打開類定義
c.獲取外圍作用域中變量的訪問權

38.可調對象
可調對象是一個對象,可以給該對象發送call消息,期望它執行定義在其中(通常是在一個代碼塊中)的某些代碼.Ruby中主要使用的可調對象方法有Proc對象和lambad.其中Proc對象是自包含(self-contained)的代碼序列,可以產生并保存它們,將它們作為方法參數傳遞,且可以使用call方法執行它們.

(1)Proc對象
用一個代碼塊來實例化Proc類,可以產生一個Proc對象:
pr = Proc.new {puts "Inside a Proc's block"}
請注意代碼塊并不在Proc對象產生的時候執行,它只是作為Proc對象的定義體保存起來.如果想要執行該代碼塊(Proc對象),需要顯式地調用它:
pr.call
==> Inside a Proc's block

基本的過程是:在調用Proc.new時為它提供一個代碼塊,該代碼塊成為Proc對象的定義體,然后,在調用該Proc對象的call方法時,代碼塊中的代碼被執行.其他的過程都只是在此過程上的添加或改變.

作為閉包的Proc對象
def talk
a = "Hello"
end

a = "GoodBye"
talk
puts a <---------輸出: GoodBye

標識符被賦值了兩次,但這兩個賦值彼此毫不相關.

def call_some_proc(pr)
a = "irrelevant 'a' in method scope"
puts a
pr.call
end
a = "'a' to be used in Proc block"
pr = Proc.new {puts a}
pr.call
call_some_proc(pr)

==>
'a' to be used in Proc block
irrelevant 'a' in method scope
'a' to be used in Proc block


像這樣帶著產生它的上下文信息的一段代碼,稱為閉包.

pr = Proc,new {|x| puts "yes is me, #{x}"}
pr.call(100)

pr = Proc.new{|*x| p x}
pr.call
pr.call(1)
pr.call(1,2)


(2)lambda生成匿名函數
lambda關鍵字可以用來生成匿名函數.需要做的只是給lambda提供一個代碼塊;于是該代碼塊成為一個匿名函數.然后可以給它發送"call"消息,函數就會執行.
>>lam = lambda {puts "A lambda!"}
==> #<Proc:0x02f4ae78@(irb):7> --->注意啦
>>lam.call
A lambda!
從上面的提示可以看到,lambda不是Lambda類的對象,它們是Proc類的對象:
>>lam.class
==> Proc
和所有的Proc對象一樣,lambda都是閉包;它們隨身攜帶了生成它們的局部的上下文環境.

(3)Proc和lambda之間的細微差別
lambda中的return從lambda返回,而Proc中的return從外圍方法返回.

def return_test
l = lambda { return }
l.call
puts "Still here"
p = Proc.new { return }
p.call
puts "You won't see this message!"

end

return_test
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值