© Shine's Blog

Powered by LOFTER

[Ruby 中文教程 By Chris Pine] 6.流程控制

翻译:阳光

原文来自 <https://pine.fm/LearnToProgram/?Chapter=06

 

6.流程控制

 

啊,流程控制。这是让一切统一到一起的东西。虽然这一章要比methods那一章短,并且更简单,但它会为你的编程开启一个完整的世界。在这章之后,我们就能开始写真正的交互程序了,之前我们能够写个程序来根据你键盘输入的内容来“说”不同的内容,但是在这一章之后,我们能够真的让程序“做”不同的事情。但在我们能做到这一点之前,我们需要能比较我们程序中的object。我们需要……

 

比较Method

 

让我们迅速讲完这章好往下进行,下一部分的Branching是所有美好事物的源头。来吧,要看某个object是比另一个大还是小,我们用>和<这两个method,像这样:

输入:

puts 1>2

puts 1<2

输出:

false

true

 

没问题。同样的,我么能用>=和<=来看看一个object是大于等于另一个还是小于等于:

输入:

puts 5 >= 5

puts 5 <= 4

输出:

true

false

最后,我么能够用==和!=来判断两个object是否相等(它的意思分别是“它们相等吗?”和“它们不同吗?”)。分辨=与==是非常重要的。=用来使一个变量指向一个object(赋值),而==则是用来问一个问题:“这两个object相等吗?”

输入:

puts 1 == 1

puts 2 != 1

输出:

true

true

 

当然,我们也可以比较字符串。当字符串作为比较对象时,它们比较的内容是其词典编纂的顺序,即它们的字典顺序。cat要比dog在字典中先出现,所以:

输入:

puts 'cat'<'dog'

输出:

true

 

虽然这里有一个问题:计算机通常会将大写字母放在小写字母之前。(这也是计算机在字体中储存字母的方式,例如:所有大写字母在前面,然后是小写字母)。这意味着它会认为'Zoo'是在'ant'前面,所以如果你想要知道在一本真的字典中哪个词会先出现,你应该在比较之前先对两个词都使用downcase(或者是upcase与capitalize)。

在Branching之前的最后一件要注意的事:比较method给我们的并不是字符串'true'和'false',它们给我们的是特殊的object:true和false。(当然,ture.to_s会给我们字符串'true',这也是为什么puts能输出'true')。ture与false会经常使用在……

 

Branching

 

Branching是一个简单的概念,但很强大。事实上,它是如此简单,我打赌我都不用解释它,我只需要给你看就够了:

输入:

puts 'Hello, What\'syour name?'

name = gets.chomp

puts 'Hello, ' +name + '.'

if name == 'Chris'

puts'What a lovely name!'

end

输出:

Hello, what's yourname?

(用户输入)Chris

Hello, Chris.

What a lovely name!

 

但如果你输入的是其他名字……

Hello, what's yourname?

(用户输入)Chewbacca

Hello, Chewbacca

 

这就是branching。如果if后面的条件成立,我们就运行if和end之间的代码。如果if后面的条件不成立,就不运行。朴素而简单。

我将if和end之间的代码进行了缩进,因为这会让它看起来更好读。几乎所有的程序员都会这样做,不管他们使用的是什么语言。在这个简单的例子中可能不明显,但当事情变得复杂时,就会很不同。

通常,我们会想让程序在一个表达式成立的时候去做一件事,在不成立的时候去做另一件事。这就是else的作用:

输入:

puts 'I am afortune-teller. Tell me your name:'

name = gets.chomp

if name =='Chris'

puts'I see great things in your future.'

else

puts'Your future is... Oh my! Look at the time!'

puts'I really have to go, sorry!'

end

输出:

I am afortune-teller. Tell me your name:

(用户输入)Chirs

I see great thingsin your future.

 

现在让我们输入一个不同的名字:

输出:

I am a fortune-teller.  Tellme your name:(用户输入)RingoYour future is... Oh my!  Look at the time!

I really have to go,sorry!

 

Branching有点像代码里的一个路口:对名字等于'Chris'的人我们应该让它们进去吗?对其余的人应该让他们走另一条路吗?

就像树的枝干一样,一个分支也可以有自己的分支:

输入:

 

puts 'Hello, andwelcome to 7th grade English.'

puts 'My name isMrs. Gabbard. And your name is...?'

name = gets.chomp

 

if name ==name.capitalize

puts'Please take a seat, ' + name + '.'

else

putsname + '? You mean' + name.capitalize + ', right?'

puts'Don\'t you even know how to spell your name??'

