Skip to content

Ruby 方法

Ruby 方法是执行特定任务的代码块。它们类似于其他编程语言中的函数,用于将一个或多个可重复的语句打包成一个单元,从而提高代码的可重用性和组织性。

按照约定,方法名称应以小写字母或下划线开头。如果方法名称以大写字母开头,Ruby 可能会将其解释为常量,从而导致解析错误。

方法必须先定义后调用;否则,Ruby 将引发 NoMethodError 异常。

def method_name(parameter1, parameter2, ...)
# 表达式(方法体)
# ...
end

一个没有参数的简单方法:

#!/usr/bin/env ruby
def greet
puts "Hello, Ruby!"
end

一个带参数的方法:

#!/usr/bin/env ruby
def personalize_greeting(name)
puts "Hello, #{name}!"
end

您可以为参数设置默认值。如果在调用方法时没有为这些参数提供实参 (arguments),则使用这些默认值。

#!/usr/bin/env ruby
def greet_with_default(name = "World")
puts "Hello, #{name}!"
end
greet_with_default # 输出: Hello, World!
greet_with_default("Alice") # 输出: Hello, Alice!

要调用方法,只需使用其名称即可。如果方法需要实参 (arguments),则提供它们。

#!/usr/bin/env ruby
def say_hello
puts "Hello!"
end
def add(a, b)
puts a + b
end
# 调用方法
say_hello # 如果没有实参,可以不使用括号调用
add(5, 3) # 使用实参调用
add 10, 20 # 在不引起歧义的情况下,括号通常是可选的

如果一个方法需要特定数量的实参,而您使用不同数量的实参调用它,Ruby 将引发 ArgumentError 异常。

#!/usr/bin/env ruby
def favorite_languages(lang1 = "Ruby", lang2 = "Python")
puts "My favorite programming language is #{lang1}."
puts "My second favorite is #{lang2}."
end
favorite_languages("JavaScript", "Go") # 使用提供的实参
puts "---"
favorite_languages("Rust") # lang1 是 "Rust",lang2 使用默认值 "Python"
puts "---"
favorite_languages # 使用两个默认值

这将产生:

My favorite programming language is JavaScript.
My second favorite is Go.
---
My favorite programming language is Rust.
My second favorite is Python.
---
My favorite programming language is Ruby.
My second favorite is Python.

Ruby 中的每个方法都隐式返回其方法体中最后一个求值表达式的值。

#!/usr/bin/env ruby
def simple_calculator(a, b)
sum = a + b
difference = a - b
difference # 这是最后一个求值表达式,因此它被返回
end
result = simple_calculator(10, 4)
puts "Result (difference): #{result}" # 输出: Result (difference): 6

return 语句可用于显式退出方法并返回一个或多个值。如果 return 没有带表达式使用,它将返回 nil。如果提供了多个表达式,return 将返回一个包含这些值的数组。

return
return expression
return expr1, expr2, expr3
#!/usr/bin/env ruby
def get_coordinates
x = 10
y = 20
z = 30
return x, y, z # 返回一个数组 [10, 20, 30]
end
def get_status(code)
return "OK" if code == 200
return "Error" # 如果 code 不是 200,则隐式返回 "Error"
end
coords = get_coordinates
puts "Coordinates: #{coords.inspect}" # 输出: Coordinates: [10, 20, 30]
status_ok = get_status(200)
puts "Status for 200: #{status_ok}" # 输出: Status for 200: OK
status_err = get_status(404)
puts "Status for 404: #{status_err}" # 输出: Status for 404: Error

可变数量的参数(Splat 运算符)

Section titled “可变数量的参数(Splat 运算符)”

Ruby 允许方法使用 splat 运算符 (*) 接受可变数量的实参。当在方法定义中使用时,* 将任何剩余的实参收集到一个数组中。

#!/usr/bin/env ruby
def display_items(category, *items)
puts "Category: #{category}"
puts "Number of items: #{items.length}"
items.each_with_index do |item, index|
puts " Item #{index + 1}: #{item}"
end
end
display_items("Fruits", "Apple", "Banana", "Orange")
puts "---"
display_items("Colors", "Red", "Green")
puts "---"
display_items("Tools") # items 将是一个空数组

