Ruby 方法参数与返回值
方法参数和返回值是 Ruby 中编写模块化和可复用代码的基础。它们定义了信息如何传递到方法中,以及处理结果如何发送回调用者。理解这些概念可以创建结构良好且易于维护的 Ruby 程序。
本章将深入探讨定义带参数方法的各项细节,涵盖不同类型的参数,以及如何高效地使用返回值。
1. 定义带参数的方法
方法可以接收参数,也就是在调用方法时传递给它的值。这些参数使得方法能够在每次被调用时处理不同的数据,从而极大地提升了代码的通用性。
1.1 基础参数
最简单的方法参数形式是必填参数。在定义方法时,你需要在方法名后面的括号内指定参数的名称。在调用该方法时,你必须为每一个参数提供对应的值。
# 定义一个名为 'greet' 的方法,它接收一个名为 'name' 的参数
def greet(name)
puts "你好,#{name}!"
end
# 调用 'greet' 方法,将字符串 "Alice" 作为 'name' 参数传递进去
greet("Alice") # 输出: 你好,Alice!
# 调用 'greet' 方法,将字符串 "Bob" 作为 'name' 参数传递进去
greet("Bob") # 输出: 你好,Bob!在这个例子中,greet 方法接收一个参数 name。当方法被调用时,作为参数传递的值会在该方法的作用域内被赋值给 name。
1.2 多个参数
方法可以接收多个参数。你只需要在方法定义中列出参数名,并用逗号隔开即可。
# 定义一个名为 'add' 的方法,接收两个参数 'x' 和 'y'
def add(x, y)
puts "总和是 #{x + y}"
end
# 调用 'add' 方法,将数字 5 和 3 分别作为 'x' 和 'y' 的参数传递进去
add(5, 3) # 输出: 总和是 8add 方法接收两个参数 x 和 y。调用方法时,第一个传入的值(5)赋给了 x,第二个传入的值(3)赋给了 y。
2. 默认参数
Ruby 允许你为方法参数指定默认值。如果调用者没有为带有默认值的参数提供具体的值,程序就会使用这个默认值。
# 定义一个名为 'power' 的方法,接收 'base' (底数) 和 'exponent' (指数) 两个参数。
# 'exponent' 参数拥有一个默认值 2。
def power(base, exponent=2)
puts "结果是 #{base ** exponent}"
end
# 仅用一个参数调用 'power' 方法。'exponent' 参数将采用其默认值 2。
power(3) # 输出: 结果是 9 (3 ** 2)
# 用两个参数调用 'power' 方法。'exponent' 参数将采用传入的值 3。
power(3, 3) # 输出: 结果是 27 (3 ** 3)在这里,如果没有提供 exponent 的值,它默认就是 2。
注意:在方法定义中,带有默认值的参数通常需要定义在必填参数的后面。
3. 可变参数 (*args)
有时,你可能需要编写一个能接收不定数量参数的方法。这可以通过使用星号操作符(Splat operator *)来实现。当在方法定义中使用时,星号操作符会将所有剩余的参数收集到一个数组(Array)中。
# 定义一个名为 'sum' 的方法,使用星号操作符 (*numbers) 接收可变数量的参数。
def sum(*numbers)
total = 0
numbers.each { |number| total += number }
puts "总和是 #{total}"
end
# 使用不同数量的参数调用 'sum' 方法。
sum(1, 2, 3) # 输出: 总和是 6
sum(1, 2, 3, 4, 5) # 输出: 总和是 15
sum() # 输出: 总和是 0在这个例子中,*numbers 将传递给 sum 的所有参数收集到一个名为 numbers 的数组中。然后方法遍历这个数组来计算总和。
4. 关键字参数
关键字参数允许你通过指定参数名的方式来传递参数。这可以极大地提高代码的可读性,特别是当一个方法包含很多参数时。在方法定义中,关键字参数是在参数名后加上冒号 (:) 来定义的。
# 定义一个名为 'describe_person' 的方法,接收关键字参数 'name' 和 'age'。
def describe_person(name:, age:)
puts "#{name} 今年 #{age} 岁。"
end
# 使用关键字参数调用 'describe_person' 方法。因为你指定了参数名,所以顺序并不重要。
describe_person(name: "Alice", age: 30) # 输出: Alice 今年 30 岁。
describe_person(age: 25, name: "Bob") # 输出: Bob 今年 25 岁。当方法有很多可选参数时,关键字参数特别有用,因为它们能清楚地表明正在设置哪些参数。
4.1 可选关键字参数
你可以通过提供默认值,让关键字参数变成可选的。如果调用者没有为该参数提供值,就会使用默认值。
# 定义一个名为 'create_user' 的方法,接收关键字参数 'name' (必填) 和 'age' (可选,有默认值)。
def create_user(name:, age: 18)
puts "正在创建用户 #{name},年龄 #{age}。"
end
# 仅传入 'name' 参数调用 'create_user' 方法。'age' 参数采用默认值 18。
create_user(name: "Eve") # 输出: 正在创建用户 Eve,年龄 18。
# 同时传入 'name' 和 'age' 参数调用 'create_user' 方法。
create_user(name: "David", age: 40) # 输出: 正在创建用户 David,年龄 40。4.2 双星号可变参数 (**kwargs)
双星号操作符 (**) 用于将一系列未知的关键字参数收集到一个哈希(Hash)中。这使得方法能够接收任意数量、任意名称的关键字参数。
# 定义一个名为 'profile' 的方法,使用双星号操作符 (**options) 接收任意数量的关键字参数。
def profile(**options)
options.each { |key, value| puts "#{key}: #{value}" }
end
# 使用不同的关键字参数调用 'profile' 方法。
profile(name: "Charlie", age: 35, city: "纽约")
# 输出:
# name: Charlie
# age: 35
# city: 纽约在这个例子中,**options 将所有的关键字参数收集到一个名为 options 的哈希中。然后遍历这个哈希打印出所有的键值对。这通常用于当你想要向方法传递一组配置选项,而不想显式定义每一个选项时。
5. 返回值
方法可以使用 return 关键字将一个值返回给调用者。如果方法没有显式地返回一个值,它会隐式地返回该方法内最后一行被评估的表达式的结果。
5.1 显式返回
return 关键字允许你明确指定方法要返回的值。当程序执行到 return 语句时,方法的运行会立即停止。
# 定义一个名为 'multiply' 的方法,接收两个参数 'a' 和 'b',并显式返回它们的乘积。
def multiply(a, b)
return a * b
end
# 调用 'multiply' 方法,并将返回的值赋给 'result' 变量。
result = multiply(4, 6)
puts "乘积是 #{result}" # 输出: 乘积是 245.2 隐式返回
如果方法中没有 return 语句,它会默认返回最后一个被评估的表达式的值。
# 定义一个名为 'subtract' 的方法,接收两个参数 'x' 和 'y',并隐式返回它们的差值。
def subtract(x, y)
x - y # 这是最后一个表达式,它的值会被隐式返回
end
# 调用 'subtract' 方法,并将返回的值赋给 'difference' 变量。
difference = subtract(10, 3)
puts "差值是 #{difference}" # 输出: 差值是 76. 返回多个值
与某些其他语言不同,Ruby 并不直接支持返回多个独立的值。然而,你可以通过返回一个数组(Array)或哈希(Hash)来巧妙地实现返回多个值的目的。
6.1 使用数组返回
# 定义一个名为 'divide' 的方法,接收 'numerator' (分子) 和 'denominator' (分母),并以数组的形式返回商和余数。
def divide(numerator, denominator)
quotient = numerator / denominator
remainder = numerator % denominator
[quotient, remainder] # 返回一个包含商和余数的数组
end
# 调用 'divide' 方法,并使用平行赋值将返回的值分别赋给 'q' 和 'r' 变量。
q, r = divide(17, 5)
puts "商: #{q}, 余数: #{r}" # 输出: 商: 3, 余数: 26.2 使用哈希返回
# 定义一个名为 'calculate_stats' 的方法,接收一个数字数组,并返回一个包含总和与平均值的哈希。
def calculate_stats(numbers)
sum = numbers.sum
average = sum.to_f / numbers.length
{ sum: sum, average: average } # 返回一个键分别为 'sum' 和 'average' 的哈希
end
# 调用 'calculate_stats' 方法,并通过哈希的键来访问返回的值。
stats = calculate_stats([1, 2, 3, 4, 5])
puts "总和: #{stats[:sum]}, 平均值: #{stats[:average]}" # 输出: 总和: 15, 平均值: 3.0当你希望为返回的多个值提供具有描述性的名称时,使用哈希通常是更好的选择。
7. 方法链式调用
有返回值的方法支持一种被称为方法链(Method Chaining)的强大技巧。这意味着你可以直接在一个方法的返回值上继续调用另一个方法,从而以一种简洁、高可读性的方式执行一系列操作。
# 字符串方法的链式调用示例
message = " hello world "
result = message.strip.upcase.gsub("WORLD", "RUBY")
puts result # 输出: HELLO RUBY在这个例子中:
strip移除了字符串开头和结尾的空白字符。upcase将处理后的字符串转换为大写。gsub将大写的 "WORLD" 替换为 "RUBY"。
每一次方法调用都在上一次方法返回的结果之上继续进行操作,形成了一条清晰的“链”。