本文介紹 Ruby 基本的數(shù)據(jù)類型,主要參考《Ruby編程語言》。
Ruby支持的數(shù)據(jù)類型包括基本的Number、String、Ranges、Symbols,以及true、false和nil這幾個特殊值,同時還有兩種重要的數(shù)據(jù)結(jié)構(gòu)——Array和Hash。
數(shù)字
Ruby 中所有的數(shù)字都是 Numberic 類的實例,所有整數(shù)都是 Integer 的實例。Fixnum 和 Bignum之間的轉(zhuǎn)換是透明的。Ruby 利用 Float 來近似的表示實數(shù),該類會利用本地平臺的浮點數(shù)表示形式。各個類之間的關(guān)系如下,圖片來源于《Ruby編程語言》。

補充以下幾點,以免忘記。
- 除法、取模與負數(shù)。
當一個操作數(shù)為負數(shù)時,Ruby的整數(shù)除法和取模操作不同于C/C++和Java。例如,-7/3,可以用浮點表示為-2.33。Ruby采取的是向負無窮大圓整,于是整除結(jié)果為-3,但是C的做法是向0圓整,所得結(jié)果為-2??梢缘弥?,在Ruby中,-a/b和a/-b相等,但是卻不一定等于-(a/b)。
而在Ruby取模操作中,-7/3的結(jié)果為2,而C中結(jié)果卻是為-1。在Ruby中,結(jié)果符號始終和第二個數(shù)操作符號保持一致。在C中結(jié)果符號始終和第一個操作數(shù)保持一致。另外Ruby還定義了remainder方法,在結(jié)果的量和符號方面都和C保持一致。
- 實數(shù)的表示
和大多數(shù)硬件和計算機語言一樣,Ruby的Float類為了高效的使用硬件,大多數(shù)浮點數(shù)都表示成二進制的,可以精確的表示1/2 和1/4這類分數(shù),但是連0.1都無法用精確的表達。所以下面一個簡單的表達式或許并不是表現(xiàn)的想你想象的那樣。
0.4 - 0.3 == 0.1
Ruby在標準庫中提供了BigDecimal類來解決這個問題,它采用十進制來表示實數(shù)。但是,針對BigDecimal對象的算術(shù)運算要比針對Float的算術(shù)運算慢上許多倍。
文本
字符串表示
- 單引號
單引號引入字符串字面量來表示字符串,其中如果需要表示單引號,只需要在之前加入一個反斜線。
'it\'s just a test!'
如果需要表示反斜線,那么只需要在反斜線之前再加入一個反斜線就可以了。
'This is a backslash: \\'
在一個單引號表示的字符串中,如果一個反斜線后邊既不是單引號又不是雙引號,那么該反斜線就表示反斜線。意味著,不需要成對的出現(xiàn)反斜線。
'a\b' == 'a\\b'
單引號字符串可以跨行,得到的字符串會包含換行符,也不能通過 反斜線來轉(zhuǎn)義行尾的換行符。
'This is a long string literal \
that include a backslash and a new line.'
如果不希望加入換行符,那么只需將其劃分成為相鄰的字符串字面量,同時在其結(jié)尾加入反斜線轉(zhuǎn)義末尾的換行符就可以了。
'The three literal are' \
'concatenated into one by interpreter' \
'The resulting string contains no newlines.'
- 雙引號
雙引號引用的字符串字面量則支持更多的轉(zhuǎn)義,比如換行\(zhòng)n,制表\t和雙引號"。
同時還支持Ruby特有的“字符串內(nèi)插”。
"The resulte is #{8 + 9}"
表達式位于花括號中,并且前邊有一個#字符。當插入的表達式只是一個全局變量、實例或類變量的引用時,花括號可以省略。
當不希望#字符被特殊處理時,只需在之前加入一個反斜線即可。
Ruby 也支持printf和sprintf這兩個方法。
printf("Pi is about %.4f", Math::PI)
但是,Ruby中還有一個與sprintf等價的操作符,只需要簡單的在一個格式字符串和帶插入的其中的參數(shù)之間放置一個%即可。
"Pi is about %.4f" % Math::PI
- Unicode 轉(zhuǎn)義序列
在Ruby1.9以后,在雙引號引用的字符串中通過\u可以轉(zhuǎn)義任意的Unicode字符,最簡單的形式是在\u后邊添加一個十六進制數(shù)字(不區(qū)分大小寫),它們代表了0000到FFFF之間的Unicode碼點。
"\u00D7" # => "x"
第二種形式是在它后邊加一對花括號,花括號之間的數(shù)字可以表示0到10FFFF之間的任何Unicode碼點。
"\u{A5}" # => same as "\u00A5"
最后一種形式允許多個碼點同時轉(zhuǎn)義,只需要在花括號內(nèi)放入多組1到6個十六進制數(shù)字組成的序列即可,各組之間用空格或tab符號分割,在開始花括號之后和結(jié)束花括號之前均不允許有空格。
"\u{20AC A3 A5}"
- 字符串字面量分界符
Ruby除了支持單引號和雙引號以外,還支持一種更一般化的語法來引用字符串字面量。以%q開頭的遵循單引號引用字符串規(guī)則,以%Q(或%)開頭的遵循雙引號引用字符串規(guī)則。其后緊接的第一個字符為分界符,知道下一個分界符(未被轉(zhuǎn)義)的內(nèi)容組成了改字符串。
%q(Don't worry about ' character!)
%Q|"How are you?", he said|
%-This string ends with a newline\n-
- Here document
Here document 以 << 或 <<- 開頭,后邊緊跟(為了避免與左移操作符混淆,不允許有空格)一個用于指定結(jié)尾分界符的標示符或字符串,從下一行開始一直待該分界符單獨出現(xiàn)到一行為止。
document = <<HERE
This is a string literal.
It has two lines and abruptly ends. . .
HERE
Ruby 解釋器解釋到 << 和分界符之后并不會停止,事實上,在讀取一個 here document 的內(nèi)容之后, Ruby 解釋器會回到該 here document 的開頭部分所在行,并繼續(xù)解析后邊的內(nèi)容。
greeting = <<HERE + <<HTERE + 'world'
Hello
HERE
there
HTERE
結(jié)尾分界符必須單獨出現(xiàn)在一行上,該分界符后邊甚至連注釋不能接注釋。如果以 << 開頭,那么結(jié)尾分界符必須出現(xiàn)在一行的開頭。如果以 <<- 開頭,那么在結(jié)尾分界符之前可以出現(xiàn)空白。除了空的 here document,每個 here document 都以一個換行符結(jié)尾。
如果采用一個沒有被引號括起來的標示符作為分界符,那么 here document 就會表現(xiàn)的像被雙引號應(yīng)用的字符串一樣,其中反斜線用于轉(zhuǎn)義,而 # 用于內(nèi)插字符串。
如采用一個雙引號引用的字符串字面量來作為 here document 的分界符。除了分界符里面可以出現(xiàn)空格,這與使用單個分界符的情形是一樣的。
如果采用單引號引用的字符串字面量作為分界符,它會表現(xiàn)的 比單引號引用的字符串還要嚴格一些。因為單引號本身不是分界符,所以反斜線不在作為轉(zhuǎn)義字符,因此,反斜線也是字符串字面量的一部分。
document = <<'THIS IS THE END, MY ONLY FRIEND, THE END'
lots an lots of test goes here
THIS IS THE END, MY ONLY FRIEND, THE END
- 反引號所引用命令執(zhí)行
當使用反引號來引用文本時,該文本作為一個由雙引號引用的字符串字面量來處理。改文本的值將被傳遞給一個名為 Kernel.` 的方法,該方法將該文本的值作為一個操作系統(tǒng)的 shell 命令來執(zhí)行。
`ls`
另外,Ruby 也支持一種泛型化的引用語法,可以用來替代反引號,類似于 %Q 的語法,這里使用 %x 來替代反引號。
%x[ls]
- 字符串字面量和可變性
Ruby 的字符串是可變的。因此,Ruby 無法用同一個對象來表達兩個相同的字符串字面量。每當 Ruby 遇見一個字符串字面量的時候,它都會創(chuàng)建一個對象。
10.times { puts "test".object_id }
因此,為了獲得更好的運行效率,應(yīng)該避免在循環(huán)中使用字符串字面量。
字符字面量
在 Ruby 中, 你可以用一個字符前面加問號的方式來表示單個字符構(gòu)成的字面量。
?A
因為 Ruby1.9 對字符串字面量的解釋方式不同于 Ruby1.8 , 字符就是長度為一的字符串,所以上邊例子完全等價于 'A',也就是說,我們完全沒有必要再使用這種語法了。
字符串的操作
Ruby 通過 + 操作符連接兩個字符串,不同 JavaScript,其并不會將右側(cè)操作數(shù)自動轉(zhuǎn)換成為字符串。
一般情況下,采用字符串內(nèi)插比采用+操作符簡單一些,并會自動調(diào)用其 to_s。
<< 操作符會將第二個參數(shù)添加到第一個參數(shù)后面,不同于+操作符,他會修改左側(cè)的操作數(shù),而不是返回一個對象。<<操作符同樣不會對右側(cè)的操作數(shù)做任何類型的轉(zhuǎn)換,但是,如果右側(cè)的操作數(shù)是一個整數(shù),那么它將會被當做一個字符編碼來處理。
* 操作符期待右側(cè)操作數(shù)是一個整數(shù)。如果左側(cè)的操作數(shù)是一個字符串字面量,那么任何內(nèi)插操作都只會在重復操作被執(zhí)行之前被執(zhí)行一次。如下:
a = 0
"#{a=a+1} " * 3 # Returns "1 1 1 ", not "1 2 3 "
Ruby 字符串同時定義了 == 、 != 、< 、<= 、> 和 >= 來比較字符串。當且僅當兩個字符串擁有相同的長度,而且所有的字符都相等的時候,它們才是相等的。字符串之間的比較會嚴格的基于字符編碼,不會對將要比較的字符串進行任何格式化。字符串是大小寫敏感的。在 ASCII 里,大寫字符的編碼值均小于小寫字符,比如 "Z" < "a"。對于 ASCII 字符進行大小不敏感的比較可以使用 casecmp,也可以是在比較前先通過 downcase 或 upcase 方法將字符串轉(zhuǎn)換成為相同的形式。記住,Ruby 關(guān)于大寫或小寫字符的理解僅限于 ASCII 字符集。
訪問字符和子字符串
在 Ruby1.9 中,亦可以這樣索引單個字符。例如:
s = "hello";
s[0] # 'h'
s[s.length -1] # 'o'
s[-1] # '0'
s[-2] # 'l'
s[s.length] # nil
而如果需要改變字符串里面的單個字符串,字需要簡單地講方括號置于表達式的左側(cè)即可。同時也支持是一個任意長度的字符串。
s[0] = 'H'
如果希望獲得一個子字符串,你只需要在方括號里使用由兩個逗號分割的操作數(shù)即可。第一個操作數(shù)指定索引值(可能為負數(shù)),第二個操作數(shù)指定長度值(必須是非負值)。
s = "hello"
s[0, 2] # "he"
s[-1, 1] # "o"
s[0, 0] # ""
s[0, 10] # "hello" 返回所有可用的字符串
s[s.length, 1] # "" 在剛好超過字符串長度的地方是一個空字符串(方便賦值時在字符串末尾添加字符串)
s[s.length+1, 1] # nil
s[0, -1] # nil
同樣,你也可以將任意的字符串復制給個上述方式索引的子字符串。
另一種提取、插入、刪除和替換子字符串的方法是通過一個 Range 對象索引一個字符串。
s = "hello"
s[2..3] # "ll"
s[-3..-1] # "llo"
s[0..0] # "h"
s[0...0] # ""
s[2..1] # ""
s[7..10] #nil
你還可以通過一個字符串來索引另一個字符串,那么第一個被匹配的字符串將被返回,否則返回nil。事實上這種形式的字符串索引只有出現(xiàn)在一個賦值語句的左側(cè)時采用用武之地。
s = "hello"
while (s["l"])
s["l"] = "L";
end
同樣,你還可以使用一個正則表達式來索引一個字符串。
s[/[aeiou]/] = "*"
對字符串進行迭代
在 Ruby1.9 里定義了三個迭代字符串的方法,each_byte 按照字節(jié)對一個字符串進行迭代,each_char 按照字符進行迭代,each_line 按照行進行迭代。另外,each_char 比使用[]操作符和字符索引更加高效。
字符編碼
Ruby 在1.9版之前堪稱是對字符編碼支持最差的語言之一,而現(xiàn)在變成了支持最好的語言之一。情況比較復雜,參見我的另一篇筆記《Ruby 與字符編碼》。
數(shù)組
Ruby 的數(shù)組可以用負值進行索引,如果賦值操作時使用負值且超出范圍,那么報錯。
另外Ruby 支持一種更加通用的數(shù)組字面量特殊語法。
%w[this is a test]
%W| ( [ { < |
同時也可以通過 Array.new 構(gòu)造函數(shù)來構(gòu)造數(shù)組。
empty = Array.new # 返回空數(shù)組 []
nils = Array.new(3) # [nil, nil, nil]
zeros = Array.new(4, 0) # [0, 0, 0, 0]
count = Array.new(3) { |i| i + 1} # [1, 2, 3]
Ruby 還定義了其他有用的操作符。
[1, 2] + [3, 4, 5] # [1, 2, 3, 4, 5]
["a", "b", "c", "b", "a"] - ["b", "c", "d"] # ["a", "a"]
[0] * 4 # [0, 0, 0, 0]
同時,還定義了 | 和 & 操作符。不過,操作符不具有傳遞性,a | b 不等于 b | a 。同時,Ruby 不保證返回數(shù)組中元素的順序。
a = [1, 1, 2, 2, 3]
b= [4, 4, 3, 3, 2]
a | b # [1, 2, 3, 4]
b | a # [4, 3, 2, 1]
a & b # [2, 3]
b & a # [3, 2]
同時數(shù)組還定義了一系列有用的 API,例如 each 等等。
哈希
Ruby 里的 hash 采用一種哈希表的數(shù)據(jù)結(jié)構(gòu)來實現(xiàn)的。那些作為哈希鍵的對象必須有一個 hash 的方法,改方法返回一個 Fixnum 的哈希碼。如果兩個鍵相同,那么它們必須具有相同的哈希碼。不相等的鍵也可以擁有相同的哈希碼,但是僅當哈希表有極少的重復時,其效率才是最高的。
Hash 類采用 eql? 方法比較鍵之間的相等性,對于大多數(shù) Ruby 類而言,eql? 方法與 == 操作符一樣。如果你新定義的類重寫了 eql? 方法,那么你必須同時重寫 hash 方法,否則你的類無法作為一個哈希鍵。
如果使用一個可變對象作為哈希鍵會帶來一些問題,改變一個對象的內(nèi)容通常會改變其哈希碼,那么內(nèi)部的哈希表將會被破壞,而且該哈希的行為也將不正確。由于字符串是可變的,但是有常常作為哈希鍵,所以 Ruby 將它們作為特例進行了處理。對那些作為鍵的字符串,Ruby 會生成它們的私有拷貝。但是這是唯一的特例,如果使用任何可變對象作為哈希鍵時,可以考慮為這些可變對象生成私有拷貝,或者調(diào)用 freeze 方法。如果你必須使用可變的哈希鍵,那么請在每次更改鍵后,調(diào)用 Hash 類的 rehash 方法。
范圍
一個 Range 對象表示位于開始值和結(jié)束值之間的一些值。begin..end 范圍對象中值滿足:
begin <= x <= end
begin...end 范圍對象中的值滿足:
begin <= x < end
所有范圍的端點值都必須實現(xiàn) <=> 操作符。如果端點沒有實現(xiàn) succ 方法,那么我們稱之為連續(xù)的成員關(guān)系測試。否則,即離散的成員關(guān)系測試。該集合包含 begin、begin.succ、begin.succ.succ 等等。范圍的成員關(guān)系是一種集合的關(guān)系。值得注意的是,對離散的成員關(guān)系測試開銷要遠大于對連續(xù)的成員關(guān)系測試開銷。
在Ruby1.9中,cover? 方法使用連續(xù)的成員關(guān)系測試。include? 和 member? 是同義詞,只有在范圍端點是數(shù)字時使用連續(xù)的成員關(guān)系測試,否則它們就會使用離散性的成員測試。
符號
一個 Ruby 解釋器的典型實現(xiàn)會維護一個符號表,在這個表中它存儲了所知曉的所有類、方法及變量名稱,是這樣一個解釋器可以避免大多數(shù)字符串比較:比如,它可以通過一個方法名在符號表中的位置來對其進行引用。這樣一來,就將一個開銷較大的字符串操作轉(zhuǎn)換成了一個開銷較小的整數(shù)操作。
Symbol 也有一個 %s 字面量語法。你可以使用 intern 和 to_sym 方法將一個 String 對象轉(zhuǎn)換成一個 Symbol,而且你也可以使用 to_s 的方法或其別名 id2name 將一個 Symbol 轉(zhuǎn)回一個字符串。
當你使用字符串的目的是在于將其作為獨一無二的標識符,而不在于它文本的內(nèi)容時,請改用符號。比較兩個 Symbol 對象的相等性要遠遠快于比較兩個字符串的相等性。
在 Ruby1.9 中,Symbol 類定義了一些 String 方法,比如 length、size、比較操作符,甚至 [] 和 =~ 操作符,而且符號也可以被作為一種不可變的(也是不可被垃圾回收的)字符串來使用。
True、False 和 Nil
True、False 和 Nil 分別是 TrueClass、FalseClass 和 NilClass 的單鍵實例。Ruby 中并沒有 Boolean 類。
當 Ruby 需要一個布爾值時,nil 表現(xiàn)為 false,而 nil 和 false 之外的所有值都表現(xiàn)為 true。
判斷一個值是否為 nil :
o == nil
o.nil?
對象
對象引用
Ruby 中使用對象時,都是在使用對象的引用,所有的對象都通過引用來操作。但是,在實現(xiàn)時,F(xiàn)ixnum 和 Symbol 對象實際上是“立即值”,而非引用。然而,F(xiàn)ixnum 和 Symbol 都沒有可變的方法,也就是不可變的,因此又可以把它當做是按引用來操作的(唯一區(qū)別在于,不能為立即值定義單鍵方法)。
t = s = "Ruby"
s[-1] = ""
print t # "Rub"
Ruby 中方法實參是通過值而不是引用來傳遞的,因此,當把一個對象傳遞給一個方法時,只不過被傳遞的值正好是對象的引用罷了。
對象標識
在 Ruby1.9 中,可以通過 id 和 object_id 來獲得對象獨一無二的標識符。
對象的類和類型
通過 class 方法來確定一個對象所屬的類。也通過 instance_of 方法來檢查對象是否為某個類的實例。
o.class == string
o.instance_of? String
通過 superclass 可以確定某個類型的超類。通過 is_a? 可以確定某個對象是否為某個類和其子類的實例。
o.class.superclass
String.superclass
o.is_a? Comparable # 也可以判斷 mixin 模塊
o.is_a? Object
對象的相等性
Ruby 擁有很多的方法用來比較對象的相等性。
equal? 方法
equal? 方法由 Object 定義,用于確定兩個值是否引用了同一個對象。
a = "Ruby"
b = c = "Ruby"
a.equal? b # false
b.equal? c #true
一般而言,子類永遠不要重寫 equal? 方法。
另一種檢查兩個值時候引用同一個對象的方法是比較他們的 object_id 。
== 操作符
在 Object 類里,他是 equal? 方法的同義詞。但大多數(shù)的類都重定義了這個操作符,使得不同的實例之間也能進行相等性測試。
Array 和 Hash 都定義了 == 操作符。如果兩個數(shù)組擁有相同的數(shù)量的元素,并且對應(yīng)位置上的元素通過 == 比較也相等,那么兩個數(shù)組通過 == 比較是相等的。如果兩個哈希擁有相同數(shù)量的鍵值對,額況且對應(yīng)的鍵和值也相等那么這兩個值通過 == 比較之后是相等。
Number 類在它們的 == 操作符里將進行簡單的數(shù)值轉(zhuǎn)換,比如 Fixnum 1 和 Float 1.0 通過 == 比較之后是相等。
諸如 String 、 Array 和 Hash 類的 == 操作符,通常要求兩個操作符屬于同一個類。但如果右側(cè)的操作數(shù)定義了一個 to_str、 to_ary 和 to_hash 的方法,那么原先的 == 操作符會調(diào)用右側(cè)的操作數(shù)所定義的 ==。
class MyArray
def initialize(array)
@array = array
end
def to_ary
@array
end
def ==(array)
to_ary == array
end
end
array = [1, 2, 3]
my_array = MyArray.new([1, 2, 3])
array == my_array # true
!= 操作符會簡單的使用 == 操作符并且反轉(zhuǎn)其結(jié)果。但在 1.9 中,類也可以顯示的定義自己的 != 操作符。
eql?
Object 將 eql? 方法定義為 equal? 方法的同義詞,那些重寫了 eql? 方法的類通常將其作為更加嚴格的 == 操作符,即不允許類型轉(zhuǎn)換。
1 == 1.0 # true
1.eql? 1.0 # false
Hash 類采用 eql? 檢查兩個哈希鍵是否相等,如果兩個對象通過 eql? 結(jié)果比較是真,那么它們的 hash 方法必須返回相同的值。
=== 操作符
=== 操作符被稱為“條件相等性”操作符,用于測試一個 case 語句的目標值是否和某個 when 從句相匹配。
Object 類定義了一個默認的 === 操作符,它會調(diào)用 == 操作符。某些關(guān)鍵的類重寫了 === 操作符:Range 用來測試一個值是否在范圍內(nèi); Regexp 類用于測試一個字符串是否與某個正則表達式相匹配;Class 類用于測試一個對象是否該類的一個實例;Symbol 類在當其右側(cè)操作數(shù)和左側(cè)操作數(shù)是同一個符號對象時,或者當右側(cè)操作數(shù)是一個持有和左側(cè)符號對象相同文本的字符串時,改操作符返回 true。
=~ 操作符
String、Regexp 和 Symbol 定義了 =~ 操作符用于進行模式匹配。Object 也定義了這個操作符,它直接返回 false。!~ 被定義為 =~ 的反義,在 Ruby1.9 以后,你也可顯式自定義。
對象的順序
類通過實現(xiàn) <=> 來定義其順序性。當左側(cè)操作數(shù)小于右側(cè)操作數(shù)時,返回-1,反之返回1,相等返回0。一般情況下,定義了 <=> 操作符的類會將 Comparable 模塊作為一個 mixin 包含進來,以同時獲得 <、<=、==、>= 和 > 操作符。還有一個比較方法 betwee?
如果 <=> 返回 nil 。那么所有基于它的操作符都返回 false。例如 NaN這個特殊的 Float。
nan = 0.0/0.0
nan < 0 # false
nan > 0 # false
nan == 0 # false
nan == nan #false
nan.equal?(nan) # true
對象轉(zhuǎn)換
顯式轉(zhuǎn)換
一般情況下,Ruby 中的方法不會對自動對類型進行轉(zhuǎn)換,如果需要,你應(yīng)該手動調(diào)用轉(zhuǎn)換方法。最為常見的就是to_s、to_i、to_f 及 to_a 方法,他們分別將對象轉(zhuǎn)換成為 String、Integer、Float 和 Array。
關(guān)于 # 的字符串內(nèi)插,Ruby 會主動調(diào)用其 to_s 的方法。to_s 的另一個重要的選擇性替代是 inspect 方法。通常而言,to_s 用于返回人類可讀的對象表現(xiàn)形式,而 inspect 方法用于調(diào)試,它能返回一個給開發(fā)人員帶來幫助的表現(xiàn)形式。而 Object 定義的 inspect 方法只是簡單的調(diào)用 to_s。
隱式轉(zhuǎn)換
Ruby 中還定義了 to_str、to_int、to_ary 和 to_hash,用于方法進行隱式的轉(zhuǎn)換。不過在內(nèi)建類里,這些轉(zhuǎn)換方法并沒有被普遍的實現(xiàn)。
在 Ruby1.9 里,內(nèi)建的 String、Array、Hash、Regexp 及 IO 類都定義了一個名為 try_convert 的類方法。如果這個方法的實參定義了以上一個合適的隱式轉(zhuǎn)換方法,那么就會對其方法進行調(diào)用,否則返回 nil。例如,對象 o 定義了 to_ary 的方法,那么 Array.try_conver(o) 將返回 o.to_ary,否則返回 nil .
轉(zhuǎn)換函數(shù)
Kernel 模塊還定義了4個全局轉(zhuǎn)換函數(shù)——Array、Float、Integer 及 String。
Array 函數(shù)視圖調(diào)用其實參的 to_ary 方法來將其轉(zhuǎn)換成為一個數(shù)組。如果沒有定義 to_ary 方法,或者該方法返回 nil。那么就試著調(diào)用其 to_a。如果沒有定義 to_a 方法,或者改方法返回nil。這簡單的返回一個數(shù)組,并把該實參作為該數(shù)組的第一個元素。
Float 對象會把 Number 的實參直接轉(zhuǎn)換成一個 Float 對象。任何非 Numeric 的值,都會調(diào)用其 to_f 的方法。
Interger 函數(shù)將其實參轉(zhuǎn)換成為一個 Fixnum 或 Bignum。如果其實參是一個 Numeric 它直接進行轉(zhuǎn)換,浮點值被截斷。如果是一個字符串,它會尋找一個基數(shù)指示符(以0開頭八進制,以0x開頭十六進制,以0b開頭二進制),并據(jù)此對字符串進行轉(zhuǎn)換。與String.to_i 不同,Integer 函數(shù)不允許末端出現(xiàn)非數(shù)值字符。對于任何其他類型轉(zhuǎn)換,Integer 會首先嘗試 to_int ,然后調(diào)用 to_i 。
String 只是簡單的調(diào)用其參數(shù)的 to_s 的方法。
算數(shù)操作符的強制轉(zhuǎn)換
數(shù)值類型定義了一個 coerce 的方法。意圖將其實參類型轉(zhuǎn)換成為其調(diào)用者類型,或者這兩個對象的更一般兼容形式。coerce 返回一個數(shù)組,第一個元素由 coerce 方法轉(zhuǎn)換而來,第二個元素來自其調(diào)用者(如果需要,就進行轉(zhuǎn)換)。
1.1.coerce(1) # [1.0, 1.1]
requier "rational"
r = Rational(1, 3)
r.coerce(2) # [2/1, 1/3]
算數(shù)操作符會使用 coerce 方法。例如,F(xiàn)ixnum 的 + 操作符不知道如果操作 Rational 數(shù)字,于是右側(cè)的操作數(shù)會調(diào)用 coerce 方法,并將左側(cè)的操作數(shù)作為實參傳進去,然后在返回數(shù)組的兩個值上簡單的調(diào)用 + 即可。
對象拷貝
clone 和 dup 方法都會返回一個調(diào)用它們對象的淺拷貝,即如果拷貝對象有指向其他對象的引用,那么只有這些引用被拷貝,而引用的對象本身不被拷貝。
如果拷貝對象定義了 initialize_copy (拷貝構(gòu)造函數(shù))的方法,那么 clone 和 dup 就會簡單的分配一個新的實例空間(該實例所屬類與被拷貝對象相同),然后在其上調(diào)用 initialize_copy 的方法。
類也可以直接重寫 clone 和 dup 的方法。
clone 和 dup 的區(qū)別有兩點,其一,clone 會拷貝一個對象被凍結(jié)和受污染的狀態(tài),而 dup 僅僅拷貝受污染的狀態(tài); 其二,clone 方法拷貝一個對象所有的單鍵方法,而 dup 不會。
編組對象
Marshal.dump 用來保存一個對象的狀態(tài),它返回一個二進制的字符串。你可以將一個 I/O 流對象作為第二個實參傳遞給 Marshal.dump 的方法,它會把保存的對象的狀態(tài)寫入這個流中。
為了恢復一個編組后的對象,你可以將一個包含了該對象的字符串或 I/O 流傳遞給 Marshal.load。
值得注意的是,這兩個方法存在版本依賴。
我們可以利用這兩個方法來創(chuàng)建對象的深度拷貝。
def deepcopy(o)
Marshal.load(Marshal.dump(o))
end
值得一體的是,YAML 是 Marshal 模塊的一種被廣泛采用的替代方案。
凍結(jié)對象
freeze 方法可以將一個對象凍結(jié)起來,一個被凍結(jié)的對象將變得不可改變——它所有的內(nèi)部狀態(tài)都不能被改變,而且對其可改變的方法的調(diào)用也會失敗。
s = "ice"
s.freeze
s.frozen? # true
s.upcase! # RuntimeError: can't modify frozen String
污染對象
taint 方法將任何對象標記為受污染的。一旦一個對象受污染,那么任何源自它的對象都變成受污染的??梢酝ㄟ^ tainted? 方法測試一個對象是否受污染。
s = "untrusted"
s.taint
s.tainted? # true
s.upcase.tainted? # true
s[3, 4] # true
用戶輸入(命令行參數(shù)、環(huán)境變量以及 get 方法讀取的字符串)都會自動成為受污染的。
一個受污染的對象可以通過 untaint 方法變成為受污染的。