这将产生:

Category: Fruits
Number of items: 3
Item 1: Apple
Item 2: Banana
Item 3: Orange
---
Category: Colors
Number of items: 2
Item 1: Red
Item 2: Green
---
Category: Tools
Number of items: 0

Ruby 方法也可以接受关键字参数,这些参数在调用方法时通过名称指定。这可以使方法调用更具可读性,尤其是在参数或布尔标志很多的情况下。

#!/usr/bin/env ruby
def create_user(name:, email:, admin: false, notify: true)
puts "Creating user: #{name}"
puts "Email: #{email}"
puts "Admin: #{admin}"
puts "Notify: #{notify}"
# ... 创建用户的逻辑 ...
end
create_user(name: "Alice", email: "alice@example.com")
puts "---"
create_user(name: "Bob", email: "bob@example.com", admin: true, notify: false)
# 使用双 splat (**) 处理任意数量的关键字参数
def process_options(user_id, **options)
puts "Processing for user: #{user_id}"
options.each do |key, value|
puts " Option #{key}: #{value}"
end
end
process_options(101, theme: "dark", layout: "compact", show_help: true)

类方法是定义在类本身上的方法,而不是定义在类的实例上。它们通常用于工厂方法或与类相关的工具函数。

您可以通过在类定义中将方法名称前加上 self. 或类本身名称来定义类方法。

#!/usr/bin/env ruby
class Utility
# 实例方法
def instance_method
puts "This is an instance method."
end
# 使用 self. 定义的类方法
def self.class_method_one
puts "This is class_method_one."
end
# 使用类名定义的类方法
def Utility.class_method_two
puts "This is class_method_two."
end
end
# 直接在类上调用类方法
Utility.class_method_one
Utility.class_method_two
# 要调用实例方法,您需要一个实例
util_instance = Utility.new
util_instance.instance_method

默认情况下,在类内部定义的方法是公共的 (public)。在顶层(任何类或模块之外)定义的方法将成为 Object 类的私有实例方法。

alias 关键字为现有方法或全局变量创建一个别名。不能在方法体内部定义别名。当一个方法被赋予别名时,该别名指向该方法在别名创建时的定义,即使原始方法后来被覆盖也是如此。

alias_method 是一个方法(通常在类/模块内部使用),它为方法实现相同的功能,因其灵活性(例如,它可以接受符号或字符串作为实参)而常被优先使用。

alias new_method_name old_method_name
alias new_global_variable_name old_global_variable_name
# 在类/模块内部:
alias_method :new_method_name, :old_method_name
#!/usr/bin/env ruby
class Greeter
def welcome(name)
"Hello, #{name}!"
end
alias_method :greet, :welcome # 为实例方法创建别名
end
my_greeter = Greeter.new
puts my_greeter.welcome("Original")
puts my_greeter.greet("Alias")
$global_var = "Initial Global"
alias $gvar $global_var # 为全局变量创建别名
puts $gvar

禁止为内置的编号全局变量(如 $1, $2)创建别名。覆盖核心全局变量可能导致意外行为。

undef 关键字取消方法的定义,使其不再可调用。它不能出现在方法体内部。

undef_method 是其基于方法对应的版本,通常在类/模块内部使用。

undef method_name
# 在类/模块内部:
undef_method :method_name
#!/usr/bin/env ruby
class Calculator
def add(a, b)
a + b
end
def subtract(a, b)
a - b
end
end
calc = Calculator.new
puts calc.add(5, 3) # 输出: 8
class Calculator
undef_method :add # 取消定义 'add' 方法
end
# calc.add(7, 2) # 现在这将引发 NoMethodError 异常
puts calc.subtract(10, 4) # 输出: 6

使用 undef 和 alias 可以修改类的接口,可能独立于其超类 (superclass)。但是,必须小心,因为如果方法被取消定义,类内部调用 self 的方法可能会失效。