博客 / 詳情

返回

Y分鐘速成ruby

源代碼下載: learnruby-zh.rb

# 這是單行註釋

=begin
這是多行註釋
=end

# 在 Ruby 中,(幾乎)所有東西都是對象

# 數字是對象
3.class #=> Integer
3.to_s #=> "3"

# 字符串是對象
"Hello".class #=> String

# 甚至方法也是對象
"Hello".method(:class).class #=> Method

# 一些基本的算術操作
1 + 1   #=> 2
8 - 1   #=> 7
10 * 2  #=> 20
35 / 5  #=> 7
2 ** 5  #=> 32
5 % 3   #=> 2

# 位運算符
3 & 5 #=> 1
3 | 5 #=> 7
3 ^ 5 #=> 6

# 算術符號只是語法糖而已
# 實際上是調用對象的方法
1.+(3) #=> 4
10.* 5 #=> 50 
100.methods.include?(:/) #=> true

# 特殊的值也是對象
nil # 相當於其它語言中的 null
true # 真
false # 假

nil.class #=> NilClass
true.class #=> TrueClass
false.class #=> FalseClass

# 相等運算符
1 == 1 #=> true
2 == 1 #=> false

# 不相等運算符
1 != 1 #=> false
2 != 1 #=> true

# 除了 false 自己,nil 是唯一的另一個值為 false 的對象
!!nil   #=> false
!!false #=> false
!!0     #=> true
!!""    #=> true

# 更多比較
1 < 10 #=> true
1 > 10 #=> false
2 <= 2 #=> true
2 >= 2 #=> true


# 組合比較運算符
1 <=> 10 #=> -1
10 <=> 1 #=> 1
1 <=> 1 #=> 0

# 邏輯運算符
true && false #=> false
true || false #=> true
!true #=> false

# 也有優先級更低的邏輯運算符
# 它們用於控制流結構中,用來串接語句,直到返回 true 或 false。

# `do_something_else` 只當 `do_something` 返回 true 時才會被調用
do_something() and do_something_else()
# `log_error` 只當 `do_something` 返回 false 時才會被調用
do_something() or log_error()


# 字符串是對象

'I am a string'.class #=> String
"I am a string too".class #=> String

placeholder = "use string interpolation"
"I can #{placeholder} when using double quoted strings"
#=> "I can use string interpolation when using double quoted strings"

# 儘可能優先使用單引號的字符串
# 雙引號的字符串會進行一些額外的內部處理

# 合併字符串,但不能和數字合併
'hello ' + 'world'  #=> "hello world"
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
'hello ' + 3.to_s #=> "hello 3"
"hello #{3}" #=> "hello 3"

# 合併字符串及其運算符
'hello ' * 3 #=> "hello hello hello "

# 字符串追加
'hello' << ' world' #=> "hello world"

# 打印輸出,並在末尾加換行符
puts "I'm printing!"
#=> I'm printing!
#=> nil

# 打印輸出,不加換行符
print "I'm printing!"
#=> I'm printing! => nil

# 變量
x = 25 #=> 25
x #=> 25

# 注意賦值語句返回了賦的值
# 這意味着你可以用多重賦值語句

x = y = 10 #=> 10
x #=> 10
y #=> 10

# 按照慣例,使用類似 snake_case 風格的變量名
snake_case = true

# 使用有意義的變量名
path_to_project_root = '/good/name/'
path = '/bad/name/'

# 符號(Symbols,也是對象)
# 符號是不可變的,內部用整數值表示的可重用的常數
# 通常用它代替字符串來有效地表示有意義的值

:pending.class #=> Symbol

status = :pending

status == :pending #=> true

status == 'pending' #=> false

status == :approved #=> false

# 數組

# 這是一個數組
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]

# 數組可以包含不同類型的元素

[1, "hello", false] #=> [1, "hello", false]

# 數組可以被索引
# 從前面開始
array[0] #=> 1
array.first #=> 1
array[12] #=> nil

