# 數據類型
Ruby核心庫(core,不包括標準庫)的數據類型分為:
- 數字(Numeric -> 包含了Integer/Float子類, Integer又包含了Fixnum和Bignum子類)
- 字符串(String)
- 符號 (Symbol)
- 數組 (Array)
- 哈希 (Hash)
- 范圍 (Range)
### 數字Numeric
數字,分為很多種,整數、小數。 Ruby中數字類型很簡單:
~~~
1.class #=> Fixnum
1.class.superclass #=> Integer
1.class.superclass.superclass #=> Numeric
~~~
一個數字字面量,即為一個數字類型,ruby中一切皆對象,所以這個數字字面量也可以響應一個叫class的方法,來返回它自己的類別,是Fixnum。 superclass方法,則返回一個類的父類。
Ruby允許我們像上面代碼那樣,連續調用,「返回的值」即為下一次調用的「消息接收者」,當然你得保證返回的值是可以響應那個消息的。
還有小數:
~~~
0.1.class #=> Float
0.1.class.superclass #=> Numeric
~~~
還有比較大的整數呢。
~~~
(2**200).class #=> Bignum
(2**200).class.superclass #=> Integer
# 當值很大的時候
(2**2000000000) #=> 返回一個Infinity,代表無窮大
(2**2000000000).class #=> Float
~~~
結論:
Ruby中整數的值在一個小范圍的時候,是Fixnum類型, 當數值很大的時候,則變成了Bignum類型,太大的值會返回一個固定的值Infinity,代表無窮大。而這個Infinity是一個Float對象。
Ruby中的小數, 是一個Float類型。 Float類型在Ruby中算是一個缺陷,因為它在計算過程中會產生誤差,會帶來一些bug。實際應用中都不會去使用這個數字類型。我們一般用Ruby標準庫中的BigDecimal類型。
### BigDecimal
示例:
~~~
require 'bigdecimal'
sum = BigDecimal.new("0")
10_000.times do
sum = sum + BigDecimal.new("0.0001")
end
print sum #=> 0.1E1
~~~
因為是Ruby標準庫,使用的時候一定要require那個庫。
### 字符串(String)
Ruby的字符串,分為兩種。一種是雙引號包含的東西,一種是單引號所包含的東西。
~~~
str = " hello world "
str = ' hello world '
~~~
他們的區別,就是單引號的字符串,基本是原樣輸出,只能識別'\''這樣形式的轉義符。而雙引號則完全識別轉義符。
~~~
str = '\'' #=> "'"
str = "\'" #=> "'"
str = 'hello \n \t world!' #=> "hello \\n \\t world!"
str = "hello \n \t world!" #=> "hello \n \t world!"
~~~
### #{}
使用#{}可以把一個變量,「鑲嵌」到一個字符串里面:
~~~
hello = "hi"
str = " #{hello} world " #=> "hi world"
str = '#{hello} world' #=> "\#{hello} world"
~~~
通過上面的代碼,也可以看出來單引號字符串和雙引號字符串之間的差別,就是單引號字符串,無法識別#{}這個操作符。
### %q / %Q 操作符
對于一些比較復雜的字符串,像:
~~~
"#{name} said: \"Clap your hands!\""
~~~
這種字符串里面,雙引號也作為了字符串的內容, 影響了可讀性。 那么Ruby就提供了一個%Q操作符來幫助我們解決這樣的問題:
~~~
name = 'Alex'
%Q|#{name} says: "Try ftp://ruby-lang.org/pub/ruby/1.9/"|
%Q-#{name} says: "Clap your hands!"-
%Q/#{name} says: "Play tic-tac-toe!"/
# 省略 Q
%-#{@name} says: "Clap your hands!"-
%/#{name} says: "Play tic-tac-toe!"/
%[#{name} says: "Play tic-tac-toe!"]
~~~
%Q后面可以跟任何一對對稱的符號,只要是對稱就可以。
%Q代表了雙引號,當%后面省略了Q,也是一樣的。 而%q, 則是代表單引號.
~~~
name = 'Lee'
%q[#{name} says: "Play tic-tac-toe!"] #=> "\#{name} says: \"Play tic-tac-toe!\""
~~~
### 符號 (Symbol)
符號類型,在Ruby中用一個冒號加名字或者是字符串來表示。
~~~
:name
:_name
:"name"
~~~
你不能使用冒號和數字來聲明一個符號型,否則會報錯。
~~~
:1
#=> SyntaxError: unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
~~~
### 符號是什么
在Ruby中,符號表示一個「名字」。它有點類似于字符串,但和字符串又有不同。在Ruby中,一切皆對象,符號類型,也是對象,每個對象都有一個唯一的對象標識符object_id, 對象標識符一樣,就代表是同一個對象,否則就是不同的對象。我們來比較下符號和字符串。
~~~
:name.object_id #=> 66088
:name.object_id #=> 66088
:name.object_id #=> 66088
"name".object_id #=> 10285860
"name".object_id #=> 10058700
"name".object_id #=> 8904020
~~~
從上面的代碼里可以看出, 連續三個:name,都是指同一個Symbol對象,而連續三個"name",則是三個不同的對象。
所以,Symbol對象是一種具有唯一性的類「字符串」, 因為Symbol也擁有字符串的一些行為。比如:
~~~
:name.upcase #=> :NAME
"name".upcase #=> 'Name'
~~~
當然,不是全部的字符串方法它都可以響應,你可以去ruby-doc.org去比較他們的方法。
Symbol對象,從創建開始,一直到程序退出運行,都是被存放到一個叫做符號表的地方, Ruby的垃圾回收(GC)不會清理這些符號對象。而字符串不一樣, GC會清理掉那些無用的字符串對象。
在認識到符號的這些特性之后, 應該不難理解我們把符號類型用來表示一個「名字」的概念。
舉個例子:
有三個雙胞胎字符串對象:'name', 'name', 'name', 我們可以用符號類型來形容他們的長相, 都是:name。
### 數組 (Array)
Ruby中的數組,是一個任何對象的有序的、用整數來索引的集合。
~~~
arr = [1, 2, :a, 'name', nil]
arr = Array[1, 2, 3, :name]
arr.class #=> Array
arr[0] #=> 1
arr[1] #=> 2
#...
~~~
Ruby的數組,可以存放任何對象。
~~~
arr = [1, 2, 3, [4, 5, 6]]
arr[0] #=> 1
arr[3][0] #=> 4
~~~
上面,我們定義了一個二維數組,通過[]方法,傳入索引參數,可以取得數組的值。
數組的概念很容易理解。可以結合ruby-doc.org來查看并且練習數組中內建的很多方法。
### 哈希 (Hash)
Ruby中的哈希,是一個鍵值對的集合。在Ruby1.8中是無序的,但是在Ruby1.9開始,哈希變成有序的了。
~~~
h = {a: 100, b: 200}
h = Hash["a" => 1000, "b" => 2000]
h[:a] #=> 100
h['a'] #=> 1000
~~~
Hash是在{}中被包含的字面量,也可以通過Hash[]方法來創建一個hash,參考上面的代碼。我們可以通過一個key來獲取其所對應的值。
Hash的key,必須是唯一的。
~~~
h = {a: 1, b: 2, a: 3}
h[:a] #=> 3
~~~
key必須是唯一,所以上面的代碼中,h[:a]取出的值是3.
我們提倡使用符號類型來作為Hash的key,這也是Ruby1.9開始引入下面的hash結構的原因之一:
~~~
h = {a: 1, b: 2}
#等同于
h = {:a => 1, :b => 2}
~~~
但也不是所有的情況都試用于上面第一種寫法,比如你必須要以數字作為key,就只能用第二種形式。但是大部分情況,第一種寫法已經夠用了。 使用字符類型做為key,可以節省內存。因為上面我們講過,字符串和符號的區別,就是每個字符串都是不同的對象,而Ruby中的對象是占用內存的,所以我們盡量讓其少生成點對象。這也是Ruby鼓勵我們在Hash中使用字符類型作為key的原因。
同樣,Hash有很多內建方法,可以去ruby-doc.org中自行查看并且練習。
### 范圍 (Range)
范圍(Range)發生無處不在:一月至十二月,0到9,50至67行,依此類推。
(1..3) 和 (1...3) 都表示一個范圍。
~~~
(1..3).class #=> Range
(1...3).class #=> Range
~~~
范圍有一個起點,一個終點,產生連續的序列值。如果是兩個點把起點和終點相連,則范圍的連續值包含終點值。如果是三個點,則范圍的連續值不包含終點值。
可以參考我們學過的數學中的開閉區間來理解這個概念。
~~~
(1..3).each{|i| puts i}
#=> 1
2
3
(1...3).each{|i| puts i}
#=> 1
2
~~~
我們使用each方法來迭代范圍中的值,可以看得出兩個點和三個點范圍類型的區別。
### 結語
Ruby中的主要數據類型大概就講這么多,Ruby還有其他的數據類型,比如時間日期, 表示真假的Boolean型,甚至標準庫中所包含的數據類型,這些大家可以參考ruby-doc.org去自行學習。
- 序
- Chapter 1: 初識Chef
- 一些背景
- Chef vs Puppet
- Chapter 2: Chef應用
- Chef架構
- Chef能做什么
- Chef組件
- Chef環境安裝
- chef-server
- opscode-chef
- chef-solo
- Chef實戰
- 實戰前的必修理論
- 使用Chef
- Chapter 3: Ruby基礎
- 對象與方法
- 標識符
- 類與模塊
- 數據類型
- 真與假
- 控制語句
- 代碼塊
- Chapter 4: Chef源碼架構
- Rubygems與gem
- bundler
- Chef源碼組織
- Chapter 5: Rails基礎
- Rails是什么
- MVC架構
- Restful
- Rails組成與項目結構
- Chapter 6: Chef Server WebUI
- Chef Server Webui組織結構
- Chef Rest API
- 參考