Ruby語言
這一章讓我們來對Ruby語言做一個從頭到腳地審視。和前面的章節(jié)不同,在這里我們集中精力闡述事實,而不是揭示語言設計的細節(jié)問題。然后我們也盡量避免對內建的類和模塊的介紹,這些內容在第275頁開始有詳細地介紹。
如果這章的內容看上去很眼熟,那是因為它們本來就應該是我們熟悉的;我們在前面介紹性的章節(jié)中對它們都有描述。應該把這一章看成自包含的對核心Ruby語法描述的語言參考。
代碼編排(Source Layout)
Ruby程序是用7字節(jié)ACSII碼(7-bit ASCII)來表示的。
[Ruby也有完整的語言擴展來支持Kanji編碼,就是使用EUC, SJIS或UTF-8編碼系統(tǒng)。如果一段代碼使用了7字節(jié)ACSII碼以外的編碼格式,那么KCODE
選項就應該被適當?shù)卦O置,如137頁所示。]
Ruby是一種面向行的(line-oriented)程序設計語言。Ruby的表達式和聲明語句都是在一行的最后結束,除非一個語句很明顯是沒有結束的---比如一行的最后一個字符是一個操作符或者逗號。一個分號可以用來分割一行中的多個語句。你也可以在一行最后加一個反斜杠來使這一行延續(xù)到下一行。注釋以'#'開始,到物理行結束為止。在編譯(執(zhí)行)的時候,注釋將被忽略。
a?=?1
b?=?2;?c?=?3
d?=?4?+?5?+??????#不需要'\' ????6?+?7
e?=?8?+?9???\ ????+?10?????????#需要'\' |
在以=begin開始的一行和以=end結束的一行之間的語句會被編譯器忽略,不過它們可以作為內嵌文檔來使用(請參見第511頁開始的附錄A)。
Ruby只讀一遍源程序,所以你可以向Ruby編譯器的
stdin
發(fā)送程序代碼。
echo?'print?"Hello\n"'?|?ruby
|
在任何地方,只要編譯器遇到一行僅包含“
__END__
”的代碼,沒有前行和后隨的空格,它就把這一行當成程序的結束---后面的所有代碼都不會被編譯了。然而,后面的代碼可以用一個全局
IO
對象
DATA
讀入正在執(zhí)行的當前程序,這在217頁有描述。
BEGIN和END模塊
每個Ruby源文件都可以聲明一些代碼模塊用來在文件被載入前(
BEGIN
模塊)或者在程序執(zhí)行結束后(
END
模塊)運行。
BEGIN {
begin code
}
END { end code } |
一個程序可以有多個
BEGIN
和
END
模塊。
BEGIN
模塊以它們出現(xiàn)的順序執(zhí)行,
END
模塊以相反的順序執(zhí)行。
常規(guī)定界輸入(General Delimited Input)
還有另外一種用來表示字符串常量,數(shù)組,正則表達式和shell命令的格式,就是用常規(guī)定界語法。所有這些常量都是以一個百分號開始,后面跟一個用來指定常量類型的字符。對這些字符的描述請參見200頁的表18.1;常用的幾個字符在這章的后面會有描述。
常規(guī)定界輸入
類型 |
涵義 |
參見 |
%q |
單引號字符串 |
202 |
%Q , % |
雙引號字符串 |
202 |
%w |
常量數(shù)組 |
204 |
%r |
正則表達式 |
205 |
%x |
Shell命令 |
218 |
 |
