## 9.功能
当你多次使用同一段代码时,可以将它们分组为一个函数,你可以在程序中的任何位置调用该分组代码以执行特定任务。 让我们以一个现实世界为例,你去旅馆,侍者走近,你点了一份炸鱼,就明白了。 订购后,你不会受到任何影响。
一旦订购了鱼苗,就会发生很多程序。 服务员记下你的订单,他去厨房,将订单交给厨师,厨师告诉他要煮熟的菜肴会花费很多时间。 服务员想着如何避免让你感到无聊,他来到你的餐桌旁,为你推荐开胃菜和/或开胃菜,为你提供可以在吃菜前喝得很好的饮料,他汇集了厨房以查看菜是否 准备好了。 如果菜已经准备好并且你已经完成了开胃菜,那么他将为你服务。 如果你还没吃完开胃菜,他会告诉厨房让菜保温,然后等你煮完。 一旦他把盘子拿到你的桌子上,他就放下装有盘子和餐具的盘子。
你要做的只是订购炸鱼,而完全忽略了后台正在运行的功能。 你向服务员下了订单(输入),然后拿到了盘子(输出)。 根据服务员的训练,服务员会预先计划或训练做什么和不做什么。
让我们开始使用 Ruby 中的函数。 我们将看一个程序,其中将编写一个名为`print_line`的函数,该函数将打印一行。 在文本编辑器中键入以下程序并运行它。
```rb
# function.rb
def print_line
puts '_'*20
end
print_line
puts "This program prints lines"
print_line
```
输出量
```rb
____________________
This program prints lines
____________________
```
让我们分析程序。 考虑以下代码:
```rb
def print_line
puts '_'*20
end
```
`def`告诉你正在定义一个功能。 函数必须具有名称,该名称紧随`def`关键字之后。 在这种情况下,函数的名称为`print_line`。 你可以在其中编写所需的代码。 在这种情况下,我们将创建一个包含 20 个下划线字符的行。
因此,我们创建了一个函数,并向其中添加了代码。 现在我们需要做的就是从程序中调用该函数。 只需在程序中键入函数名称即可,如下所示
```rb
print_line
puts "This program prints lines"
print_line
```
从输出中可以看到,在字符串`“This program prints lines”`的上方和下方都打印了由 20 个下划线字符组成的行。
### 9.1。 参数传递
让我们对本节中的功能进行更多控制。 有时你不去酒店订购一顿菜,你可以订购多少或更少。 如果你和朋友一起去,可以订购更多份量;如果你一个人,则订购的份量会更少。 为什么用`print_line`功能不能做同样的事情? 为什么我们不能更改其长度,这样做将是一件很了不起的事情,我们可以根据自己的选择打印长度的行。
看下面的代码,我们在函数名称后键入了一个名为`length`的东西,它称为参数。 像函数一样,参数也有一个名称,在这种情况下,我们将其命名为`length`。 我们可以将任何值传递给它以改变打印行的`length`。 输入以下代码并执行
```rb
# function_1.rb
def print_line length
puts '_'*length
end
10.step(50,10) do |x|
print_line x
end
40.step(10,-10) do |x|
print_line x
end
```
你将获得如下所示的设计模式
```rb
__________
____________________
______________________________
________________________________________
__________________________________________________
________________________________________
______________________________
____________________
__________
```
看下面的代码
```rb
10.step(50,10) do |x|
print_line x
end
40.step(10,-10) do |x|
print_line x
end
```
我们已经使用`step`循环将捕获的值递增或递减到循环内的`x`变量中,通过将`x`传递给`print_line`函数,方法是将其放置在调用后,如上突出显示 。 因此,每次打印一条不同长度的线(由`x`决定)。 以某种方式构造程序,以便生成模式。
### 9.2。 默认参数
在 [function_1.rb](code/function_1.rb) 中,你了解了如何将参数传递给函数。 如果假设你无法通过辩论,该怎么办? 如果这样做,将会产生一个错误,一个好的程序员将不会希望发生这种错误。 为了防止这种情况并使编程变得容易一些,最好为函数提供默认参数。 注意下面在 [function_default_argument.rb](code/function_default_argument.rb) 中给出的代码
```rb
# function_default_argument.rb
def print_line length = 20
puts '_'*length
end
print_line
print_line 40
```
执行程序并观察结果
```rb
____________________
________________________________________
```
你可以在程序中通过输入`length = 20`来查看函数`print_line`,这表明如果未传递任何参数,则该函数必须假定`length`的值为 20。 如果通过,则此值将被你传递的任何值所覆盖。 正如你在第一个函数调用中看到的那样,我们仅通过函数名称`print_line`来调用函数,我们无需理会将长度值传递给它,但是我们看到在输出中打印出一行长度为 20 个单位的行 。
### 9.3。 将数组传递给函数
通常,当你将变量传递给函数时,会创建该变量的副本。 而且,如果你对变量进行了更改,则该函数外部的变量不会受到影响。 因此,让我们看看将数组传递给函数时会发生什么。 在下面的程序中键入并运行它。
```rb
# array_passed_to_function.rb
def array_changer array
array << 6
end
some_array = [1, 2, 3, 4, 5]
p some_array
array_changer some_array
p some_array
```
Output
```rb
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
```
如果你是编程新手,这可能并不奇怪,但是当将变量传递给函数时,其值不应更改。 但是在数组的情况下,在函数`array_changer`中,我们向其中添加了一个元素,并且它会更改。 好吧,这是数组传递给函数的特殊行为。
为避免这种情况,请尝试以下程序
```rb
# array_copy.rb
def array_changer array
array << 6
end
some_array = [1, 2, 3, 4, 5]
p some_array
array_changer Marshal.load(Marshal.dump(some_array))
p some_array
```
Output
```rb
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
```
在这里,数组没有改变,请看`array_changer Marshal.load(Marshal.dump(some_array))`行,这段代码将`some_array`复制到 function 参数,以便即使在函数内部对其进行了更改,也不会在函数外部进行更改。
////在这里写函数式编程
### 9.4。 返回值
到目前为止,我们已经看到函数接受了参数,现在我们看到函数可以返回可用于某些目的的值。 现在让我们来看程序 [function_return.rb](/code/function_return.rb) ,研究代码,键入并执行它。
```rb
#! /usr/bin/ruby
# function_return.rb
def addition x, y
sum = x+y
return sum
end
a, b = 3, 5
puts addition a,b
```
Output
```rb
8
```
执行后得到的输出为 8。请注意上述程序中名为 addition 的方法。 它接受两个参数`x`和`y`,在该方法内部,我们声明一个名为`sum`的变量,该变量分配给`x`与`y`的加法。 下一个语句是此处的主人公,请参见我们使用了关键字`return`,这将返回该函数的值。 在上面的程序中,我们返回`sum`,因此当我们得到答案时。
不是我们必须使用`return`语句返回值。 默认情况下,返回在 Ruby 函数中执行的最后一条语句。 考虑下面显示的程序 [function_last_gets_returned.rb](code/function_last_gets_returned.rb) 。 在其中,我们有一个名为`square_it`的方法,该方法接受一个名为`x`的单个参数。 它只有一个语句`x**2`,恰好也是最后一个语句。
```rb
#!/usr/bin/ruby
# function_last_gets_returned.rb
def square_it x
x**2
end
puts square_it 5
```
输入程序并执行。
```rb
25
```
如你所见,我们调用了`square_it 5`,结果为 25。 这可能是因为在 Ruby 中,默认情况下返回上一次执行的语句的结果。
### 9.5。 关键字参数
要了解关键字参数,请在下面键入程序并执行:
```rb
# keyword_argument.rb
def say_hello name: "Martin", age: 33
puts "Hello #{name} your age is #{age}"
end
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
say_hello
```
Output
```rb
Hello Joseph your age is 7
Hello Vignesh your age is 21
Hello Martin your age is 33
```
因此,要查看此功能的工作原理,请分析代码。 查看 say_hello 的函数定义,如下所示
```rb
def say_hello name: "Martin", age: 33
puts "Hello #{name} your age is #{age}"
end
```
查看突出显示的部分`def say_hello name: "Martin", age: 33`。 在这里,我们不将参数指定为`def say_hello name= "Martin", age= 33`,而是使用特殊的`name: “Martin”`,我们取出了等号并替换为冒号。 那有什么用呢? 现在看一下函数调用的部分
```rb
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
say_hello
```
第一行是`say_hello name: "Joseph", age: 7`,此处第一个参数是`name`,第二个参数是`age`。 但是看看代码`say_hello age: 21, name: "Vignesh"`,这里的第一个参数是`age`,第二个参数是`name`。 但是由于参数是由关键字提示的,因此它的位置无关紧要,并且该方法将按预期输出字符串。
第三行`say_hello`只是显示如果缺少参数会发生什么,因为我们已经指定了默认值,所以它采用了默认值。 是否可以将关键字参数与默认值一起使用? 绝对没错。 试试下面的程序,看看自己
```rb
# keyword_argument_no_defaults.rb
def say_hello name:, age:
puts "Hello #{name} your age is #{age}"
end
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
# say_hello # uncomment it and try it out
# say_hello "Karthik", 32 # uncomment it and try it out
```
### 9.6。 递归函数
让我们看看另一件事。 你可能想知道为什么我要进行所有数学运算? 某些程序员确实写了一些书,这些书尽可能地排除了数学知识,我不是专业的数学家,但我很欣赏数学。 计算机是基于数学的。 所有计算机都使用称为布尔代数的东西来执行所有任务。 我并不是说你必须是数学家才能成为程序员,但是了解数学确实会有所帮助。
好,什么是阶乘? 取一个数字,取 3,现在将是 3 X 2 X 1,即六个! 是不是很简单? 6 是 3 的阶乘。好吧,我们现在取 4,所以 4 X 3 X 2 X 1 将是 24,以类似的方式,2 的阶乘将是 2 X 1,即 2。有了这些知识,我们现在将构造一个 该程序将为我们提供一定数量的阶乘。
研究下面给出的程序。 专注于名为阶乘的函数
```rb
# factorial.rb
def factorial num
fact = 1
1.upto(num) { |a|
fact = fact * a
}
fact
end
number = 17
puts "Factorial of #{number} = #{factorial number}"
```
执行上面的代码,这就是你得到的输出
```rb
Factorial of 17 = 355687428096000
```
在上面的示例中(在阶乘函数中),我们将所有数字从一个取到特定的数字,将其相乘得到阶乘。 现在研究如下所示的代码 [factorial_1.rb](code/factorial_1.rb)
```rb
# factorial_1.rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
number = 17
puts "Factorial of #{number} = #{factorial number}"
```
Execute the code above and this is what you get as output
```rb
Factorial of 17 = 355687428096000
```
输出与先前程序 [factorial.rb](code:factorial.rb) 相同。 请仔细查看上述程序中名为`factorial`的功能。 我列出来看看
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
该功能令人困惑,不是吗? 当我发疯并且想学习编程时,我学习了 C。递归函数的概念是使用阶乘解释的,而且我很长一段时间都没有理解它。 为了避免痛苦,让我详细解释。
取数字 1。它的阶乘为 1。因此,如果遇到 1,则返回 1,如下代码所示
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
现在考虑数字 2 的阶乘 2 X 1,它是 2 乘以 1 的阶乘。换句话说,我们可以将其写为 2 乘以 2-1 的阶乘。 因此,如果在函数`factorial`中遇到第二个数字,它将跳过第一个 if 语句,而下面的第二个语句`return num * factorial(num-1)`被执行
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
在这个有趣的事情发生了。 这里调用阶乘(2-1),即阶乘函数本身。 因此,当 2-1 的阶乘,即 1 的阶乘被调用时,它返回 1,该 1 乘以 2 并返回,因此在这种情况下最终返回 2。
现在取数字 3。其阶乘为 3 X 2 X1。这可以写成 3 乘以阶乘 2。阶乘 2 转换为 2 乘以阶乘 1。因此最终得到结果。 对于任何大于 1 的数字,阶乘函数都会反复调用其自身。 函数调用本身的过程称为递归。
### 9.7。 可变数量的参数
假设你不知道向一个函数传递了多少个参数,假设你正在编写一个要添加 N 个数字的函数,则 N 的值未知,那么如何获得可变数量的参数。 键入下面给出的程序 [function_variable_arguments.rb](code/function_variable_arguments.rb) 并执行它。
```rb
# function_variable_arguments.rb
def some_function a, *others
puts a
puts "Others are:"
for x in others
puts x
end
end
some_function 1,2,3,4,5
```
Output
```rb
1
Others are:
2
3
4
5
```
因此,程序的输出如上所示。 如你所见,我们将 1,2,3,4,5 作为参数传递,那么`a`只是一个变量,因此它取值为 1,其他变量被变量`**others**` **吸收( 注意,变量名前的星号** 是一种特殊的自变量,它将所有未被前一个自变量吸收的其余自变量存储在其他变量名中(作为数组)。 现在在下面的代码中
```rb
for x in others
puts x
end
```
就是这样。 现在尝试编写一个函数以查找 n 个数的最大值,并编写另一个函数以查找 n 个数的最小值,并编写一个程序查找一堆数字的最大值和最小值。
### 9.8。 哈希作为函数参数
潜入多个参数到函数中的另一种方法是将它们作为哈希传递。 看下面的程序,我们有一个名为`some_function`的函数,该函数有两个参数,第一个名为`first_arg`,第二个名为`others_as_hash`,我们在下一行`some_function "Yoda", {jedi: 100, sword: 100, seeing_future: 100}`中调用此函数,执行它并 注意输出
```rb
# hashes_to_functions.rb
def some_function first_arg, others_as_hash
puts "Your first argument is: #{first_arg}"
puts "Other arguments are:"
p others_as_hash
end
some_function "Yoda", {jedi: 100, sword: 100, seeing_future: 100}
```
Output
```rb
Your first argument is: Yoda
Other arguments are:
{:jedi=>100, :sword=>100, :seeing_future=>100}
```
如我们所料,程序将打印第一个参数并传递给`others_as_hash`的哈希,这并不奇怪,但请看下面的程序 [hashes_to_function_1.rb](code/hashes_to_function_1.rb) ,执行该程序,其输出将 与上面的程序相同
```rb
# hashes_to_functions_1.rb
def some_function first_arg, others_as_hash
puts "Your first argument is: #{first_arg}"
puts "Other arguments are:"
p others_as_hash
end
some_function "Yoda", jedi: 100, sword: 100, seeing_future: 100
```
但是请注意这部分,我们已经将`some_function`称为
```rb
some_function "Yoda", jedi: 100, sword: 100, seeing_future: 100
```
在函数中,我们将第二个参数作为哈希值进行传递,但是如上所示,它应予注意,请注意,我们已避免使用花括号,并且它仍然有效。 这才是重点。
- 前言
- 红宝石
- 先决条件
- 1.安装 Ruby
- 2.在线资源
- 3.入门
- 4.比较与逻辑
- 5.循环
- 6.数组
- 7.哈希和符号
- 8.范围
- 9.功能
- 10.可变范围
- 11.类&对象
- 12.安全导航
- 13.打破大型程序
- 14.结构和 OpenStruct
- 15. Rdoc
- 16. Ruby 样式指南
- 17.模块和混入
- 18.日期和时间
- 19.文件
- 20. Proc,Lambda 和块
- 21.多线程
- 22.异常处理
- 23.正则表达式
- 24.宝石
- 25.元编程
- 26.基准
- 27.测试驱动开发
- 28.观察者模式
- 29.模板模式
- 30.工厂模式
- 31.装饰图案
- 32.适配器模式
- 33.单例模式
- 34.复合模式
- 35.建造者模式
- 36.策略模式
- 赞助商
- 捐
- 人们怎么说
- 版权
- 取得这本书