二十分鐘 Ruby 體驗(转载)
来源:互联网 发布:完成端口例子 编辑:程序博客网 时间:2024/06/06 04:04
转载自:http://www.ruby-lang.org/zh_TW/documentation/quickstart/
(开个新坑,如无意外,现在到明年7月入职,会一直更新Ruby文章)
簡介
這是一個簡短的 Ruby 入門體驗,應該可以在二十分鐘內完成。您必須先安裝好 Ruby (如果還沒有,請先下載安裝)
互動式 Ruby
Ruby 附帶了一支程式可以讓你即時看到執行 Ruby 敘述的結果。使用這種互動式環境來學習 Ruby 可說是非常地方便。
打開 IRB (表示 Interactive Ruby)。
- 如果你使用 Mac OS X 請打開
Terminal
然後輸入irb
和 enter。 - 如果你使用 Linux,請打開一個 shell 然後輸入
irb
和 enter。 - 如果你使用 Windows,請從開始選單中打開 Ruby 的
fxri
。
irb(main):001:0>
Ok,打開了,現在怎麼辦?
請輸入:"Hello World"
irb(main):001:0> "Hello World"=> "Hello World"
讓 Ruby 聽話!
發生什麼事了? 你是不是剛剛寫下了全世界最短的 “Hello World” 程式?也不盡然。第二行只是 IRB 告訴我們最後的敘述執行結果。如果我們需要輸出 “Hello World” 還需要多一行:
irb(main):002:0> puts "Hello World"Hello World=> nil
puts
是 Ruby 的基本輸出指令。但是什麼是 => nil
呢? 那是那一行敘述的執行結果。 puts
總是回傳 nil,nil 在 Ruby 中表示一個絕對的空值。
你的第一個免費計算機
其實,我們已經可以用 IRB 來當做一個簡單的計算機了。
irb(main):003:0> 3+2=> 5
三加二,夠簡單了。那怎麼三乘二呢? 你可以試試,一點都不難,你也能夠隨意輸入數字試試。試著按按看 上 它會顯示上一行的 3+2
,然後你可以往左移動到 +
更改成 *
乘號。
irb(main):004:0> 3*2=> 6
接下來,讓我們試試看三的平方:
irb(main):005:0> 3**2=> 9
在 Ruby 中 **
是 “次方” 的意思。但是如果你想開根號呢?
irb(main):006:0> Math.sqrt(9)=> 3.0
等一下,上面那是什麼? 如果你想說:”它是 9 的平方根” 那就對了。讓我們來仔細看一下。首先,什麼是 Math
?
給程式分類的模組(Modules)
Math
是一個內建的數學模組。Ruby 的模組有兩種作用。這裡介紹的是第一種:把功能相似的方法放在一起。Math
模組還包括了像是 sin()
和 tan()
。
接下來介紹點(dot)。這個點是做什麼用的? 這個點是用來告訴接收者(即 Math 模組)一個訊息。什麼訊息呢? 在這個例子,訊息是 sqrt(9)
,也就是呼叫 sqrt
方法,並傳遞 9 作為參數。sqrt 正是 “square root” 平方根的意思。
這個方法的回傳值是 3.0
。你可能會發現到這不只是 3
而已,還包括小數點。這是因為大多數的情況開根號不會剛好是整數,所以這個函數總是回傳浮點數。
如果我們想記住運算的結果呢? 指定到一個變數即可。
irb(main):007:0> a = 3 ** 2=> 9irb(main):008:0> b = 4 ** 2=> 16irb(main):009:0> Math.sqrt(a+b) => 5.0
儘管這是一個不錯的計算機,但我們將逐漸脫離基本的 Hello World
,讓我們繼續吧。
如果您想說很多次 “Hello”,卻不想敲太多按鍵。是時候定義一個方法了!
irb(main):010:0> def hirb(main):011:1> puts "Hello World!"irb(main):012:1> end=> nil
從 def h
開始定義一個方法。它告訴 Ruby 方法名字是 h
。下一行是方法的內容,也就是我們之前看過的 puts "Hello World"
。接著最後一行 end
表示方法定義結束。 Ruby 回應 => nil
告訴我們它知悉了這個方法定義。
這個簡短可以反覆執行的方法
現在來試試看執行這個方法數次:
irb(main):013:0> hHello World!=> nilirb(main):014:0> h()Hello World!=> nil
簡單吧。在 Ruby 中呼叫方法只要輸入方法名字就可以了。如果方法不需要參數,那麼括號可以省略。你也可以加上空括號,但不是必要的。
如果你只想對某個人打招呼呢? 只要重新定義 h
方法接受一個參數即可。
irb(main):015:0> def h(name)irb(main):016:1> puts "Hello #{name}!"irb(main):017:1> end=> nilirb(main):018:0> h("Matz")Hello Matz!=> nil
正如預期... 讓我們仔細看看到底發生什麼事情。
字串內嵌
什麼是 #{name}
啊? 這是 Ruby 用來在字串中插入資料的方式。大括號裡面的程式會被執行後變成一個字串,然後將整個大括號符號替換掉。例如,我們來把人名變成大寫:
irb(main):019:0> def h(name = "World")irb(main):020:1> puts "Hello #{name.capitalize}!"irb(main):021:1> end=> nilirb(main):022:0> h "chris"Hello Chris!=> nilirb(main):023:0> hHello World!=> nil
這裡還有幾個小訣竅。第一是我們再次省略了方法的括號。如果方法呼叫很簡單,那麼括號建議你可以省略掉。另一個訣竅是參數有預設值 World
。意思是說 “如果沒有給 name 參數,那麼就使用預設值 "World"
“。
發展成 Greeter (接待員)
如果我們需要一個接待員,可以記住你的名字,並且禮貌地歡迎你。你會開始需要使用物件(object)了。讓我們來建立 “Greeter” 類別(class)。
irb(main):024:0> class Greeterirb(main):025:1> def initialize(name = "World")irb(main):026:2> @name = nameirb(main):027:2> endirb(main):028:1> def say_hiirb(main):029:2> puts "Hi #{@name}!"irb(main):030:2> endirb(main):031:1> def say_byeirb(main):032:2> puts "Bye #{@name}, come back soon."irb(main):033:2> endirb(main):034:1> end=> nil
新的關鍵字是 class
。這定義了一個新的類別叫做 Greeter,以及屬於這個類別的方法。注意到 @name
這是一個實例變數,可以在類別裡面的方法中存取到。你可以看到在方法 say_hi
和 say_bye
裡使用了它。
如何讓 Greeter 類別動起來呢? 請接著看 建立物件。
讓我們建立一個 greeter 物件來使用:
irb(main):035:0> g = Greeter.new("Pat")=> #<Greeter:0x16cac @name="Pat">irb(main):036:0> g.say_hiHi Pat!=> nilirb(main):037:0> g.say_byeBye Pat, come back soon.=> nil
一旦建立了 g
物件,它就會記得它的名字是 Pat。嗯,但是我們如何拿到這個名字的值呢?
irb(main):038:0> g.@nameSyntaxError: compile error(irb):52: syntax error from (irb):52
啊,這樣不行。
揭開物件的面紗
物件中的實例變數(Instance variables)是隱藏的。雖然可以透過檢查(inspect)物件看到這個變數,不過 Ruby 採用了物件導向的思維(譯註: 即封裝),內部屬性資料基本上是隱藏起來的。
到底 Greeter 物件有哪些方法呢?
irb(main):039:0> Greeter.instance_methods=> ["method", "send", "object_id", "singleton_methods", "__send__", "equal?", "taint", "frozen?", "instance_variable_get", "kind_of?", "to_a", "instance_eval", "type", "protected_methods", "extend", "eql?", "display", "instance_variable_set", "hash", "is_a?", "to_s", "class", "tainted?", "private_methods", "untaint", "say_hi", "id", "inspect", "==", "===", "clone", "public_methods", "respond_to?", "freeze", "say_bye", "__id__", "=~", "methods", "nil?", "dup", "instance_variables", "instance_of?"]
哇。有這麼多。我們不是只定義了兩個方法,怎麼回事呢? 這裡列出的是所有Greeter 物件的方法,因此也包括了它所繼承的類別的方法。如果我們只需要 Greeter 自己的方法,可以傳入一個 false 參數,表示我們不希望包括父類別的方法。
irb(main):040:0> Greeter.instance_methods(false)=> ["say_bye", "say_hi"]
看起來好多了。讓我們看看 greeter 物件對哪些方法有反應?
irb(main):041:0> g.respond_to?("name")=> falseirb(main):042:0> g.respond_to?("say_hi")=> trueirb(main):043:0> g.respond_to?("to_s")=> true
它知道 say_hi
和 to_s
(意思是轉換成字串,這是每個物件都有的方法),但是不知道 name
這個方法。
變更類別,永不嫌晚
那麼要怎麼能夠讀取或修改名字呢? Ruby 提供了一個簡單的方式來讓你存取物件的變數:
irb(main):044:0> class Greeterirb(main):045:1> attr_accessor :nameirb(main):046:1> end=> nil
在 Ruby 裡你可以再度打開一個類別然後修改它。這個改變會對之後產生的物件,甚至是已經產生的物件產生即時效果。所以,我們來建立一個新的物件試試看 @name
屬性。
irb(main):047:0> g = Greeter.new("Andy")=> #<Greeter:0x3c9b0 @name="Andy">irb(main):048:0> g.respond_to?("name")=> trueirb(main):049:0> g.respond_to?("name=")=> trueirb(main):050:0> g.say_hiHi Andy!=> nilirb(main):051:0> g.name="Betty"=> "Betty"irb(main):052:0> g=> #<Greeter:0x3c9b0 @name="Betty">irb(main):053:0> g.name=> "Betty"irb(main):054:0> g.say_hiHi Betty!=> nil
attr_accessor
會定義兩個新的方法,name
用來取值,而 name=
用來給值。
可以歡迎任何東西的 MegaGreeter!
這個 greeter 玩膩了,它一次只能處理一個人。要如何能夠有 MegaGreeter 可以不只歡迎這個世界,還可以歡迎不同人,甚至是一群人呢?
接著讓我們開一個新檔案來撰寫 Ruby 程式吧,互動式的 IRB 不適合撰寫較長的程式。
要離開 IRB 請輸入 “quit” 或 “exit” 或按下 Control-D。
#!/usr/bin/env rubyclass MegaGreeter attr_accessor :names # 初始化這個物件 def initialize(names = "World") @names = names end # 向每個人說 hi def say_hi if @names.nil? puts "..." elsif @names.respond_to?("each") # @names 是可以迭代的陣列容器 @names.each do |name| puts "Hello #{name}!" end else puts "Hello #{@names}!" end end # 向每個人說 bye def say_bye if @names.nil? puts "..." elsif @names.respond_to?("join") # 用逗號將陣列中的元素串接成一個字串 puts "Goodbye #{@names.join(", ")}. Come back soon!" else puts "Goodbye #{@names}. Come back soon!" end endendif __FILE__ == $0 mg = MegaGreeter.new mg.say_hi mg.say_bye # 變更成 "Zeke" mg.names = "Zeke" mg.say_hi mg.say_bye # 變更成一個名字的陣列 mg.names = ["Albert", "Brenda", "Charles", "Dave", "Englebert"] mg.say_hi mg.say_bye # 變更成 nil mg.names = nil mg.say_hi mg.say_byeend
把這個檔案存成 “ri20min.rb”,然後輸入 “ruby ri20min.rb” 來執行它。您應該可以看到輸出是:
Hello World!Goodbye World. Come back soon!Hello Zeke!Goodbye Zeke. Come back soon!Hello Albert!Hello Brenda!Hello Charles!Hello Dave!Hello Englebert!Goodbye Albert, Brenda, Charles, Dave, Englebert. Comeback soon!......
這個最後的範例有許多新東西,讓我們來仔細瞧瞧。
我們來深入看看這個新程式。注意到由井號(#)開頭的第一行,在 Ruby 裡,任何在井號之後的內容都是註解,會被直譯器忽略。除了檔案的第一行是個例外,在 Unix-like 作業系統下這告訴 Shell 如何執行這個檔案。其餘的註解則用來說明程式。
我們的 say_hi
方法也改變了:
# 對每個人說 hidef say_hi if @names.nil? puts "..." elsif @names.respond_to?("each") # @names 是可以迭代的陣列容器 @names.each do |name| puts "Hello #{name}!" end else puts "Hello #{@names}!" endend
它現在會根據 @names
參數的不同而有不同的行為。如果是 nil,它會輸出三個點。沒必要對空氣打招呼,對吧?
循環、迴圈,迭代 (Iteration)
如果 @names
物件可以回應 each
方法,那表示你可以迭代它,好讓我們輪流對其中的元素打招呼。如果 @names
什麼都不是,我們透過字串內嵌把它轉化成字串,用預設的打招呼方式。
下面來看一看這是怎麼迭代的:
@names.each do |name| puts "Hello #{name}!"end
each
是一個可以接受程式區塊(a block of code)的方法,它會對 @names
裡的每個元素執行這個程式區塊,也就是從 do
到 end
的程式碼。一個程式區塊就像是一個匿名方法,也像是 lambda
。而在直線 |
符號之間的是這個程式區塊的參數。
具體來說就是,程式區塊裡的 name
參數會被輪流指定為容器裡的每個元素,然後執行 puts "Hello #{name}!"
。
大多數的程式語言會用 for
迴圈來做這件事情,例如在 C 裡面:
for (i=0; i<number_of_elements; i++){ do_something_with(element[i]);}
這樣也行,只是沒這麼漂亮。你需要一個用過即丟的 i
變數、需要計算容器的長度、檢查離開迴圈的條件。而 Ruby 的方式漂亮多了,所有的工作都被包裝在each
方法裡。在 each
內部會去輪流呼叫 yield "Albert"
、yield "Brenda"
、yield "Charles"
等等。(譯註:yield 的意思是”轉交”,也就是跳去執行程式區塊)
讓 Ruby 發光發亮的程式區塊(Blocks)
程式區塊真正厲害的地方是,它可以處理比迭代更複雜的任務。你可以用來設定(setup)、卸載(teardown)和錯誤處理,這些都可以隱藏起來讓方法使用者無需擔心。
# 向每個人說 byedef say_bye if @names.nil? puts "..." elsif @names.respond_to?("join") # 用逗號將陣列中的元素串接成一個字串 puts "Goodbye #{@names.join(", ")}. Come back soon!" else puts "Goodbye #{@names}. Come back soon!" endend
say_bye
方法沒有用到 each
,而是檢查 @names
@ 是不是可以回應 join
方法。如果可以,就呼叫它。不然它就把它當做字串輸出。這個方法並不在乎變數真正的型別(type),而只關心變數是不是可以回應支援某個方法,這種風格叫做 “鴨子型別(Duck Typing)”,意義就是 “如果它走起來像鴨子,叫起來也像鴨子,那就當它是鴨子”。這種思維的好處是它不會被變數的型別所限制。如果有人寫了新的容器類別,並且也實作了 join
這個方法,那麼我們就可以在這裡使用它。
讓腳本跑起來
這就是 MegaGreeter 類別了。剩下的部份是就是使用這個類別而已。唯一要注意的技巧是以下這行:
if __FILE__ == $0
__FILE__
是一個預先定義好的變數,內容是目前這個檔案的名稱。而 $0
是執行這隻程式的執行檔名稱。這個檢查是說 “如果這個檔案就是執行程式的檔案....”。這可以允許將這個檔案當做方法庫使用。也就是說,這個檔案如果當做方法庫使用時,不會執行這段程式。如果當做執行檔執行,就會執行這段程式。
就這樣啦
這就是二十分鐘的 Ruby 入門體驗了。還有許多值得探索的地方,例如不同的控制結構、如何使用程式區塊及 yield
、模組(modules)的第二個用途 mixin 等等。希望這份體驗教學讓你有興趣繼續學習。
如果你希望進一步了解,歡迎前往我們的 文件,那裡提供了一些免費的線上文件和導覽。
或是你希望找本書,請參考看看 書籍清單 (外部連結),或是你本地的書店。
- 二十分鐘 Ruby 體驗(转载)
- 初遇Ruby,觉得十分亲切
- 十分实用的手机小常识!(转载)
- 十分
- [ 转载 ] 為什麼 Ruby
- [转载]ruby 动态性
- 一个十分有趣的字符串算法, 转载留个记号
- (转载)网络流算法,十分清晰易懂
- Programming Ruby 读书笔记(二)
- ruby学习笔记二
- Ruby 语法(二)
- Ruby 教程(二)
- Ruby语言 (二)
- ruby 学习笔记(二)
- ruby基础 二
- Ruby 基础 (二)
- 开始用ruby,转载一篇
- 二十分钟Ruby入门
- Windows 8 数学输入板
- android-opencv【 undefined reference to 】
- 扫雷__重绘优化与数据持久化
- Android 4.1 Netd详细分析(二)源文件/模块/基础类统领
- XNA in Silverlight 5.0
- 二十分鐘 Ruby 體驗(转载)
- WINCE change static IP address
- Windows 8 安全功能
- UML类图关系大全
- linux基础编程:进程通信之信号
- Oracle .CURRVAL NEXTVAL 用法
- undefined reference to 问题解决方法
- 进制的快速转换
- HTTP POST GET 本质区别详解