|
在類型字符后面是一個分隔符,它可以是任何字符。如果分隔符是“
(
”,“
[
”,“
{
”,“
<
”中的一個,那么常量由分隔符到相應的后隨結束符(譯者注:比如左括號'('對右括號')')之間的字符組成,注意嵌套的分隔符。對于其他的分隔符,常量由兩個分隔符之間的字符組成。
%q/this?is?a?string/
%q-string-
%q(a?(nested)?string)
|
定界字符串可以跨越多行文本。
%q{def?fred(a)
?????a.each?{?|i|?puts?i?}
???end}
|
基本數(shù)據(jù)類型
Ruby的基本數(shù)據(jù)類型有數(shù)字,字符串,數(shù)組,哈希表(hashes),范圍(ranges),符號(symbols)和正則表達式。
整數(shù)和浮點數(shù)類型
Ruby的整數(shù)是類
Fixnum
或者
Bignum
的對象。
Fixnum
可以容納物理機器一個字長少一位大小的整數(shù)。當一個
Fixnum
超過它的范圍時,它會自動轉換成
Bignum
類型,而
Bignum
類型的范圍只能被物理內存所限制。如果一個
Bignum
上的操作使得它的最終值適合一個
Fixnum
保存,那么結果就會以一個
Fixnum
對象返回。
整數(shù)前面可以帶一個可選的符號標記,一個可選的進制指示符(
0
代表八進制,
0x
代表十六進制,
0b
代表二進制),然后跟一串相應進制的數(shù)字串。在數(shù)字串中的下劃線將被忽略。
你可以在一個ASCII字符前面加一個問號來取得它相應的整數(shù)值。Ctrl和Meta(譯者注:Meta就是Alt鍵)的鍵組合可以由?\C-
x, ?\M-
x, 和?\M-\C-
x來產生。一個字符
ch
的Ctrl版本是(就是Ctrl + ch組合)
ch&0x9f
,然后它的Meta版本是
ch?|?0x80
。你可以用字符序列
?\\
來取得反斜杠的整數(shù)值。
123456????????????????????#?Fixnum
123_456???????????????????#?Fixnum?(下劃線被忽略)
-543??????????????????????#?Negative?Fixnum
123_456_789_123_345_789???#?Bignum
0xaabb????????????????????#?十六進制
0377??????????????????????#?八進制
-0b1010???????????????????#?二進制?(負的)
0b001_001?????????????????#?二進制
?a????????????????????????#?character?code
?A????????????????????????#?upper?case
?\C-a?????????????????????#?control?a?=?A?-?0x40
?\C-A?????????????????????#?case?ignored?for?control?chars
?\M-a?????????????????????#?meta?sets?bit?7
?\M-\C-a??????????????????#?meta?and?control?a
|
一個帶有小數(shù)點的數(shù)字串(也可以帶指數(shù))被認為是
Float
對象,大小和物理機器上
double
類型一樣。你必須在小數(shù)點后面跟一個數(shù)字,因為像
1.e3
意味著去調用類
Fixnum
的方法
e3
。
12.34 |
|
12.34 |
-.1234e2 |
|
-12.34 |
1234e-2 |
|
12.34 |
字符串
Ruby提供了好幾種方法來產生字符串常量。每中方法都產生
String
對象。每種方法在字符串是如何定界和要產生多少替換上是不一樣的。
單引號字符串(
'
stuff'
和%q/
stuff/)進行最少限度的替換。兩種格式的表示方法都把“\\”轉換成一個反斜杠,然后把“\'”轉換成一個單引號。
'hello' |
|
hello |
'a?backslash?\'\\\'' |
|
a?backslash?'\' |
%q/simple?string/ |
|
simple?string |
%q(nesting?(really)?works) |
|
nesting?(really)?works |
%q?no_blanks_here?; |
|
no_blanks_here |
雙引號字符串("
stuff",%Q/
stuff/,和%/
stuff/)還會進行額外的替換,詳見203頁表18.2。
雙引號字符串中的替換
 |
\a |
Bell/alert (0x07) |
\nnn |
Octal nnn |
\b |
Backspace (0x08) |
\xnn |
Hex nn |
\e |
Escape (0x1b) |
\cx |
Control-x |
\f |
Formfeed (0x0c) |
\C-x |
Control-x |
\n |
Newline (0x0a) |
\M-x |
Meta-x |
\r |
Return (0x0d) |
\M-\C-x |
Meta-control-x |
\s |
Space (0x20) |
\x |
x |
\t |
Tab (0x09) |
#{expr} |
Value of expr |
\v |
Vertical tab (0x0b) |
 |
|
a??=?123 |
"\123mile" |
|
Smile |
"Say?\"Hello\"" |
|
Say?"Hello" |
%Q!"I?said?'nuts',"?I?said! |
|
"I?said?'nuts',"?I?said |
%Q{Try?#{a?+?1},?not?#{a?-?1}} |
|
Try?124,?not?122 |
%<Try?#{a?+?1},?not?#{a?-?1}> |
|
Try?124,?not?122 |
"Try?#{a?+?1},?not?#{a?-?1}" |
|
Try?124,?not?122 |
字符串可以跨越多個文本行,在這種情況下它們可以包含換行符。我們也可以使用
here documents來表達很長的字符串常量。每當Ruby遇到字符序列<<
標識符 或者 <<
括號字符串的時候,它就把后隨的所有輸入行變成一個字符串常量。它一直接收字符到字符串中,直到它遇到一行以前面的標識符或者
括號字符串開始的程序行。你可以在<< 后面跟一個負號,使得結束符可以向右邊縮進。如果一個括號字符串被用來作為結束符,那么引號規(guī)則就會應用到here document中;另外,雙引號規(guī)則也起作用。
a?=?123
print?<<HERE
Double?quoted?\
here?document.
Sum?=?#{a?+?1}
HERE
print?<<-'THERE' ????This?is?single?quoted. ????The?above?used?#{a?+?1} ????THERE |
產生結果:
Double?quoted?here?document.
Sum?=?124
????This?is?single?quoted.
????The?above?used?#{a?+?1}
|
相鄰的單引號和雙引號字符串會連接在一起成為一個
String
對象。
'Con'?"cat"?'en'?"ate" |
|
"Concatenate" |
字符串保存在8比特字節(jié)長的序列中
[為了在日本使用,jcode
庫支持一系列對EUC,SJIS,或者UTF-8編碼字符串的操作。不過底層的字符串還是以字節(jié)形式被訪問。],然后每個字節(jié)都保存一個256以內的8比特值,包括空值null和換行。203頁表18.2所示的替換規(guī)則允許不可打印字符可以便利并且可移植地嵌入到普通字符串中。
每一次一個字符串被用在一個賦值或者用做一個參數(shù)的時候,一個新的
String
對象會被創(chuàng)建。
for?i?in?1..3
??print?'hello'.id,?"?"
end
|
產生結果:
537767360?537767070?537767040
|
String
類的詳細資料請參見第363頁開始的文檔。
范圍(Ranges)
在一個條件表達式外面,表達式
expr..
expr和
expr...
expr會創(chuàng)建范圍對象(
Range
)。中間兩點的格式不包括兩邊的邊界值;中間有三點的格式還包括最后那個邊界值。要看
Range
類的詳細信息,請參見第359頁。第222頁有在條件語句中使用范圍的其他方法。
數(shù)組
類
Array
的對象由一系列在方括號中由逗號分隔的對象引用組成。最后一個逗號會被忽略。
arr?=?[?fred,?10,?3.14,?"This?is?a?string",?barney("pebbles"),?]
|
字符串數(shù)組可以由一個簡捷符號組成,
%w
,它可以把由逗號分隔的一個連續(xù)字符串中的子字符提取出來組成一個字符串數(shù)組??崭窨梢杂煞葱备苻D義。這是一種定界輸入的格式,請參見200--201頁。
arr?=?%w(?fred?wilma?barney?betty?great\?gazoo?) |
arr |
|
["fred",?"wilma",?"barney",?"betty",?"great?gazoo"] |
哈希值(Hashes)
一個Ruby的
Hash
對象是由一系列在花括號里面的鍵/值匹配對組成的。由逗號分隔鍵/值對,鍵和值之間由
=>
連接。最后一個逗號會被忽略。
colors?=?{?"red"???=>?0xf00,
???????????"green"?=>?0x0f0,
???????????"blue"??=>?0x00f
?????????}
|
在一個特定的哈希表中的鍵和值的類型不一定要一致。
哈希鍵值的要求
作為一個哈希鍵值的唯一要求是它必須響應消息
hash
,然后返回一個哈希值,這個哈希值不能改變。這意味著一些類(比如
Array
和
Hash
,像這種類型的)不能很好的適合哈希鍵值的要求,因為它們的值會隨著它們的內容而變化。
如果你保持了一個對象的外部引用,然后這個對象又被用來做為一個哈希鍵。那么你通過這個引用來改變這個對象然后改變哈希值,這個哈希鍵對應的哈希值將不會起作用。
因為字符串經(jīng)常被用來當作鍵值,然后字符串值又會經(jīng)常改變,Ruby對字符串鍵值做了特殊處理。當你把一個
String
對象當做哈希鍵時,哈希表會復制一個字符串,然后把這個字符串當作鍵值。后隨的所有對原來字符串的改變不會影響哈希表。
如果你寫了自己的類然后把它們的實例當作哈希鍵值,你必須確保哈希表的鍵值在創(chuàng)建以后不再改變或者在鍵值改變的時候記得調用
Hash#rehash
方法來重新索引哈希表。
符號對象(Symbols)
一個Ruby的符號對象是一個對象名的內部表示。你可以在對象名前面加一個冒號來產生相應的符號對象。一個特定的對象名總是產生相同的符號對象,不論對象名在程序中是如何被使用的。
其他編程語言稱這個替換過程為“interning”,然后把符號對象叫做“atoms”。
正則表達式
正則表達式是類型
Regexp
的對象。它們可以通過顯式地調用
Regexp.new
來創(chuàng)建,或者使用文字常量方式,/
pattern/和
%r{
pattern}
。
%r
創(chuàng)建方法是一種普通定界輸入(詳見200--201頁)。
/pattern/
/pattern/選項
%r{pattern}
%r{pattern}選項
Regexp.new( 'pattern' [, 選項
] )
|
正則式的選項
一個正則表達式可以包含一個或多個選項來修改默認的匹配規(guī)則。如果你使用文字常量來創(chuàng)建正則式,那么一個或多哥選項就緊跟在結束符后面。如果你使用
Regexp.new
方法,那么選項就是構造函數(shù)的第二個參數(shù)。
i |
忽略大小寫. 這個匹配將會忽略模式和字符串中的字符的大小寫。如果全局變量$= 被設置,那么匹配也會大小寫不敏感。 |
o |
替換一次。任何在正則式中的#{...} 替換都僅進行一次,就是第一次遇到它的時候。其他情況中,替換會在每次一個Regexp 對象產生的時候進行。 |
m |
多行模式。通常的,'.'匹配除了換行以外的任何字符。有了/m 選項以后,'.'匹配任何字符了。 |
x |
擴展模式。復雜的正則表達式會很難閱讀。'x'選項允許我們可以在模式中加入空格,換行和注釋來使它更容易被閱讀。 |
正則式的模式
-
規(guī)則字符
- 除了.,|, (, ), [, \, ^, {, +, $, *,和?,任何字符都匹配它自己。如果要匹配上面的字符,那么應該在它們前面加一個反斜杠。
-
^
- 匹配一行的開始
-
$
- 匹配一行的末尾
-
\A
- 匹配字符串的開始
-
\z
- 匹配字符串的末尾
-
\Z
- 匹配字符串的末尾,如果字符串以"\n"結束,那么它從"\n"前面開始匹配。
-
\b
, \B
- 相應匹配單詞邊界和非單詞的邊界
-
[
字符 ]
- 一個字符串類型匹配任何出現(xiàn)在方括號里面的單個字符。 字符
|, (, ), [, ^, $, *,
和?
,在其他地方有特殊含義,但是在方括號里面就失去了它們的特殊含義。序列 \
nnn, \x
nn, \c
x, \C-
x, \M-
x, and \M-\C-
x有如203頁表18.2所示的特殊含義。序列\d
, \D
, \s
, \S
, \w
,和\W
是一組字符串的縮寫,如59頁表5.1所示。序列c1-c2表示在c1和c2之間的所有字符(包括c1,c2)。字符]
或-
必須僅跟在左括號后面。一個(^)緊跟在左括號后使匹配反義---模式匹配任何不在方括號中出現(xiàn)的字符。
-
\d
, \s
, \w
- 分別匹配數(shù)字,空格和單詞字符(word character)。\D, \S, 和\W匹配不是數(shù)字,空格和單詞字符的字符。這些縮寫在59頁表5.1有詳細描述。
-
.
(句點)
- 出現(xiàn)在方括號外面,它代表除了換行以外的任何字符(如果
/m
選項被設置了,那么它也匹配換行符)。
-
re
*
-
匹配零次或者多次re的出現(xiàn)。
-
re
+
- 匹配一次或者多次re的出現(xiàn)。
-
re
{m,n}
- 匹配最少"m"次然后最多"n"次re的出現(xiàn)。
-
re
?
- 匹配零次或一次re的出現(xiàn)。
*
, +
, 和{m,n}
都是最大匹配的,加上一個問號使得它們進行最小匹配。
-
re1
|
re2
- 匹配re1或者re2,
|
的優(yōu)先級很低。
-
(...)
- 圓括號用來集合正則表達式。比如,模式
/abc+/
匹配一個含有一個'a', 一個'b'然后一個或多個'c'的字符串。/(abc)+/
就匹配一次或多次"abc"的出現(xiàn)。圓括號還用來收集模式匹配的結果。Ruby為每一個左圓括號保存括號中的部分匹配結果,直到相應的右括號為止。在同一個匹配中,\1
代表第一組匹配的結果,\2
代表第二組結果,依次類推。在匹配外面,特殊變量$1
, $2
等起到相同的作用。
替換作用
-
#{...}
- 表示一個字符串中的表達式的替換。默認情況,替換會在每次匹配成功時發(fā)生。當
/o
選項被設置時,它僅僅匹配一次。
-
\0, \1, \2, ... \9, \&, \`, \', \+
- 替換第n組匹配,或者整個,前面或后面,或者最高匹配的那一組。
語法擴展
和Perl和Python類試,Ruby的正則表達式提供了一些對傳統(tǒng)Unix正則表達式的擴展。這些擴展都寫在
(?/code>?and?)
里面。這些圓括號括著的擴展是組,但是它們不會產生后引用(backreferences):它們不會設置\1
和$1
等變量的值。
-
(?# 注釋)
- 在模式串中插入注釋。注釋在模式匹配的時候被忽略。
-
(?:re)
- 把re加入組,然而不產生后引用。這在當你希望創(chuàng)建一個組但是又不想讓它設置
$1
等值的時候特別有用。在下面的例子中,兩個模式都保存了一個包括月份,日子和年份的數(shù)據(jù),用冒號或空格分隔。第一種格式的在$2
和$4
中保存了數(shù)據(jù),但是第二種格式?jīng)]有保存內部數(shù)據(jù)。
date?=?"12/25/01" |
date?=~?%r{(\d+)(/|:)(\d+)(/|:)(\d+)} |
[$1,$2,$3,$4,$5] |
|
["12",?"/",?"25",?"/",?"01"] |
date?=~?%r{(\d+)(?:/|:)(\d+)(?:/|:)(\d+)} |
[$1,$2,$3] |
|
["12",?"25",?"01"] |
-
(?=re)
- 在此處匹配re,但是不要銷毀它(也可以愜意地叫做零距離回顧(``zero-width positive lookahead''))。它可以讓我們方便地引用前面的內容而不會影響
$&
。在這個例子中,scan
方法匹配后面跟一個句點的單詞,但是句點不包括在匹配結果里面。
str?=?"red,?white,?and?blue" |
str.scan(/[a-z]+(?=,)/) |
?/td>
|
["red",?"white"] |
-
(?!re)
- 看看在此處是否不匹配re。不要銷毀這個匹配(否定的零距離回顧)。比如,
/hot(?!dog)(\w+)/
匹配任何包含“hot”然后后面不跟“dog”的單詞,返回$1
中的最后一個單詞。
-
(?>re)
- 把一個獨立的正則式嵌入到第一個正則式中。這個表達式在當前匹配點被確定。如果它銷毀了一些字符,這些字符就不會被上級的正則式訪問到。因此這個結構是有后回溯機制的(backtracking),這可以是一個執(zhí)行效果的增強。比如,模式
/a.*b.*a/
的基本意思是匹配一個含有一個'a',后面跟數(shù)個'b',然后沒有后隨'a'的字符串。然而,這可以用嵌套的正則式/a(?>.*b).*a/
來避免。在這種格式中,內嵌的正則式消耗掉了所有字符串,直到有字符'b'的出現(xiàn)。當一個對后隨'a'的查找失敗以后,就沒有回溯的必要了,這個模式匹配迅速結束。
require?"benchmark"
include?Benchmark
str?=?"a"?+?("b"?*?5000)
bm(8)?do?|test|
??test.report("Normal:")?{?str?=~?/a.*b.*a/?}
??test.report("Nested:")?{?str?=~?/a(?>.*b).*a/?}
end
|
產生結果:
??????????????user?????system??????total????????real
Normal:???0.420000???0.000000???0.420000?(??0.414843)
Nested:???0.000000???0.000000???0.000000?(??0.001205)
|
-
(?imx)
- 打開"i","m"或"x"選項。如果用在一個組里面,那么效果就限制在組里面。
-
(?-imx)
- 關閉"i","m"或"x"選項。
-
(?imx:re)
- 打開re的"i","m"或"x"選項。
-
(?-imx:re)
- 關閉re的"i","m"或"x"選項。
標識名
Ruby的標識名用來指向常量,變量,方法,類和模塊。標識名的首字符用來幫助我們確定標識所指向內容的類型。一些標識名,就是210頁表18.3所示的都是保留字,不能用來當作變量,方法,類或模塊的名字。
保留字
 |
__FILE__ |
and |
def |
end |
in |
or |
self |
unless |
__LINE__ |
begin |
defined? |
ensure |
module |
redo |
super |
until |
BEGIN |
break |
do |
false |
next |
rescue |
then |
when |
END |
case |
else |
for |
nil |
retry |
true |
while |
alias |
class |
elsif |
if |
not |
return |
undef |
yield |
 |
|
在下面的描述中,小寫字母表示'a'到'z'的字母和'_',下劃線。大寫字母表示'A'到'Z'的字母,還有數(shù)字表示'0'到'9'的數(shù)字字符。標識符字符表示大小寫字母和數(shù)字的組合。
一個局部變量由一個小寫字母后面跟標識符組成。
fred??anObject??_x??three_two_one
|
類的實例變量由一個‘@
’開始,后面跟一個大寫或小寫字母,然后后面還可以有一些標識符字符。
一個類變量由兩個‘@@
’開始,后面跟一個大寫或小寫字母,然后后面還可以有一些標識符字符。
一個常量名由一個大寫字母開始,后面跟標識符字符。類名和模塊名是常量,所以也遵循常量的命名規(guī)則。常量名一般是由大寫字母組成,然后可以帶下劃線。
module?Math
??PI?=?3.1415926
end
class?BigBlob
|
全局變量,以及一些特殊的系統(tǒng)變量,由一個美圓符號'$
'開始,然后后面跟標識符字符。另外,還有一些有兩個字符組成的變量名,它們第二個字符是標點符號。這些預設的變量名在213頁有描述。最后,全局變量名也可以用"$-
"開頭,后面跟任意一個字符。
$params??$PROGRAM??$!??$_??$-a??$-.
|
關于方法的命名規(guī)則,在從第225頁的開始的章節(jié)有描述。
變量/方法的疑惑
每當Ruby在一個表達式中遇到一個比如像'a'這樣的字符,他必須確定這個'a'到底是一個局部變量的引用還是一個無參數(shù)的函數(shù)方法調用。為了確定這個,ruby用了一種啟發(fā)式(heuristic)的方法。當Ruby在讀取源代碼的時候,它記下了那些被賦值的標識符。它假定這些標識符是變量名。然后如果它在隨后遇到一個標識符可能是變量,也可能是方法名的時候,它就查看這個標識服是否在以前被賦過值。如果被賦過值,它就把標識符當成變量名;否則它就把標識符當成一個方法調用。作為一個比較詭異的例子,請參見以下的代碼片段,由Clemens Hintze遞交。
def?a
??print?"Function?'a'?called\n"
??99
end
for?i?in?1..2 ??if?i?==?2 ????print?"a=",?a,?"\n" ??else ????a?=?1 ????print?"a=",?a,?"\n" ??end end |
produces:
a=1
Function?'a'?called
a=99
|
在語法解析的時候,Ruby遇到第一個'a',因為此時'a'沒有被賦值,就認為它是一個方法調用。然后到第二個打印語句的時候,Ruby已經(jīng)遇到了一個賦值,所以此時它把'a'當成一個變量。
注意賦值語句不一定要被執(zhí)行---Ruby只要見到它就可以了。這個程序不會出現(xiàn)錯誤。
變量和常量
Ruby變量和常量都是指向對象的引用。變量自身并沒有內在的類型。一個變量的類型僅僅由它指向的對象的信息決定。 [我們說一個變量沒有類型,我們的意思就是任何給定的變量可以在不同時間指向許多不同的類型。]
一個Ruby的常量也是對一個對象的引用。常量在Ruby首次對它賦值時被創(chuàng)建(一般在一個類或模塊的定義中)。和一些通融性差的語言不同,允許我們修改變量的值,盡管這樣會得到一個警告信息。
MY_CONST?=?1
MY_CONST?=?2???#?generates?a?warning
|
產生結果:
prog.rb:2:?warning:?already?initialized?constant?MY_CONST
|
注意雖然常量不應該被修改,但是我們可以修改它指向的對象的內部狀態(tài)。
MY_CONST?=?"Tim" |
MY_CONST[0]?=?"J"???#修改常量的內部狀態(tài) |
MY_CONST |
|
"Jim" |
賦值潛在地給一個對象別名,給同一個對象不同的名字。
常量和變量的作用域
在一個類或模塊中定義的常量可以方便地在類或模塊任何地方訪問。在模塊或類外面,它們可以使用域作用符“::
”來訪問,在一個表達式前加一個“::
”可以返回類或模塊相應的對象。在任何類外面定義的常量,可以通過在它前面加"::
"訪問到。我們不能在方法中定義常量。
OUTER_CONST?=?99 |
class?Const |
??def?getConst |
????CONST |
??end |
??CONST?=?OUTER_CONST?+?1 |
end |
Const.new.getConst |
|
100 |
Const::CONST |
|
100 |
::OUTER_CONST |
|
99 |
全局變量在整個程序中都可以使用。每個指向特定全局對象名的引用都返回相同的對象。引用一個未初始化的全局變量返回一個
類變量在整個類或模塊體中都可以被使用。類變量在使用之前必須被初始化。一個類變量被這個類的所有對象所共有,然后只在類內部使用。
class?Song
??@@count?=?0
??def?initialize
????@@count?+=?1
??end
??def?Song.getCount
????@@count
??end
end
|
類變量屬于最內層嵌套類或模塊。最頂層的類變量是定義在Object
中的,然后就像全局變量一樣。如果接收者是一個類或者模塊,那么定義在單例類里面的類變量屬于接收者;否則,它們屬于接收者的類。
class?Holder
??@@var?=?99
??def?Holder.var=(val)
????@@var?=?val
??end
end
a?=?Holder.new def?a.var ??@@var end |
Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright ? 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).
Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.