# 像運算符一樣,[var] 形式的訪問
# 也只是語法糖
# 實際上是調用對象的 [] 方法
array.[] 0 #=> 1
array.[] 12 #=> nil

# 從尾部開始
array[-1] #=> 5
array.last #=> 5

# 同時指定開始的位置和長度
array[2, 3] #=> [3, 4, 5]

# 或者指定一個區間
array[1..3] #=> [2, 3, 4]

# 將數組逆序
a=[1,2,3]
a.reverse! #=> [3,2,1]

# 像這樣往數組增加一個元素
array << 6 #=> [1, 2, 3, 4, 5, 6]
# 或者像這樣
array.push(6) #=> [1, 2, 3, 4, 5, 6]

# 檢查元素是否包含在數組中
array.include?(1) #=> true

# 哈希表是 Ruby 的主要鍵/值對錶示法
# 哈希表由大括號表示
hash = {'color' => 'green', 'number' => 5}

hash.keys #=> ['color', 'number']

# 哈希表可以通過鍵快速地查詢
hash['color'] #=> 'green'
hash['number'] #=> 5

# 查詢一個不存在的鍵將會返回nil
hash['nothing here'] #=> nil

# 從 Ruby 1.9 開始,用符號作為鍵的時候有特別的記號表示:

new_hash = { defcon: 3, action: true }

new_hash.keys #=> [:defcon, :action]

# 檢查鍵值是否存在
hash.key?(:defcon) #=> true
hash.value?(3) #=> true

# 小貼士:數組和哈希表都是可枚舉的
# 它們共享一些有用的方法,比如 each, map, count 等等

# 控制流

if true
  "if statement"
elsif false
 "else if, optional"
else
 "else, also optional"
end

# 循環

for counter in 1..5
  puts "iteration #{counter}"
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5


# 但是,沒有人用 for 循環。
# 你應該使用 "each" 方法,然後再傳給它一個塊。
# 所謂塊就是可以傳給像 "each" 這樣的方法的代碼段。
# 它類似於其它語言中的 lambdas, 匿名函數或閉包。
#
# 區間上的 "each" 方法會對區間中的每個元素運行一次塊代碼。
# 我們將 counter 作為一個參數傳給了塊。
# 調用帶有塊的 "each" 方法看起來如下:

(1..5).each do |counter|
  puts "iteration #{counter}"
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5

# 你也可以將塊包含在一個大括號中:
(1..5).each { |counter| puts "iteration #{counter}" }

# 數據結構中的內容也可以使用each來遍歷。
array.each do |element|
  puts "#{element} is part of the array"
end
hash.each do |key, value|
  puts "#{key} is #{value}"
end

# 如果你還需要索引值,可以使用 "each_with_index",並且定義
# 一個索引變量
array.each_with_index do |element, index|
  puts "#{element} is number #{index} in the array"
end

counter = 1
while counter <= 5 do
  puts "iteration #{counter}"
  counter += 1
end
#=> iteration 1
#=> iteration 2
#=> iteration 3
#=> iteration 4
#=> iteration 5

# Ruby 中還有很多有用的循環遍歷函數,
# 如 "map", "reduce", "inject" 等等。
# 以map為例,它會遍歷數組,並根據你在
# 塊中定義的邏輯對它進行處理,然後返回
# 一個全新的數組。
array = [1,2,3,4,5]
doubled = array.map do |element|
  element * 2
end
puts doubled
#=> [2,4,6,8,10]
puts array
#=> [1,2,3,4,5]

grade = 'B'

case grade
when 'A'
  puts "Way to go kiddo"
when 'B'
  puts "Better luck next time"
when 'C'
  puts "You can do better"
when 'D'
  puts "Scraping through"
when 'F'
  puts "You failed!"
else 
  puts "Alternative grading system, eh?"
end
#=> "Better luck next time"

# case也可以用區間
grade = 82
case grade
when 90..100
  puts 'Hooray!'
when 80...90
  puts 'OK job'
else
  puts 'You failed!'
end
#=> "OK job"