reply= gets.chomp

ifreply.downcase == 'yes'

puts'Hummph! Well, sit down!'

else

puts'GET OUT!!'

end

end

 

输出:

Hello, and welcometo 7th grade English.

 

My name is Mrs. Gabbard.  Andyour name is...?(用户输入)chrischris?  You mean Chris, right?Don't you even know howto spell your name??(用户输入)yes

 

Hmmph!  Well, sit down!

 

好吧,我来将第一个字母大写:

输出:

Hello, and welcometo 7th grade English.

 

My name is Mrs. Gabbard.  Andyour name is...?(用户输入)Chris

Please take a seat,Chris.

 

有时可能会很难弄清楚那些if、else和end都在哪。我会在写if的同时就写end。所以就像我在上面的程序中写的那样,这是它一开始看起来的样子:

puts 'Hello, andwelcome to 7th grade English.'

 

puts 'My name isMrs. Gabbard.  And your name is...?'name=ets.chomp

 

if name ==name.capitalize

 

else

 

end

 

然后用评论来占满空间,这些评论计算机会忽略掉:

 

puts 'My name isMrs. Gabbard.  And your name is...?'name=ets.chomp

 

if name ==name.capitalize

#She's civil.

 

else

#She gets mad.

 

end

 

#之后的内容都会被当作评论来看待(当然除非它是一个字符串的一部分)。还有就是,写完代码后我删掉了评论。有些人喜欢把它留在那,个人看来,我觉得写得好的代码都会为自己代言。我曾经用过很多评论,但我的Ruby技巧越熟练,就越少使用评论。这是个人的选择,你会找到你自己的风格(通常是慢慢进化得到的)。

下一步我可能这么写:

puts 'Hello, andwelcome to 7th grade English.'puts 'My name is Mrs. Gabbard.  And your name is...?'

 

name = gets.chomp

 

if name ==name.capitalize  puts 'Please take aseat, ' + name + '.'else

 

  puts name + '?  You mean ' + name.capitalize + ', right?'

 

  puts 'Don\'t you even know how to spell yourname??'

 

  reply = gets.chomp  

 

  if reply.downcase == 'yes'

 

  else endend

 

再一次地,我一次把if、else和end都写出来了。它真的能帮我在代码中明确“我在哪里”。这也让工作变得更简单了,因为我可以专注于一小部分,比如讲if和else之间的部分填满。这样做的另一个好处是计算机能在各个层面上理解这个程序。我想你展示过的每一个程序的未完成版本都能运行。它们还没有写完,但它们是能用的程序。通过这种方式我能够测试我都写了一些什么,这能让我知道它现在怎么样,它还需要什么改进。当它它了!

这些技巧能帮你用branching写程序,但它们也对另一种流程控制有帮助:

 

Looping

 

通常,你会想让你的计算机不停地做同一件事,这也是计算机擅长的东西。

当你告诉计算机保持重复做一件事的时候,你也需要告诉它什么时候停下来。计算机不会觉得无聊,所以如果你不告诉它停下来,它就不会停。我们用while来告诉计算机在某个特定条件成立的情况下去重复某件事,以避免它根本停不下来。这与if的用法很像:

输入:

command = ''

 

while command !='bye'

putscommand

command= gets.chomp

end

 

puts 'Come againsoon!'

输出:

 

(用户输入)Hello?Hello?(用户输入)Hi!Hi!

(用户输入)

Very nice to meetyou.

 

Very nice to meetyou.

 

(用户输入)Oh... howsweet!

 

Oh... how sweet!(用户输入)byeCome again soon!

 

这就是一个loop(循环)。(你可能注意到了一开始输出的那个空行,它来自于第一个puts,在第一个gets之前。如何让程序避免这个空行呢。测试它!除了一开始的空行,程序是不是与上面这个完全一样呢?)

Loop允许你做各种类型的有趣的事情,我敢肯定你有想象力。但是,如果你犯了错,它们也可能导致一些问题。如果你的计算机陷入到一个无休止的循环中怎么办?如果你觉得这可能发生了,只要按住Ctrl键并按C。

在我们尝试loop之前,让我们学一些使工作更简单的东西吧。

 

一点逻辑

 

让我们再来看一下我们第一个branching程序。如果我的妻子回来了,看到这个程序然后试了一下,但它并不能把她的名字当作一个lovely name怎么办?我可不想伤害她的感情(或者去睡沙发),所以让我们重新改写它:

输入:

puts 'Hello, what\'syour name?'

name = gets.chomp

