跳至主要内容

[Ruby] 方法/函式(function / method)

實例方法

##
# 檢驗 object 中是否包含某一 method
# [object].respond_to?(:[method])
# 也可以不加冒號用引號寫 Obj.respond_to?('[method]')
##
Obj.respond_to?(:next)
Obj.class.respond_to?([method]) # 檢驗某個 obj 的 class 是否包含某 class method
defined? (methods) # 註1

# 檢驗 object 是否為 nil
arr.nil? # [object].nil?

# 檢驗物件類型
:hello.is_a? Symbol # true,[object].is_a? String/Integer/Symbol
:hello.class # Symbol,[object].class

##
# 找出某一物件內的方法來源(註2, 註3)
# 也可以不加冒號用引號寫 Obj.method('methodName')
##
Obj.method(:methodName)

類別方法

[Class].methods    # 列出物件內的所有方法

觀念

implicit return(自動回傳)

在 Ruby 中方法如果沒有寫 return 則會自動回傳方法中最後的表達式。

# method 會自動以 string 的格式 return(implicit return)
def add(a, b)
a+b
end
puts add(3, 5) # 8

命名慣例

在 Ruby 中函式(function)就是方法(method),命名的開頭一般是小寫(也可以是 _ 或數字);結尾可以是?(問號,question)或!(驚嘆號,bang,exclamation)或=(等號,equal)。

一般來說(慣例):

  • 結尾如果是,執行方式和一般方法沒有差別,但通常用!結尾,表示會有「副作用」,例如,這個方法會改變原本的變數值,同時也表示它會有一個相對應不會改變原本變數值的方法。
  • 結尾如果是,這個方法經常會回傳表示 true 或 false 的物件。
  • 結尾如果是,表示這個方法是指派方法(assignment method),在 assignment method 中,函式中的回傳值會被忽略,而是自動回傳參數的值。
# bang, exclamation, 驚嘆號:表示有副作用
a = "Hello everyone"
a.upcase # 沒有驚嘆號,不會改變原本變數的值
puts a # "Hello everyone"
a.upcase! # 有驚嘆號,會改變原本變數的值
puts a # "HELLO EVERYONE"

# question mark,問號:表示回傳 Boolean
a = "Hello everyone"
puts a.nil? # false
puts a.empty? # false

# equal,等號,回傳值會被忽略,直接回傳參數值
def a=
return 3
end

puts a= "Hello", 7

建立方法(method)

建立帶有參數的方法

建立一般的方法

def add(a, b)
puts "{#a} + {#b} is {#a+b}"
end

建立帶有參數預設值的方法

方法內可以定義參數預設值,預設值不一定要放在最前面或最後面,但是必須是組在一起的:

def add_values(a = 2, b)
a + b
end
p add_values 3 # 5

def add_values(a, b = 4)
a + b
end
p add_values 3 # 7

為物件直接新增方法

greeting = "Hello "
def greeting.sayhi(name)
puts self + name
end
greeting.sayhi("Mark") # Hello Mark

建立具有具名參數的方法(named parameter, keyword arguments)

在定義 function 的參數時使用 : 可以達到具名參數的作用, [變數名稱]:[變數預設值] ,一旦對應到相同的名稱,就可以直接使用:

# 使用 : 定義具名參數
def select_options(selected = nil, disabled: nil, prompt: nil)
puts prompt # 可以直接取得具名參數的值,'this is prompt'
puts disabled # 可以直接取得具名參數的值,'disabled'
end

# 使用時可以透過 Hash 的方式帶入參數
select_options(1, prompt: 'this is prompt', disabled: 'disabled')

呼叫方法

可省略括號()

<%= link_to '刪除', user, method: :delete, data: { confirm: 'sure?' }, class:'btn' %>
<%= link_to ('刪除', user, method: :delete, data: { confirm: 'sure?' }, class:'btn') % # 括號可以省略
<%= link_to('刪除', user, {method: :delete, data: { confirm: 'sure?' }, class:'btn'}) %>> # 最後一個參數是 hash 時也可省略大括號

最後一個參數如果是 hash 可省略大括號

方法的最後一個參數如果是 hash 的話可以省略大括號

這是因為如果第一個參數放 hash 的話,它無法辨識那是 block 或是 hash;如果放在中間,它無法辨識那是一個 {age: 18},還是 {age: 18, favorite: ruby}

def say_hello_to(name, options = {})
"Hello, #{name}. Your age is #{options[:age]}. Your favorite programming language is #{options[:favorite]}"
end

say_hello_to "Eddie", {age: 18, favorite: 'ruby'}
say_hello_to "Eddie", age: 18, favorite: 'ruby' # 省略大括號

參數解構(decomposition)

#########################
# 陣列解構賦值 ##
#########################

# 可以在參數的地方多包一個括號來解構陣列
def arr_decompo((a, b))
p a: a, b: b
end
arr_decompo([1,2]) # 回傳 {:a=>1, :b=>2}

# 如果參數的地方所給予的陣列元素超過參數數目,則會自動省略
def arr_decompo((a, b))
puts a: a, b: b
end
arr_decompo([1,2,3]) # 回傳 {:a=>1, :b=>2}

# splat arguments:可以使用*來將多餘的陣列元素轉為陣列
def arr_decompo((a, *b))
puts a: a, b: b # 回傳 {:a=>1, :b=>2}
end
arr_decompo([1,2,3]) # 回傳 {:a=>1, :b=>[2, 3]}

特殊情況

# 當定義同樣名稱的方法時,原本的方法會被覆蓋(overriding)

puts "3".to_i # 3
class String
def to_i
"6"
end
end
puts "3".to_i # 6

# 當定義同樣名稱的變數和方法時,會以區域變數優先

age = 18

def age
puts 20
end

age # 18(以區域變數優先)
age() # 20

參考資料