Terry七月Ruby讀書筆記
Terrychu 2008-11-16
文檔名:D:/MyNotes/RubyRuby語言入門教程v1.0.doc
創建時間:2008年7月10日, 10:17:57
修改時間:2008年7月17日, 10:19:04
今年7月讀《Ruby語言入門教程v1.0》時的讀書筆記,靜靜地面對電腦,嘗試一種新的語言,是一種淡然的快樂。
***********************************************************
Page 3 概述
¨ 解釋執行:Python,Ruby,交互性很好; ¨ 編譯執行:Pascal, C,速度較快。 n 本地執行,如C,C++; n 虛擬機執行,如Java, C#。
¨ 動態語言,如JavaScript,Ruby; ¨ 靜態語言,如C++,Java。 |
語言 ¨ 語法 關鍵字 ¨ 語義 ¨ 語用
|
松本行弘(Matz) 1993
Ruby [`ru:bi](紅寶石)
Ruby 吸取了 perl 的正則表達式, python 的簡單性可讀性,smalltalk 的純面向對象語法和單繼承,LISP 的無窮嵌套的語法,Java的線程…
Page 14 上手
XP
Cmd
C:/Documents and Settings/Administrator>ruby -v ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32] |
第一種方式:ruby命令
C:/Documents and Settings/Administrator>ruby -e 'print "hello world"' hello world |
ruby 運行ruby;
-e 執行後面的ruby腳本程序;
print 打印顯示;
hello,world 要輸出的內容。
第二種方式:irb交互執行
C:/Documents and Settings/Administrator>irb irb(main):001:0> print "hello world" hello world=> nil irb(main):002:0> exit |
exit: 退出irb交互式環境
第三種方式:創建ruby腳本
C:/Documents and Settings/Administrator>copy con helloworld.rb print "hello world" print "3*7=",3*7 ^Z 已複製 1 個文件。
C:/Documents and Settings/Administrator>helloworld.rb hello world3*7=21 |
Page 17 IDE
¨ Eclipse + RDT(Ruby Development Tools)
¨ FreeRIDE+SciTE
1.在SciTE編輯Ruby代碼;
2.保存爲 .rb文件;
3.菜單欄,工具->運行或者F5;
Page 18 語法
1. 註釋
單行註釋 # 多行註釋 =begin =end
Ruby的內嵌文檔(Rdoc)註釋,用ri命令從源文件中產生文檔。
Rdoc內嵌在ruby代碼之中的,可以轉換爲html文檔。
ri命令,用來查看函數說明、類說明。函數說明、類說明應該放置在=begin和=end之中。注意:“=begin”一定要寫在行首,也就是說,這一行前六個字符是“=begin”,之前不允許有空格。
2. 分行
用分號;表示語句結束。
一行多個語句,用分號隔開,最後一個語句,分號可以省略,換行符表示一行結束。
語句太長,可以在行末用符號 / ,表示續行。
3. 分隔符
名稱 |
符號 |
用途 |
分號 |
; |
用來分隔一行中的多個語句 |
圓括號 |
( ) |
提高優先級;定義方法時容納參數列表 |
空格 |
|
分隔字符;在可省略()的地方,代替() |
逗號 |
, |
隔開多個參數 |
點 |
. |
將對象與它的方法隔開 |
緊連的兩個冒號 |
:: |
域作用符,將模塊(類)與它的常量隔開 |
4. 關鍵字
Ruby中的關鍵字如下:
模塊定義: |
module |
異常處理: |
rescue,ensure |
類定義: |
class |
對象引用: |
super,self |
方法定義: |
def,undef |
塊的起始: |
begin/end |
檢查類型: |
defined? |
嵌入模塊: |
BEGIN,END |
邏輯值和空值: |
true,false,nil |
文件相關: |
__FILE__,__LINE__ |
邏輯判斷: |
not,and,or |
方法返回: |
return |
條件語句: |
if,then,else,elsif,case,when,unless |
別名: |
alias |
循環語句: |
for,in,while,until,next,break,do,redo,retry,yield |
BEGIN模塊相當於C語言中的宏,END模塊用來作一些收尾工作。有了
require,include,應該取消BEGIN和END的語法定義。
5. 運算符
6. 標識名:
常量,變量,方法,類和模塊;
大小寫敏感;
標識名第一個字符表明這個名字的用法。
局部變量、方法參數和方法名稱 |
以小寫字母開頭或者下劃線開頭; |
類名、模塊名和常量 |
用大寫字母開頭。 |
全局變量 |
以美元符爲前綴$; |
實例變量 |
以@開頭; |
類變量 |
用@@開頭; |
詞首字母后面可以是字母、數字和下劃線的任意組合;
@後面不可以直接跟數字。
Ruby程序代碼用7位ACSII碼來表示,通過語言擴展來支持 EUC,SJIS或UTF-8等8位編碼系統。Ruby2.0版本將支持16位的Unicode編碼。
7. 類庫
可以直接使用:
i) 關鍵字;
ii) require或者include包含的類庫中的類、方法;
iii)從父類中繼承得到的方法。
puts |
每個參數後自動換行 |
|
不自動換行,換行用”/n” |
printf |
按格式輸出,不自動換行 |
gets |
從鍵盤或文件中讀入數據 |
C:/Documents and Settings/Administrator>ruby -e 'puts "hello","world"' hello world |
C:/Documents and Settings/Administrator>ruby -e 'printf "number:%f",3.2' number:3.200000 |
注意:printf的參數之間用逗號隔開。
C:/Documents and Settings/Administrator>ruby -e ' printf "number:%4.3f,string %s ",1.5,"hello world"' number:1.500,string hello world |
8. 數據類型
類型 |
分類 |
說明及示例 |
數字 |
整數型 |
0 八進制, 0x 十六進制,0b 二進制 |
浮點型 |
||
字符串 |
單引號 ‘’ |
|
雙引號 “” |
|
|
數組 |
從0開始,每個元素可以不同類型 |
例 [2.4,"thank you",[a,b,c],78] |
區間 |
1..5 |
1,2,3,4,5 |
1…5 |
1,2,3,4 |
|
正則表達式 |
|
|
9. 賦值運算
交換變量a,b的值:
a,b=b,a;
注意括號:
a = (b = 1 + 2) + 3 #a=6 ,b=3
逗號,從左往右運算,分別賦給a,b,c
x = 0 #x=0
a,b,c = x, (x+1), (x+2) #a=0 ,b=1,c=2
10. 條件運算
== |
等於 |
!= |
不等於 |
eql? |
比較兩個對象的值、類型是否相等 |
equal? |
比較兩個對象在內存中地址是否相同 |
< |
小於 |
> |
大於 |
<= |
小於等於 |
>= |
大於等於 |
=~ |
匹配正則表達式 |
!~ |
斷言不匹配正則表達式 |
=== |
右邊的對象在左邊區間內 puts(0..9)===3.14 #true puts('a'..'f')==='c' # true |
<=> |
比較兩個對象大小,大於1,等於0,小於-1. |
Ruby裏,nil和false爲假,其它都爲真。
11. 判斷語句
|
if then end |
( ) if |
|
|
if elsif else end |
|
unless
|
if not
|
|
|
case when when else end |
12. 循環語句
單行while |
(語句1;語句2;語句…)while條件 |
多行while |
while 條件 語句,語句 end |
until直到 |
until 跳出循環條件 語句 until 條件=while not (條件) |
for…in循環 |
for 變量 in 對象 語句1; 語句2 ; 語句… end |
break,next&redo&retry
在循環體內,如果遇到:
break |
跳出當層循環; |
next |
忽略本次循環的剩餘部分,開始下一次的循環; |
redo |
重新開始循環,還是從這一次開始; |
retry |
重頭開始這個循環體。 |
times , upto , downto , each ,step
語句 |
運行結果 |
3.times { print "Hi!" } |
#Hi!Hi!Hi! |
1.upto(9) {|i| print i if i<7 } |
#123456 |
9.downto(1){|i| print i if i<7 } |
#654321 |
(1..9).each {|i| print i if i<7} |
#123456 |
0.step(11,3) {|i| print i } |
#0369 |
C:/Documents and Settings/Administrator>irb irb(main):001:0> 1.upto(9){|i| print i if i<7} 123456=> 1 irb(main):002:0> 9.downto(1){|i|print i if i<7} 654321=> 9 irb(main):003:0> (1..9).each {|i| print i if i<7} 123456=> 1..9 irb(main):004:0> 0.step(11,3) {|i| print i} 0369=> 0 |
13. 異常
Java
try…catch…finally…throw
Ruby
begin/end…rescue…ensure…raise
retry可以用在rescue中。可以只用rescue或ensure,兩者都使用時,rescue必須在ensure前。
14. 線程
Page 40
面向對象
2008/7/13
1. 消息機制:對象通過消息影響對象,對象即類的實例。誰,將被影響?
2. Object:東西,物體,客體。
3. Class:種類,等級,階級;
4 動態語言:人們可以決定代碼世界中一類事物的屬性、方法,當然可以修改代碼世界中一類事物的屬性、方法,而且可以委託其它的類來修改,甚至刪除。這是動態語言超越靜態語言之處。由於代碼是一直運行着,與其它代碼一直交互着,修改、刪除應該慎重,避免產生副作用。
5 封裝
注意:
類名首字母要大寫;
實例變量用@開頭;
方法名或者參數名用小寫字母或者下劃線開頭。
6 initialize是初始化方法
p2.motherland="ABC" #以賦值,因爲有對應的setter方法。
setter: |
getter: |
attr_writer:motherland相當於 |
attr_reader:motherland相當於 |
def motherland=(value) return @motherland=value end |
def motherland return @motherland end |
attr_accessor :motherland
相當於 attr_reader:motherland; attr_writer :motherland
7.繼承
class 子類<父類
子類繼承父類:
重寫方法;
添加方法;
增強父類方法(super)。
Ruby語言已經定義了一個類Object,如果你在定義新類的時候,沒有指明新類的父類,那麼,Ruby解釋器認爲,新類的父類是 Object 類。類Object 含有new方法、initialize 方法…只要你不重寫這些方法,你就自然在使用類Object 的方法。
你寫一個類的時候,是在創造一類事物的藍圖;當你new的時候,一個實例就按照藍圖生成了。
Ruby沒有析構函數,使用垃圾收集器自動回收實例佔用的資源。
8.多態
父類子類的行爲差異,不同子類的行爲差異,就是多態
Ruby語言,只有重寫(override),沒有其它語言具有的嚴格意義上的重載(overload)。Ruby語言有自己的單例方法,還有模塊插入(Mix-in)。
插曲
http://liubin.itpub.net/post/325/15623
覆蓋 override:
Overriding 也許叫做overwriting更合適,
OVERLOAD覆蓋是指在子類(c++中的派生類) 中重新定義父類的函數,其函數名、參數列、返回值類型必須同父類中的相對應被覆蓋的函數嚴格一致,覆蓋函數和被覆蓋函數只有函數體(花括號中的部分)不同,當派生類對象調用子類中該同名函數時會自動調用子類中的覆蓋版本,而不是父類中的被覆蓋函數版本。
重載(overload):
在同一個類中,出現多個同名的方法的現象就是Overload重載事發生在同一個類中,不同方法之間的現象。
在c++或者java中,方法一般爲
返回類型 方法名(參數1,參數2)
判斷2個方法是不是overload,主要指方法名一樣,參數不一樣,參數不一樣指的是參數的個數,相同位置的參數的類型是否一樣,而與參數(型參)的名稱無關(參數類型/個數/順序,不同),與返回類型也無關。程序會根據不同的參數列來確定需要調用的函數比如c++或者java中,這都是overload ruby中,不存在這樣的overload
多態(polymorphism)
至於多態,我還沒有見過一個看一眼就能明白的定義。
有的說是允許將子類類型的指針賦值給父類類型的指針,當然java中沒有指針的概念。
多態有時候也被稱爲動態綁定或者晚綁定或運行時綁定,意思是編譯的時候不必關心,運行的時候才決定調用哪個對象的哪個方法。
我覺得多態的用途之一就是在父類提供一個接口(服務),然後調用的時候用的卻是子類的具體實現。
page 49
Ruby前前後後
1.動態語言
編程語言將向動態迴歸;
命令式語言和函數式語言將融合。
Ruby在語法層次實現了冗餘。
Ruby語言的冗餘性、缺陷性和動態性正是現實世界的真實寫照。
page51
2.動態變量類型
命令式語言 |
將操作數演化成現在我們熟悉的變量,將操作碼演化成方法(或叫函數),對變量執行各種操作。 |
面向對象編程又將基本變量和方法封裝在一起,成爲一個更復雜的變量——對象。但是,在一個類中仍然區分基本變量和方法。 |
|
函數式語言 |
一開始的函數式語言不區分變量和方法,一切都是表(list),表就是能夠不斷分解成單個元素的數學符號。表可以是變量,可以是方法。 |
後來的有些函數式語言,吸取了命令式語言的語法,也區分變量和方法。 |
Ruby: 命令式語言,融合了函數式語言的語法,變量和方法區分得不很明顯。
變量名,變量值,變量類型,變量的作用域;“變量名,變量值”,必要的。
動態類型語言:由編譯內核(或解釋內核)在運行時刻來判斷變量類型的語言。
弱類型語言:弱化了類型的概念,變量在運行中能夠隨時代表不同的事物,而不管事物是什麼類型。
Ruby語言有基本類型。
純粹的函數式語言中沒有變量作用域的概念。
Ruby中有變量作用域概念,如變量名前綴字符。
實際應用中,有時會比較複雜,在使用閉包時會顯現出來。
Ruby語言中,一切都是對象,變量不是對象,變量只是引用某個對象的時候的一個代號。
Ruby是動態類型語言,不用給任何變量指定數據類型,解釋器會在你第一次賦值給變量時,在內部將數據類型記錄下來。
Ruby語言中,一個變量被賦予了某個數據類型的值,在程序中你可以隨時再賦予這個變量其它數據類型的值。
Ruby 是在運行中檢測語法,只要與語法定義不矛盾,就能通過。
Ruby 的動態類型特點是一把雙刃劍,
死盯住變量的命名。用一些有意義的名字,不必太長,但是應該少用單字符,除非是循環指針變量。在一個項目組中,程序員是要彼此相互溝通合作的。
3.改變藍圖——類
Ruby是動態語言,你可以改變Ruby程序的結構,功能。
在Ruby程序運行中,方法、屬性可以被加入或去除,新的類或對象可以被建立,新的模塊可以出現。
除了修改方法,添加方法,還可以除去方法。
Ruby是動態語言:靈活,強大,初學者容易犯錯誤;
4.編碼建議
(1) 命名
常量 |
大寫,下劃線分隔 |
MAX |
類名/模塊名 |
大寫字母開頭 |
MyClass |
方法名 |
小寫,下劃線分隔 |
is_prime? |
變量/參數名 |
小寫字母開頭單詞組合 |
currentValue |
注意:
類名、模塊名、變量名、參數名最好使用“名詞”或者“形容詞+名詞”。
方法名最好使用“動詞”或者“動詞+名詞”。例如:aStudent.talk。
在Ruby裏,有時將“!”和“?”附於某些方法名後面。驚歎號“!”暗示這個方法具有破壞性,有可能會改變傳入的參數。問號“?”表示這個方法是一個布爾方法,只會返回true或false。
(2) 空格
關鍵字之後要留空格。
逗號“,”、分號“;”之後要留空格。
“,”、“;”向前緊跟,緊跟處不留空格。
賦值操作符、比較操作符、算術操作符、邏輯操作符,如“=”、“+=”“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”等二元操作符的前後應當加空格。
一元操作符如“!”、“~”等之後不加空格。
象“[]”、“.”、“::”這類操作符前後不加空格。
函數名之後不要留空格,緊跟左圓括號“(”,以與關鍵字區別。左圓括號“(”向後緊跟,右圓括號“)”向前緊跟,緊跟處不留空格。
(3) 圓括號
Ruby中圓括號常常被省略
優先規則會自動確定哪個參數被哪個方法使用。
建議除了極簡單的情況,還是使用圓括號爲好。
圓括號還可以把幾個語句約束成一個語句集合。
(4) return
在定義方法的時候,在最後一行可以顯式地return某個值或幾個值,但不是必須的。
Ruby方法的最後一行語句如果是表達式,表達式的值會被自動返回;最後一行語句如果不是表達式,就什麼也不返回。
return不僅僅用在方法的最後一行。使用break能夠跳出本層循環,如果要從多重循環體中跳出,可以使用return,結束這個方法;return還能夠從方法的某個執行點立即退出,而不理會方法的其餘代碼。
(5) 註釋
註釋表明了一段代碼塊的功能、意圖或是代碼塊的解釋,應該簡潔明瞭,錯誤的註釋不如沒有註釋。一般地,註釋的位置應與被描述的代碼相鄰,可以放在代碼的上方或右方,不要放在代碼的下方。
page 61
面向對象
1. 重載&重寫
多態性:重寫/覆蓋/覆寫(override) 重載(overload)
重載(overload) |
重寫(override) |
一個類中,方法名相同、參數列表不同的幾個方法,調用時根據不同的參數調用不同的方法。方法重載與返回類型無關。 |
子類有一個方法,方法名、參數列表、返回類型與父類的某個方法完全一致。調用時會調用子類的方法,而屏蔽掉父類的同名方法。需要注意的是,子類覆寫的方法,其可訪問性一定要強於或等同於,父類被覆寫的同名方法。 |
重載不僅僅是發生在子類和父類之間,大多數時候,發生在同一個類中。 |
覆寫發生在子類和父類之間,當然也可以是子類和父類的父類之間。 |
成員函數被重載的特徵: URL:http://blog.csdn.net/zgbsoap/archive/2005/12/30/566120.aspx
(1)相同的範圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;
(4)virtual 關鍵字可有可無。
覆蓋是指派生類函數覆蓋基類函數,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函數名字相同;
(3)參數相同;
(4)基類函數必須有virtual關鍵字。
Ruby語言,只有重寫,沒有其它語言具有的嚴格意義上的重載。
分析:重載,參數不同,參數列表對應位置參數類型不同。而ruby支持缺省參數、可變參數,因此,參數不同不會發生重載。所以,ruby沒有嚴格意義上的重載。
父類和子類中的同名方法,子類重寫父類。子類對象執行子類中的方法。
在同一個類中寫兩個同名方法,總是執行寫在後面的方法。
ruby支持缺省參數,和C++相同。
在 Ruby中,我們說覆寫是指重寫,我們說重載也是指重寫。
Ruby是動態語言,可以隨時改變類的屬性、方法,所以覆寫和重載的重要性就降低了。
2. 增強父類方法
如果我們只是想增強父類的方法,而不是完全地替代它,就可以用關鍵字super指明。
在子類定義和父類同名的函數時,加入super關鍵字。
3. 變量
(1) 穩定性
constant :Unchanging in nature, value, or extent; invariable.穩定的,不變的。
常變量(常量)。常量名用大寫字母開頭。
變量:作用域,可以改變值。
Ruby中的常量,可以在類和模塊中定義,不能在方法中定義。
如果在外部訪問類或模塊中的常量,要使用域作用符::。
(2) 作用域
全局變量——作用域程序任何位置,全局變量用$開頭。
局部變量——作用域程序某個單元,用小寫字母開頭。
全局變量和實例變量如果沒有初始化,其默認值爲 nil 。
Ruby中的局部變量,可以是存在於類、方法、模塊、循環、過程對象中。
(3) 共享性
實例變量——只能被某個實例對象使用的變量,變量名用@開頭;
類變量——能被某個類的所有實例對象共享的變量,變量名用@@開頭。
類變量在使用前必須要初始化。
(4) 類方法
類方法——不依賴於任何特定實例對象的方法。
類方法與實例方法的定義方式不同,定義類方法要在方法名前加上類名和點號“.”。
調用一個類方法,與定義類方法一樣,要在方法名前加上類名和點號“.”。
類方法提供了一個途徑,在類的外部訪問類變量,無需通過類的實例方法。
對象是類的實例,說明類是對於對象的一個抽象,那麼,如果把類繼續抽象,把類看做實例,那它會是誰的實例? ——元類! 元數據,描述數據的數據。 |
疑問:類方法可否操作實例變量,而不僅僅是類變量?
4. 單例方法
Ruby如何反映相同的類,不同實例,之間的不同的行爲特徵?
(1)單例方法:在Ruby裏,可以給具體的實例對象添加實例方法,這個方法只屬於這個實例對象,我們把這樣的方法稱之爲單例方法,單例方法也叫作單件方法。
(2)定義單例方法:
首先要生成一個實例對象,
其次,要在方法名前加上對象名和一個點號“.”。
(3)實例方法,屬於類的每個實例對象。單例方法只出現在單個實例對象中。用單例方法可以極大地豐富多態性在Ruby中的表現力。
Ruby對於類和對象的擴展,就像數學中的多維,原來只是類和對象兩個層次,這裏,看成任意的層次,只不過,類和對象是其中的兩個不同的層次。所以,有了類的類——類的進一步抽象,有了單例方法,在對象這個層面上設計方法。
5. 訪問控制
在Ruby裏,要讀取或是改變對象的屬性,唯一的途徑是調用對象的方法。
控制了對方法的訪問,也就控制了對對象屬性的訪問。
控制對方法的訪問,有三種方式:
訪問控制 |
意義 |
public |
可以被任何實例對象調用,不存在訪問控制; |
protected |
可以被定義它的類和其子類訪問, 可以在類中或子類中指定給實例對象; |
private |
可以被定義它的類和其子類訪問, 不能被實例對象調用。 |
方法默認都是公有的(initialize方法除外,它永遠是私有的)。
public方法 |
可以被定義它的類和其子類訪問, 可以被類和子類的實例對象調用; |
protected方法 |
可以被定義它的類和其子類訪問, 不能被類和子類的實例對象直接調用, 但是可以在類和子類中指定給實例對象; |
private方法 |
可以被定義它的類和其子類訪問, 私有方法不能指定對象。 |
Ruby語言的訪問控制是動態的,是在程序運行時刻確立的。
你可以根據自己的需要,在程序的不同位置,改變某個方法的訪問控制級別,讓你的程序更加富於變化。
page 79
模塊化程序設計
1. 模塊
在程序中,相關的、不相關的代碼的組合,叫作模塊。一般情況下,我們總是把功能相關的代碼放在一個模塊裏。
把功能相關的程序代碼放在一個模塊裏,體現了模塊的第一個作用:可以被其它程序代碼重複使用。
Ruby標準包裏的 Math 模塊提供了許多方法
模塊名.方法名(參數) |
Math 模塊還提供了兩個常量,圓周率π 和自然對數底 e,
模塊名::常量名 |
定義模塊用 module...end 。模塊與類非常相似,但是:
A) 模塊不可以有實例對象;
B) 模塊不可以有子類。
2. 命名空間
模塊的第二個作用:提供了一個命名空間(namespace),防止命名衝突。
include 模塊名
定義一個模塊方法,在方法名前加上模塊名和一個點號“.”。
調用一個模塊方法,與定義模塊方法一樣,要在方法名前加上模塊名和一個點號“.”。模塊方法提供了一個途徑,在模塊的外部訪問模塊內部方法,無須 include模塊。定義模塊常量不需要如此。
3. 糅和(Mix-in)與多重繼承
柔和/混合插入/Mix-in
Ruby是單繼承,通過Mix-in模塊,實現多重繼承的優點。
模塊的第三個作用:實現了類似多重繼承的功能。
通過“<父類名”,一個子類可以得到父類的屬性和方法;
通過“include模塊名”,一個子類可以得到某個模塊的常量和方法。
類不能被include。
include方法爲一個類的所有對象包含某個模塊;
extend方法爲一個類的某個對象包含某個模塊(聯繫單例方法)。
4. require和load
require方法包含另一個文件,另一個文件名需要是一個字符串。
load方法與require方法相對應,也用來包含另一個文件。
require包含文件,只加載一次,遇到同一文件時自動忽略;不同路徑下的同名文件會多次加載。
load包含文件,加載多次,即使是相同路徑下同一文件。
總結一下:
require,load |
包含文件 |
include,extend |
包含模塊 |
require |
加載文件一次 |
加載文件時可以不加後綴名 |
一般情況下用於加載庫文件 |
load |
加載文件多次 |
加載文件時必須加後綴名 |
用於加載配置文件 |
利用load多次加載文件的特性,可以用來實現程序的無縫升級和系統的熱部署。程序功能改變了,你只需要重新load一次,其它代碼與它再次交互的時候,這個程序實際上已經不是原來的程序了。
page 88
複雜數據類型
1. 數組
(1) 建立數組
¨ array_1=[]
¨ array_2=Array.new
¨ array_3=['3 ','4 ','5 ']
(2) 訪問元素
arr=[3,4,5,6,7,8,9]
Ruby以整數作爲下標,訪問數組元素通過數組下標,數組下標稱作數組索引比較好一些。
數組的索引從0開始(arr[0]),一直到數組的長度減去1,如:arr[arr.length-1]或arr[arr.size-1]);
負數表示從數組末尾開始的索引,如:arr[-1]。
用一對數字索引數組,第一個數字表示起始位置,第二數字表示從起始位置開始的元素數目。如:arr[2..4],arr[-3,2]。
arr.first,arr.last分別代表第一個和最後一個元素。
(3) 增刪元素
Ruby的數組大小是動態的,你能夠隨時增加、刪除數組元素。
print arr.join(", "),"/n" 意思是:將數組 arr轉換成字符串輸出,用", "隔開每個
元素,並且換行。
arr=[3,4,5]
print arr #輸出:345
print arr.join(", ") #輸出:3,4,5
(4) 數組運算
arr1=["abc",1,2,"de"]
arr2=[2,3,4,7,6,5]
運算 |
運算表達式 |
輸出結果 |
加 |
print arr1+arr2 |
abc12de234765 |
減 |
print arr2-arr1 |
34765 |
乘 |
print arr1*2 |
abc12deabc12de |
並 |
print arr1|arr2 |
abc12de34765 |
交 |
print arr1&arr2 |
2 |
排序 |
print arr2.sort |
234567 |
倒置 |
print arr1.reverse |
de21abc |
2. 字符串
(1) 生成一個字符串
字符串是 String 類的對象,一般使用字符串值來創建。
%q用來生成單引號字符串;
%Q用來生成雙引號字符串。
%q或者%Q後面跟着的是分隔符,可以是配對的!!;//;<>;();[];{};等等。
字符串文檔,從<<和文檔結束符的下一行開始,直至一個放置在行首的文檔結束符結束。文檔結束符自己指定,結束符本身不屬於字符串。
注意:文檔結束符後面不能跟有空格。
一個數組可以用join方法轉換成字符串,join()內的參數也是一個字符串,用來分隔數組的每個元素,例如:arr.join(",")。
(2) 字符串操作
字符串既然是String類的對象,String類的方法你都可以使用在字符串變量上。
(3) 字符串轉義
雙引號括起來的字符串會有轉義,例如:“/n”表示換行。
單引號括起來的字符串不會轉義,有一個例外:單引號字符串裏的單引號,需要轉義。
(4) 字符串內嵌表達式
在雙引號字符串中,不僅可以使用轉義符,而且可以在#{ }之中放入Ruby表達式,使用字符串時,這些表達式的值被計算並放入字符串。
字符串內嵌表達式,使得你能夠更加靈活地組織代碼,表現出更強、更多的動態特性。
3. 代碼塊
可以用大括號{ }將代碼組織成塊,也可以用 do…end 將代碼組織成塊。大括號{ }的優先級高於 do…end。代碼塊,簡稱塊。
yield [ji:ld] 產生,輸出……
注意:{}或者do…end之間的是塊。
#E8.4-1.rb def one_block yield yield yield end one_block { puts "This is a block." } 代碼塊
把塊作爲參數,帶入到def定義中的yield處即可。
調用一次塊要用關鍵字yield。每一次yield,塊就被調用一次。
yield還可以帶參數調用塊,yield後面是實參,塊定義處是形參。
一個塊可以接收yield傳來的參數,還可以將結果返回給調用它的方法。
如果我們還沒有決定在塊裏寫什麼代碼,或者塊裏的代碼會隨着不同的情形而變化,那麼就看出代碼塊的靈活性了。
先寫出方法的大致框架,調用方法的時候才告訴方法要作什麼。
4. 迭代器
迭代器是一個與代碼塊有關聯的方法。
(1..9).each {|i| print i if i<7}
迭代器 each 是數組類的一個方法;大括號{ }裏的代碼是代碼塊。
class Array def one_by_one for i in 0...size yield(self[i] ) end puts end end arr = [1,3,5,7,9] arr.one_by_one {|k| print k , ", "} # 1, 3, 5, 7, 9, arr.one_by_one {|h| print h*h, ", "} # 1, 9, 25, 49, 81,
5. 閉包
代碼塊是一段代碼,相當於一個匿名方法,被調用它的方法所調用。
如果我們不僅僅想調用代碼塊,還想把代碼塊作爲參數傳遞給其它方法,就要使用閉包。
閉包也是一段代碼,一個代碼塊,而且能夠共享其它方法的局部變量。
閉包既然是一段代碼,也就有自己的狀態,屬性,作用範圍,也就是一個可以通過變量引用的對象,我們稱之爲過程對象。
一個過程對象用 proc 創建,用 call 方法來調用。
¨ 閉包作爲參數傳遞給其它方法
以下兩個程序相同
程序1 |
程序2 |
def method(pr) puts pr.call(7) end
oneProc=proc{|k| k *=3} method(oneProc) |
oneProc=proc{|k| k *=3}
puts oneProc.call(7) |
#過程對象oneProc作爲一個參數,傳遞給method; |
|
¨ 閉包共享其它方法局部變量
def method(n) return proc{|i| n +=i } end
oneProc=method(3) puts oneProc.call(9) #12 puts oneProc.call(5) #17 |
方法method返回一個Proc對象,這個對象引用了函數的參數n。即使參數n在閉包被調用時已經不在自己的作用域裏,這個閉包還是可以訪問參數n,並且和方法method共同擁有變量n。開始時方法method的變量n是3;oneProc.call(9)的時候,oneProc 更新了變量n,把n=12 傳回給方法method;oneProc.call(5)的時候,oneProc取出方法 method 的變量 n=12,更新爲n=17,傳回給方法method的同時,也把n=17作爲自己的返回值輸出。 |
正則表達式
正則表達式(regular expression)描述了一種字符串匹配的模式,可以用來檢查一個串是否含有某種子串;將匹配的子串做替換;或者從某個串中取出符合某個條件的子串;等等。
Ruby 中,可以使用構造器顯式地創建一個正則表達式,也可以使用字面值形式 /正則模式/ 來創建一個正則表達式。
=~ |
匹配一個正則表達式:用來比較是否符合一個正則表達式,返回模式在字符串中被匹配到的位置,否則返回nil。 |
!~ |
不匹配一個正則表達式:用來斷言不符合一個正則表達式,返回true,flase。 |
一些字符或字符組合在正則表達式中有特殊的意義。
特別字符 |
描述 |
( ) |
標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字符,請使用 /( 和 /)。 |
[] |
範圍描述符 (比如,[a - z] 表示在 a 到 z 範圍內的一個字母),要匹配 [,請使用/[。 |
{} |
標記限定符表達式。要匹配{,請使用 /{。 |
/ |
將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, 'n'匹配字符 'n'。'/n'匹配換行符。序列 '//'匹配 "/",而 '/('則匹配 "("。 |
| |
指明兩項之間的一個選擇。要匹配 |,請使用 /|。 |
. |
匹配除換行符 /n之外的任何單字符。要匹配 .,請使用 /。 |
非打印字符
非打印字符 |
描述 |
/f |
匹配一個換頁符。等價於/x0c。 |
/n |
匹配一個換行符。等價於/x0a。 |
/r |
匹配一個回車符。等價於/x0d。 |
/s |
匹配任何空白字符,包括空格、製表符、換頁符等等。等價於[/f/n/r/t/v]。 |
/S |
匹配任何非空白字符。等價於[^/f/n/r/t/v]。 |
/t |
匹配一個製表符。等價於/x09。 |
/w |
匹配包括下劃線的任何單詞字符。等價於'[A-Za-z0-9_]'字母或數字;相當於[0-9A-Za-z] |
/W |
匹配任何非單詞字符。等價於'[^A-Za-z0-9_]'非字母,數字 |
/d |
匹配一個數字字符。等價於[0-9]。[0-9]數字;相當於[0-9] |
/D |
匹配一個非數字字符。等價於[^0-9]。非數字字符 |
/b |
退格符(0x08)(僅在範圍描述符內部時) |
限定符
限定符用來指定正則表達式的一個給定組件必須要出現多少次才能滿足匹配。
* 和 + 限定符都是貪婪的,因爲它們會儘可能多的匹配文字,只有在它們的後面加上一個 ? 就可以實現非貪婪或最小匹配。
限定符 |
描述 |
* |
前面元素出現0或多次。* 等價於{0,}。 例如,zo*能匹配 "z"以及 "zoo"。 要匹配 * 字符,請使用 /*。 |
+ |
前面元素出現1或多次。+ 等價於{1,}。 例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。 要匹配 + 字符,請使用 /+。 |
? |
前面元素最多出現1次;相當於 {0,1}。 例如,”do(es)?” 可以匹配 “do” 或 “does” 中的"do" 。 要匹配 ? 字符,請使用 /?。 |
{n} |
n 是一個非負整數。匹配確定的 n 次。 例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food"中的兩個o。 |
{n,} |
n 是一個非負整數。至少匹配n 次。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。 例如,'o{2,}' 不能匹配 "Bob"中的 'o',但能匹配 "foooood"中的所有 o。 |
{n,m} |
m 和 n 均爲非負整數,其中n <= m。前面元素最少出現n 次,最多出現 m次。 'o{0,1}'等價於 'o?'。請注意在逗號和兩個數之間不能有空格。 例如,"o{1,3}"將匹配 "fooooood"中的前三個 o。 |
定位符
用來描述字符串或單詞的邊界,^和$分別指字符串的開始與結束,/b描述單詞的前或後邊界,/B表示非單詞邊界。不能對定位符使用限定符。
定位符 |
描述 |
^ |
匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配^字符本身,請使用/^。 |
$ |
匹配輸入字符串的結尾位置。如果設置了RegExp對象的Multiline屬性,則$也匹配'/n'或'/r'。要匹配$字符本身,請使用/$。 |
/b |
匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,'er/b'可以匹配"never"中的'er',但不能匹配"verb"中的'er'。 |
/B |
匹配非單詞邊界。'er/B'能匹配"verb"中的'er',但不能匹配"never"中的'er' |
各種操作符的運算優先級
相同優先級的從左到右進行運算,不同優先級的運算先高後低。各種操作符的優先級從高到低如下:
優先級 |
操作符 |
描述 |
高 |
/ |
轉義符 |
|
(),[] |
圓括號和方括號 |
|
*,+,?,{n},{n,},{n,m} |
限定符 |
|
^,$, |
位置和順序 |
低 |
| |
“或”操作 |
元編程
元編程:編寫能夠生成程序的程序。
聽起來很有趣!
Ruby語言強大的動態特徵,賦予了我們靈活地進行元編程的能力。
Terry的博客主站 ,以後的文章將寫在這裏,歡迎光臨 :www.helemi.net