8 最美不过简简单单
正如我们在上一篇文章中看到的那样,循环和迭代允许我们一遍遍地重复做相同的事情。但在现实中有时我们想在程序中其他地方重复做同样的事情。比如说我们在写一个面向心理专业学生所做的调查问卷,而我这里已经有一份他们提供给我的调查问卷,类似下面这样:
puts 'Hello, and thank you for taking the time to'
puts 'help me with this experiment. My experiment'
puts 'has to do with the way people feel about'
puts 'Mexican food. Just think about Mexican food'
puts 'and try to answer every question honestly,'
puts 'with either a "yes" or a "no". My experiment'
puts 'has nothing to do with bed-wetting.'
puts
# We ask these questions, but we ignore their answers.
goodAnswer = false
while (not goodAnswer)
puts 'Do you like eating tacos?'
answer = gets.chomp.downcase
if (answer == 'yes' or answer == 'no')
goodAnswer = true
else
puts 'Please answer "yes" or "no".'
end
end
goodAnswer = false
while (not goodAnswer)
puts 'Do you like eating burritos?'
answer = gets.chomp.downcase
if (answer == 'yes' or answer == 'no')
goodAnswer = true
else
puts 'Please answer "yes" or "no".'
end
end
# We pay attention to *this* answer, though.
goodAnswer = false
while (not goodAnswer)
puts 'Do you wet the bed?'
answer = gets.chomp.downcase
if (answer == 'yes' or answer == 'no')
goodAnswer = true
if answer == 'yes'
wetsBed = true
else
wetsBed = false
end
else
puts 'Please answer "yes" or "no".'
end
end
goodAnswer = false
while (not goodAnswer)
puts 'Do you like eating chimichangas?'
answer = gets.chomp.downcase
if (answer == 'yes' or answer == 'no')
goodAnswer = true
else
puts 'Please answer "yes" or "no".'
end
end
puts 'Just a few more questions...'
goodAnswer = false
while (not goodAnswer)
puts 'Do you like eating sopapillas?'
answer = gets.chomp.downcase
if (answer == 'yes' or answer == 'no')
goodAnswer = true
else
puts 'Please answer "yes" or "no".'
end
end
# Ask lots of other questions about Mexican food.
puts
puts 'DEBRIEFING:'
puts 'Thank you for taking the time to help with'
puts 'this experiment. In fact, this experiment'
puts 'has nothing to do with Mexican food. It is'
puts 'an experiment about bed-wetting. The Mexican'
puts 'food was just there to catch you off guard'
puts 'in the hopes that you would answer more'
puts 'honestly. Thanks again.'
puts
puts wetsBed
上面的程序有些太长,许多代码都是重复的(围绕着食物问题的代码是一样的,只有在尿床的部分有些许不同)。代码重复总是件不好的事,但我们又没法将它们写成一个大的循环或迭代中去,因为我们通常会在问题中间做点其他事情。鉴于这种情况我们就很有必要写一个方法,比如下面这种:
def sayMoo
puts 'mooooooo...'
end
但运行后程序没有输出sayMoo
。这是为什么?因为我们还没有告诉它去输出(我们只是告诉程序如何做,但还没指示程序去做)。让我们再来试验一下:
mooooooo...
mooooooo...
coin-coin
mooooooo...
mooooooo...
嗯,成功运行。(考虑到你们可能不太了解法语,在程序中有一个法国的鸭子,因为在法国鸭子的叫声就是coin-coin
)
在上面的程序中我们就成功定义(define
)了sayMoo
的方法(方法的名字类似变量命名方式,以小写字母开头,但也有少数以+或==开头的例外)。但是难道方法不是通常要与对象一起用的吗?好吧,的确需要这样用,但上面的例子有些类似pus
和gets
,方法是以整个程序为对象的,在下个章节中我们将会看到如何将方法与其他对象一起用上,但是我们要首先学习…
方法中参数的使用
你可能已经注意到类似gets``to_s``reverse
等方法可以直接向对象进行调用,但类似+``-``puts
等需要参数才能告诉对象如何使用这种方法。比如你不能仅仅用5+
,是吧?你只是在告诉对象5
去执行加法,但没告诉它增加多少……
为了给sayMoo
增加参数(比如叫声的数量),可以这样做:
def sayMoo numberOfMoos
puts 'mooooooo...'*numberOfMoos
end
sayMoo 3
puts 'oink-oink'
sayMoo # This should give an error because the parameter is missing.
运行结果是:
mooooooo...mooooooo...mooooooo...
oink-oink
#<ArgumentError: wrong number of arguments (0 for 1)>
numberOfMoos
是一个指向参数的变量:如果我键入的是sayMoo 3
,那么参数是3,变量numberOfMoos
是指向3的。
正如你所看到的:上面的程序中参数就是必须要提供的,别忘了如果你不提供参数,sayMoo
要用什么去乘以'mooooooo...' ?你笨笨的电脑是有点懵逼的。
如果我们把Ruby中的对象比作英语中的名词,把Ruby中的方法比作动词,那么你可以把参数对应于英语中的副词(好比sayMoo,参数是教我们如何sayMoo)或某些情况下类似直接宾语(好比puts中的参数就是应该输出的相应内容)。
局部变量
在下面的代码中有两个变量:
输出结果是:
44 doubled is 88
两个变量分别是
num
和numTime2
,它们都在我们定义的方法doubleThis
中。类似之前你看到的所有变量都称作局部变量,因为这些变量只能在方法内部使用,在外部使用的话就会提示错误:
def doubleThis num
numTimes2 = num*2
puts num.to_s+' doubled is '+numTimes2.to_s
end
doubleThis 44
puts numTimes2.to_s
输出就会提示有错误:
44 doubled is 88
def_double.rb:7:in `<main>': undefined local variable or method `numTimes2' for main:Object (NameError)
提示中的undefined local variable…事实上我们的确定义了numTime2
变量,但它没有位于我们想使用的地方,而只位于我们定义的方法中。
输出为:
HAHA! I ruined your variable!
You can't even touch my variable!
在上面程序中有两个名字均为var
的变量:一个在方法littlePest
中,另一个则在方法外面。当我们用命令littlePest var
时候,仅仅是字符串的传递,都指向同一个字符串。littlePest
方法中将局部变量var
指向nil
,但对方法外部的另一个同样的变量var
无任何影响。