二十分鐘 Ruby 體驗(转载)

本文通过互动式Ruby环境IRB,引导读者快速掌握Ruby的基础语法,包括基本运算、字符串操作、方法定义与调用、类和对象的创建等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: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
=> 9
irb(main):008:0> b = 4 ** 2
=> 16
irb(main):009:0> Math.sqrt(a+b) => 5.0

儘管這是一個不錯的計算機,但我們將逐漸脫離基本的 Hello World讓我們繼續吧

如果您想說很多次 “Hello”,卻不想敲太多按鍵。是時候定義一個方法了!

irb(main):010:0> def h
irb(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> h
Hello World!
=> nil
irb(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
=> nil
irb(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
=> nil
irb(main):022:0> h "chris"
Hello Chris!
=> nil
irb(main):023:0> h
Hello World!
=> nil

這裡還有幾個小訣竅。第一是我們再次省略了方法的括號。如果方法呼叫很簡單,那麼括號建議你可以省略掉。另一個訣竅是參數有預設值 World。意思是說 “如果沒有給 name 參數,那麼就使用預設值 "World"“。

發展成 Greeter (接待員)

如果我們需要一個接待員,可以記住你的名字,並且禮貌地歡迎你。你會開始需要使用物件(object)了。讓我們來建立 “Greeter” 類別(class)。

irb(main):024:0> class Greeter
irb(main):025:1>   def initialize(name = "World")
irb(main):026:2>     @name = name
irb(main):027:2>   end
irb(main):028:1>   def say_hi
irb(main):029:2>     puts "Hi #{@name}!"
irb(main):030:2>   end
irb(main):031:1>   def say_bye
irb(main):032:2>     puts "Bye #{@name}, come back soon."
irb(main):033:2>   end
irb(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_hi
Hi Pat!
=> nil
irb(main):037:0> g.say_bye
Bye Pat, come back soon.
=> nil

一旦建立了 g 物件,它就會記得它的名字是 Pat。嗯,但是我們如何拿到這個名字的值呢?

irb(main):038:0> g.@name
SyntaxError: 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")
=> false
irb(main):042:0> g.respond_to?("say_hi")
=> true
irb(main):043:0> g.respond_to?("to_s")
=> true

它知道 say_hi 和 to_s (意思是轉換成字串,這是每個物件都有的方法),但是不知道 name 這個方法。

變更類別,永不嫌晚

那麼要怎麼能夠讀取或修改名字呢? Ruby 提供了一個簡單的方式來讓你存取物件的變數:

irb(main):044:0> class Greeter
irb(main):045:1>   attr_accessor :name
irb(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")
=> true
irb(main):049:0> g.respond_to?("name=")
=> true
irb(main):050:0> g.say_hi
Hi Andy!
=> nil
irb(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_hi
Hi Betty!
=> nil

attr_accessor 會定義兩個新的方法,name 用來取值,而 name= 用來給值。

可以歡迎任何東西的 MegaGreeter!

這個 greeter 玩膩了,它一次只能處理一個人。要如何能夠有 MegaGreeter 可以不只歡迎這個世界,還可以歡迎不同人,甚至是一群人呢?

接著讓我們開一個新檔案來撰寫 Ruby 程式吧,互動式的 IRB 不適合撰寫較長的程式。

要離開 IRB 請輸入 “quit” 或 “exit” 或按下 Control-D。

#!/usr/bin/env ruby

class 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
  end

end


if __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_bye
end

把這個檔案存成 “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.  Come
back soon!
...
...

這個最後的範例有許多新東西,讓我們來仔細瞧瞧

我們來深入看看這個新程式。注意到由井號(#)開頭的第一行,在 Ruby 裡,任何在井號之後的內容都是註解,會被直譯器忽略。除了檔案的第一行是個例外,在 Unix-like 作業系統下這告訴 Shell 如何執行這個檔案。其餘的註解則用來說明程式。

我們的 say_hi 方法也改變了:

# 對每個人說 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

它現在會根據 @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)和錯誤處理,這些都可以隱藏起來讓方法使用者無需擔心。

# 向每個人說 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
end

say_bye 方法沒有用到 each,而是檢查 @names@ 是不是可以回應 join 方法。如果可以,就呼叫它。不然它就把它當做字串輸出。這個方法並不在乎變數真正的型別(type),而只關心變數是不是可以回應支援某個方法,這種風格叫做 “鴨子型別(Duck Typing)”,意義就是 “如果它走起來像鴨子,叫起來也像鴨子,那就當它是鴨子”。這種思維的好處是它不會被變數的型別所限制。如果有人寫了新的容器類別,並且也實作了 join 這個方法,那麼我們就可以在這裡使用它。

讓腳本跑起來

這就是 MegaGreeter 類別了。剩下的部份是就是使用這個類別而已。唯一要注意的技巧是以下這行:

if __FILE__ == $0

__FILE__ 是一個預先定義好的變數,內容是目前這個檔案的名稱。而 $0 是執行這隻程式的執行檔名稱。這個檢查是說 “如果這個檔案就是執行程式的檔案....”。這可以允許將這個檔案當做方法庫使用。也就是說,這個檔案如果當做方法庫使用時,不會執行這段程式。如果當做執行檔執行,就會執行這段程式。

就這樣啦

這就是二十分鐘的 Ruby 入門體驗了。還有許多值得探索的地方,例如不同的控制結構、如何使用程式區塊及 yield、模組(modules)的第二個用途 mixin 等等。希望這份體驗教學讓你有興趣繼續學習。

如果你希望進一步了解,歡迎前往我們的 文件,那裡提供了一些免費的線上文件和導覽。

或是你希望找本書,請參考看看 書籍清單 (外部連結),或是你本地的書店。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值