puts 'Hello, ' +name + '.'

if name == 'Chris'

puts'What a lovely name!'

else

ifname == 'Katy'

puts'What a lovely name!'

end

end

输出:

Hello, what's your name?(用户输入)KatyHello,Katy.What a lovely name!

 

好吧,它能用……但是它并不是一个很好的程序。为什么不是呢?嗯,我从编程中学到的最好的规则就是DRY规则:不要重复你自己。我可能会为这条规则写一本小书来讲它为什么是一条好规则。在我们的例子中,我们重复了这一行:'What a lovely name!'。这有什么大不了的?好吧,假如我写第二次的时候拼写错了怎么办?如果我想要将两行中的'lovely'都改成'beautiful'怎么办?我很懒,记得不?基本上,如果我想让程序在得到'Chris'和'Katy'时做同样的事情,那它应该确实是在做“同样”的事情:

输入:

puts 'Hello, what\'syour name?'

name = gets.chomp

puts 'Hello, ' +name + '.'

if (name == 'Chris'or name == 'Katy')

puts'What a lovely name!'

end

输出:

Hello, what's yourname?

 

(用户输入)KatyHello,Katy.

 

What a lovely name!

 

好多了。为了能让它起作用,我用了or。其他的逻辑运算符是and和not。用它们的时候记得用括号。让我们看看它们是如何运作的:

输入:

iAmChris = true

iAmPurple = false

iLikeFood = true

iEatRocks = false

 

puts (iAmChris andiLikeFood)

puts (iLikeFood andiEatRocks)

puts (iAmPurple andiLikeFood)

puts (iAmPurple andiEatRocks)

puts

puts (iAmChris oriLikeFood)

puts (iLikeFood oriEatRocks)

puts (iAmPurple oriLikeFood)

puts (iAmPurple oriEatRocks)

puts

puts (not iAmPurple)

puts (not iAmChris)

输出:

true

false

false

false

 

true

true

true

false

 

true

false

 

这里面唯一可能让你感到困惑的是or。在英语中,我们经常用“or”来表示“这个或者另一个,但不是两个都”。例如,你的妈妈可能会说:“甜点可以吃派或者蛋糕”。她可不是在说你能两个都吃!另一方面,计算机用or来表示“这个或者另一个,或者两个都”。(换言之,“这些中至少一个是true”)这也是计算机比你妈要有趣的原因。

 

一些练习

 

·“99 bottles of beer on the wall...”写一个程序来把这句歌词输出成这样:“99 Bottles of Beer on the Wall.”

·写一个叫做“聋子奶奶”的程序。不管你跟奶奶说什么(不管你输入什么),她都会回应你“HUH?! SPEAK UP, SONNY!”,知道你喊出来(将所有字母大写)。如果你喊出来了,她就能听到你说话了(至少她觉得她是听到了),然后会朝你喊回来:“NO, NOT SINCE 1938!”为了能让你的程序更可信,让你的程序每次回应的年份不一样,也许是1930到1950之间随机的一年(这是个可选部分,如果你度以下method那一章最下面关于Ruby随机数发生器的内容的话,实现起来会更简单)。除非你说了BYE,否则你不能停止和奶奶交谈。

提示:不要忘了chomp!'BYE'后面跟一个回车不等于单独的'BYE'!

提示2:试试想想程序的哪个部分应该不停地重复。那些内容都应该在你的while循环里。

·扩展你的“聋子奶奶”程序:加入奶奶不想让你离开呢?当你喊出BYE,她可能假装没有听到你。改写你之前的程序,你必须连喊三个BYE才能结束与奶奶的对话。一定要测试你的程序:如果你喊了三次BYE,但不是在一行中的话,你应该继续与奶奶交谈。

·闰年。写一个程序,询问一个开始年份和一个结束年份,然后输出这个时间范围内所有的闰年(当然如果这个范围两端有闰年的话,也要输出它们)。闰年是能给4整除的年份(就像1984和2004).但是,能被100整除的不是闰年(比如1800和1900),除非它们能被40整除(比如1600和2000,它们是闰年)。(没错,这很复杂,但还赶不上七月位于冬天中期这件事,这是迟早要发生的)。

 

当你完成了这些,休息一下!你已经学习了非常多了。恭喜你!你现在为你能让计算机所做的事情感到吃惊了吗?再学几章你就几乎能用编程来做所有事情了。真的!看看你现在能做的,如果没学looping和branching,这些都是不能实现的。

现在让我们学一种新的object,它能够追踪其它object的序列:array。


发表于2014-07-13.