# 異常處理:
begin
  # 這裏的代碼可能會拋出異常
  raise NoMemoryError, 'You ran out of memory.'
rescue NoMemoryError => exception_variable
  puts 'NoMemoryError was raised', exception_variable
rescue RuntimeError => other_exception_variable
  puts 'RuntimeError was raised now'
else
  puts 'This runs if no exceptions were thrown at all'
ensure
  puts 'This code always runs no matter what'
end

# 函數

def double(x)
  x * 2
end

# 函數 (以及所有的塊) 隱式地返回最後語句的值
double(2) #=> 4

# 當不存在歧義的時候括號是可有可無的
double 3 #=> 6

double double 3 #=> 12

def sum(x,y)
  x + y
end

# 方法的參數通過逗號分隔
sum 3, 4 #=> 7

sum sum(3,4), 5 #=> 12

# yield
# 所有的方法都有一個隱式的,可選的塊參數
# 可以用 'yield' 關鍵字調用

def surround
  puts "{"
  yield
  puts "}"
end

surround { puts 'hello world' }

# {
# hello world
# }
# => nil

# 可以向函數傳遞一個塊
# "&"標記傳遞的塊是一個引用
def guests(&block)
  block.class #=> Proc
  block.call(4)
end

guests { |n| "You have #{n} guests." }
# => "You have 4 guests."

# 可以傳遞多個參數,這些參數會轉成一個數組,
# 這也是使用星號符 ("*") 的原因:
def guests(*array)
  array.each { |guest| puts guest }
end

# 結構

# 如果函數返回一個數組,在賦值時可以進行拆分:
def foods
    ['pancake', 'sandwich', 'quesadilla']
end
breakfast, lunch, dinner = foods
breakfast #=> 'pancake'
dinner #=> 'quesadilla'

# 有些情況下,你會想使用解構操作符 `*` 來解構數組
ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"]

def best(first, second, third)
  puts "Winners are #{first}, #{second}, and #{third}."
end

best *ranked_competitors.first(3) #=> Winners are John, Sally, and Dingus.

# 結構操作符也可放在參數裏面
def best(first, second, third, *others)
  puts "Winners are #{first}, #{second}, and #{third}."
  puts "There were #{others.count} other participants."
end

best *ranked_competitors 
#=> Winners are John, Sally, and Dingus.
#=> There were 2 other participants.

# 按照慣例,所有返回布爾值的方法都以 ? 結尾
5.even? # false
5.odd? # true

# 如果方法名末尾有感嘆號 !,表示會做一些破壞性的操作,比如修改調用者自身。
# 很多方法都會有一個 ! 的版本來進行修改,
# 和一個只返回更新結果的非 ! 版本
company_name = "Dunder Mifflin"
company_name.upcase #=> "DUNDER MIFFLIN"
company_name #=> "Dunder Mifflin"
# 這次我們修改了 company_name
company_name.upcase! #=> "DUNDER MIFFLIN"
company_name #=> "DUNDER MIFFLIN"

# 類

# 用 class 關鍵字定義一個類
class Human

  # 一個類變量,它被這個類的所有實例變量共享
  @@species = "H. sapiens"
  
  # 基本構造函數
  def initialize(name, age = 0)
    # 將參數值賦給實例變量 "name"
    @name = name
    # 如果沒有給出 age,那麼會採用參數列表中的默認值
    @age = age
  end
  
  # 基本的 setter 方法
  def name=(name)
    @name = name
  end
  
  # 基本地 getter 方法
  def name
    @name
  end
  
  # 以上的功能也可以用下面的 attr_accessor 來封裝
  attr_accessor :name
  
  # Getter/setter 方法也可以像這樣單獨創建
  attr_reader :name
  attr_writer :name
  
  # 類方法通過使用 self 與實例方法區別開來。
  # 它只能通過類來調用,不能通過實例調用。
  def self.say(msg)
    puts "#{msg}"
  end
  
  def species
    @@species
  end
end


# 初始化一個類
jim = Human.new("Jim Halpert")
dwight = Human.new("Dwight K. Schrute")

# 讓我們來調用一些方法
jim.species #=> "H. sapiens"
jim.name #=> "Jim Halpert"
jim.name = "Jim Halpert II" #=> "Jim Halpert II"
jim.name #=> "Jim Halpert II"
dwight.species #=> "H. sapiens"
dwight.name #=> "Dwight K. Schrute"

# 調用類方法
Human.say('Hi') #=> "Hi"

# 變量的作用域由它們的名字格式定義
# 以 $ 開頭的變量具有全局域
$var = "I'm a global var"
defined? $var #=> "global-variable"

# 以 @ 開頭的變量具有實例作用域
@var = "I'm an instance var"
defined? @var #=> "instance-variable"

# 以 @@ 開頭的變量具有類作用域
@@var = "I'm a class var"
defined? @@var #=> "class variable"

# 以大寫字母開頭的變量是常數
Var = "I'm a constant"
defined? Var #=> "constant"

# 類也是對象。因此類也可以有實例變量。
# 類變量在類以及其繼承者之間共享。

# 基類
class Human
  @@foo = 0

  def self.foo
    @@foo
  end

  def self.foo=(value)
    @@foo = value
  end
end

# 派生類
class Worker < Human
end

Human.foo # 0
Worker.foo # 0

Human.foo = 2 # 2
Worker.foo # 2

# 類實例變量不能在繼承類間共享。

class Human
  @bar = 0

  def self.bar
    @bar
  end

  def self.bar=(value)
    @bar = value
  end
end

class Doctor < Human
end

Human.bar # 0
Doctor.bar # nil

module ModuleExample
  def foo
    'foo'
  end
end

# '包含'模塊後,模塊的方法會綁定為類的實例方法
# '擴展'模塊後,模塊的方法會綁定為類方法

class Person
  include ModuleExample
end

class Book
  extend ModuleExample
end

Person.foo     # => NoMethodError: undefined method `foo' for Person:Class
Person.new.foo # => 'foo'
Book.foo       # => 'foo'
Book.new.foo   # => NoMethodError: undefined method `foo'

# 當包含或擴展一個模塊時,相應的回調代碼會被執行。
module ConcernExample
  def self.included(base)
    base.extend(ClassMethods)
    base.send(:include, InstanceMethods)
  end

  module ClassMethods
    def bar
      'bar'
    end
  end

  module InstanceMethods
    def qux
      'qux'
    end
  end
end

class Something
  include ConcernExample
end

Something.bar     # => 'bar'
Something.qux     # => NoMethodError: undefined method `qux'
Something.new.bar # => NoMethodError: undefined method `bar'
Something.new.qux # => 'qux'

其它資源

  • Learn Ruby by Example with Challenges - A variant of this reference with in-browser challenges.
  • An Interactive Tutorial for Ruby - Learn Ruby through a series of interactive tutorials.
  • Official Documentation
  • Ruby from other languages
  • Programming Ruby - An older free edition is available online.
  • Ruby Style Guide - A community-driven Ruby coding style guide.
  • Try Ruby - Learn the basic of Ruby programming language, interactive in the browser.

有建議?或者發現什麼錯誤?在Github上開一個issue,或者發起pull request!原著David Underwood,並由16個好心人修改。
Translated by: Lin Xiangyu Jiang Haiyun woclass
© 2022 David Underwood, Joel Walden, Luke Holder, Tristan Hume, Nick LaMuro, Marcos Brizeno, Ariel Krakowski, Dzianis Dashkevich, Levi Bostian, Rahil Momin, Gabriel Halley, Persa Zula, Jake Faris, Corey Ward, Jannik Siebert, Keith Miyake, lidashuang, ftwbzhao
本作品採用 CC BY-SA 3.0 協議進行許可。

user avatar peter-wilson 頭像 esunr 頭像 waweb 頭像 user_ze46ouik 頭像 gfeteam 頭像 tofrankie 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.