© Shine's Blog

Powered by LOFTER

[Ruby 中文教程 By Chris Pine] 5.更加了解method

翻译:阳光

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


5.更加了解method

 

目前为止我们已经看过了一些不同的method,puts、gets之类的(测验:列出目前学到的所有method!一共有十种,答案在下面),但是我们还没有真的讨论过method到底是什么,我们知道它们是干什么的,但不知道它们究竟是什么。

但说真的,那就是它们:干事的。如果object(像字符串,整数,浮点数)是Ruby语言中的名词的话,那么method就像是动词。并且,就像英语中的一样,你不能在使用动词的时候没有名词。比如,滴答声不是凭空来的,是一个钟(clock,也可能是一块表或是其他什么玩意)发出来的,在英语中我们可能会说,“The clock ticks.”而在Ruby中我们可能会说clock.tick(当然这里假设clock是一个Ryby的object)。

程序员也许会说我们“召唤了clock的tick method”,或者说我们“在clock上召唤了tick”。

所以,你回答刚才的测验了吗?很好。我觉得你肯定记得puts、gets、chomp,因为我们刚刚学过。你也可能记得我们的转换method:to_i、to_f、to_s。但是,你能写出剩下的四个吗?就是四种运算符+、-、*、/!正如我刚才说的,就像每个动词都需要一个名词一样,每个method都需要一个object。通常那个object正在被method处理是很容易看出来的:它就在那个点前面,就像clock.tick这个例子中展示的一样,或者是在101.to_s中。但有的时候,并不是这么明显的,比如用运算method的时候。确实,5 + 5比起5.+5是一个更简洁的方法。举个例子:

输入:

puts'hello'.+'world'

puts (10.*9).+9

输出:

hello world

99

这看起来并不美观,所以我们不会这么写,但是,明白到底发生了什么是很重要的。(在我的计算机上,它会给我警告:“警告:以后加上括号。程序是可以运行的,但是它还是告诉我在识别我的意图上出现了问题,应该在以后的编写中加上括号)这也让我们更深地理解了为什么可以写'pig'*5但是不能写5*'pig':因为'pig'*5实在告诉'pig'做乘法,而5*'pig'则是在告诉5做乘法,'pig'知道如何将自己复制5遍,但是5就不知道怎么将自己复制'pig'了。

当然,我们还要解释一下puts和gets。它们的object在哪?在英语中,有时你是可以不要名词的,例如,如果一个恶棍叫嚣着“Die!”,那他的名词可能是他所指向的任何人。在Ruby中,如果我说puts 'to be or not to be',实际上我在说的是self.puts 'to be or not to be'。所以什么是self?它是一个特殊的变量,指代一切你正处于的object。我们现在甚至还不知道怎么去进入一个object,但在我们知道之前,我们已经深处一个大型object中了——整个程序!幸运的是,程序有它自己的一些method,就像puts和gets一样。瞧这个:

输入:

iCantBelieveIMadeAVariableNameThisLongJustToPointToA3= 3

putsiCantBelieveIMadeAVariableNameThisLongJustToPointToA3

self.putsiCantBelieveIMadeAVariableNameThisLongJustToPointToA3

输出:

3

3

 

如果你还不能完全理解的话,也没关系。最重要的一点是,所有的method都是由某个object来实现的,就算前面没有一个点,也是这样的。如果你能明白这一点,你就圆满了。

 

奇特的字符串method

 

让我们来学一些有趣的字符串method。你没必要记住所有的,你可以在忘记的时候回来再看一遍。我只是想给你看看字符串能做的所有操作中的一小部分。事实上,我自己连一半的字符串method都记不住——但这没关系,因为网上有许多很好的参考手册为你列出了全部的字符串method并给出了相应解释(我会在这个教程的最后告诉你怎么找到这些参考手册)。说真的,其实我真的也不想知道全部的字符串method,那有点像知道字典里的全部单次一样……那就是字典的作用吗?所以你不必知道它里面有什么东西?

好,我们第一个字符串string是reverse,它会将字符串反着来一遍:

输入:

var1 = 'stop'

var2 = 'streesed'

var3 = 'Can youpronounce this sentence backwards?'

 

puts var1.reverse

puts var2.reverse

puts var3.reverse

puts var1

puts var2

puts var3

输出:

pots

desserts

?sdrawkcab ecnetnessiht ecnuonorp uoy naC

stop

stressed

Can you pronouncethis sentence backwards?

正如你所看到的,reverse不会将原来的字符串反转,它只会创建一个新的版本。这就是为什么在我们使用了reverse之后var1还是保持在'stop'的原因。

另一个字符串method是length(长度),它告诉我们字符串中字符的数量(包括空格):

输入:

puts 'What is yourfull name?'

name = gets.chomp

puts 'Did you knowthere are ' + name.length + ' characters in your name, ' + name + '?'

输出:

What is your full name?(用户输入)ChristopherDavid Pine#<TypeError: can't convert Fixnum into String>

额哦!出错了,而且看起来它是在name= gets.chomp之后出错的。你发现问题了吗?看看你是否能看出来。问题出在length上:它给了我们一个数字,但是我们需要的是一个字符串。解决方法很简单,我们给它加上一个to_s(然后祈祷吧):

输入:

puts 'What is yourfull name?'

name = gets.chomp

puts 'Did you knowthere are ' + name.length.to_s + ' characters in your name, ' + name + '?'

输出:

What is your full name?(用户输入)ChristopherDavid Pine

 

Did you know thereare 22 characters in your name, Christopher David Pine?

不,我不知道我名字有22个字符。注意:是字符数,不是字母数。我猜我们可以写一个程序来分别询问你的姓和名,然后将它们的长度加起来……嘿,为什么你不试试呢!去吧,我等你。

你完成了吗?很好!编程很有趣对吧?再学几章,你就会为你能做的事情感到吃惊。

还有一些字符串method是用来改变大小写的。upcase将每个小写字母都改成大写的,downcase则将每个大写字母都改成小写的。swapcase则将字符串中的大小写字母相互转换。capitalize则是只将首个字符大写(如果那个字符是个字母的话)。

输入:

letters ='aAbBcCdDeE'puts letters.upcase

 

putsletters.downcase

 

putsletters.swapcase

 

putsletters.capitalize

 

puts ' a'.capitalize

 

puts letters

输出:

AABBCCDDEE

 

aabbccddee

 

AaBbCcDdEe

 

Aabbccddee a

 

aAbBcCdDeE

 

这是很基础的操作。如你所见,'a'.capitalize的结果是只大写第一个字符,而不是大写第一个字母。

同样,如我们前面见到过的那样,这些操作都不会改变字母。我并不是想要过渡强调这一点,但是明白这一点真的很重要。有些method确实是会改变相关的object的,但是我们还没有学到它们,而且暂时不会学到。

我们要学习的最后一个神奇的字符串method是有关视觉显示的。第一个,center(居中),在字符串的前面和后面加上空格,以使字符串位于中间。但是,就像你必须告诉puts你想要显示什么出来、告诉+你要它加什么一样,你也必须告诉center这个居中所用的总长度是多少。所以如果我们想要将一行诗的文字居中,我可能会这么写:

 

输入:

lineWidth = 50

puts(                'Old MotherHubbard'.center(lineWidth))

puts(               'Sat in hercupboard'.center(lineWidth))

puts(         'Eating her curds anwhey,'.center(lineWidth))

puts(          'When along came aspider'.center(lineWidth))

puts(         'Which sat down besideher'.center(lineWidth))

puts('And scared herpoor shoe dog away.'.center(lineWidth))

输出:

                Old Mother Hubbard                

               Sat in her cupboard                

            Eating her curds an whey,             

             When along came a spider             

            Which sat down beside her             

        And scared her poor shoe dog away.        

 

嗯……我不觉得这是这首童谣该有的样子,但我懒得去追究细节了。(同样的,我为了能让所有的.center lineWidth都对齐,我在字符串前面加了多余的空格。这只是因为觉得这样看起来好一点。程序员对一个程序中的代码如何看起来更好一点通常都有强烈的感觉,他们经常互有差异,你写的程序越多,你越能形成自己的风格)。说起来懒惰这件事,在编程中懒惰不一定总是坏事。例如,看到我是如何用变量lineWidth来贮存宽度值了吗?这样我以后如果想要回来把它变得更宽的话,我就可以只改变最上面的一行就可以了,而不用一行一行去改。如果是首长诗,这可能会为我节省非常多的时间。这种类型的懒惰在编程中绝对是种美德。

关于这个center的结果……你可能注意到了,这可能赶不上一个文本处理软件做的漂亮。如果你真的想要一个完美的居中效果(或者是一种更好看的字体),那你应该用一个文本处理软件!Ruby是一个非常好的工具,但没有更具能胜任所有工作。

另外两个字符串显示格式method是ljust和rjust,分别代表靠左和靠右。它们与center类似,只不过是只在左或右一边加上空格。让我们看一下所有这三个是如何发挥作用的:

输入:

lineWidth = 40

str = '--> text<--'

puts str.ljustlineWidth

puts str.centerlineWidth

puts str.rjustlineWidth

puts str.ljust(lineWidth/2) + str.rjust (lineWidth/2)

输出:

--> text<--                            

              --> text <--              

                            --> text <--

--> text<--                --> text <--

 

一些练习

 

写一个Angry Boss程序。它应该粗鲁地询问你想要干嘛。不管你回答什么,程序都应该冲你喊叫,然后把你开除了。比如,如果你输入I want a raise.,它应该嚷嚷的是:WHADDAYA MEAN "I WANT A RAISE."?!?  YOU'RE FIRED!!

 

这些事为了让你熟练center,ljust,rjust所做的一些练习:写一个程序,显示这样一个表出来:

                Table of Contents                

                                                

Chapter 1:  Numbers                      page 1

Chapter2:  Letters                          page 72

Chapter 3:  Variables                   page 118

 

高级一点的数学

(这一部分完全是可以选择不学的。它假定你已拥有不错的数学知识。如果你不感兴趣,你可以直接进入到流程控制章节,不会有任何问题。但是,看一下这部分的Random Numbers随机数会很有帮助)。

数字的method没有字符串的多(但我还是不能全都了解它们)。这里,我们会看一下其他的运算method和一个随机数发生器,还有数学object与他的三角函数与非自然数运算。

 

更多算法

 

另外两个算法是**(乘方)和%(取模)。如果你想要用Ruby求5的平方,你应该写成5**2.指数部分也可以用浮点,比如你想要求5的开方,可以写成5**0.5。取模method让你保留除法过后的余下的部分。比如,7除以3,取模后得1。

让我们试试在编程中运用它们:

输入:

puts 5**2

puts 5**0.5

puts 7/3

puts 7%3

puts 365%7

输出:

25

2.23606797749979

2

1

1

从最后一行,我们可以知道一年是若干个星期加一天。所以如果你的生日是今年的某个星期二,下一年就是个星期三。你也可以对浮点使用modulus。基本上,它会处理地很理智,但我会让你把它搞乱的。

在学习随机数发生器之前,还有最后一个method要提及:abs。它就是取绝对值:

输入:

puts ((5-2).abs)

puts ((2-5).abs)

输出:

3

3

 

随机数

 

Ruby有一个不错的随机数发生器,能产生随机数。如果你直接写rand,会产生一个大于等于0并小于1的浮点。如果你给rand一个整数(比如5),它会产生一个大于等于0并小于5的整数(即有5个可能,从0到4)。

让我们看看rand是如何发挥作用的:

输入:

puts rand

puts rand

puts rand

puts (rand(100))

puts (rand(100))

puts (rand(100))

puts (rand(1))]

puts (rand(1))

puts (rand(1))

puts(rand(99999999999999999999999999999999999999999999999999999999999))

puts('The weathermansaid there is a ' +rand(101).to_s+'% chance of rain,')

puts('but you cannever trust a weatherman.')

输出:

0.866769322351658

0.155609260113273

0.208355946789083

61

46

92

0

0

0

22982477508131860231954108773887523861600693989518495699862

The weatherman saidthere is a 47% chance of rain,

but you can nevertrust a weatherman

注意我用的是rand(101)来产生一个在0和100之间的数,如果你写rand(1),那你只能得到0。我所见过人们用rand时最大的问题就是不知道确切的随机数可能产生的范围,即使是职业程序员,即使是商店中已完成的可以买到的产品中也是如此。我甚至有一个CD播放器,如果你选择随机播放,那它只会在除了最后一首以外的歌曲中随机播放……(我很好奇如果我放一张只有一首歌曲的CD进去会怎么样?)

有时你可能想要你的程序在两次不同的运行过程中产生一串相同的随机数。(比如,我用随机产生的数字来为一个计算机游戏创建了一个随机的世界,然后我非常喜欢这个世界,所以我想要再来一次,或是把它发给我的一个朋友)。为了做到这一点,你要设置一个seed(种子),用srand来实现这一点:

输入:

srand 1776

puts(rand(100))puts(rand(100))

 

puts(rand(100))puts(rand(100))puts(rand(100))puts''srand 1776puts(rand(100))puts(rand(100))

 

puts(rand(100))puts(rand(100))

 

puts(rand(100))

输出:

24

35

36

58

70


24

35

36

58

70

 

当你用相同的seed数字的时候,每次产生的随机数都一样。如果你想要回到产生不同随机数的模式(就跟你没用srand时一样),只需要写srand 0。这样它会用一个非常奇怪的数字来代替,它使用的是你计算机当前的时间(也可以是别的),以毫秒计算。

 

数学Object

 

最后,让我们来看一下数学object。我们直接试试:

输入:

puts(Math::PI)

puts(Math::E)

puts(Math.cos(Math::PI/3))

puts(Math.tan(Math::PI/4))

puts(Math.log(Math::E**2))

puts((1 +Math.sqrt(5))/2)

输出:

3.14159265358979

2.71828182845905

0.5

1.0

2.0

1.61803398874989

 

首先你注意到的可能是::这个符号。解释范围运算符这件事情确实不是本教程的……额,范围所在。这不是含沙射影,我发誓。你只要知道使用Math::PI会得到你想要的结果就够了。

如你所见,Math有所有良好的科学计算机所具有的功能。而且,浮点结果确实很接近正确答案。

然后我们要学习流程了!


发表于2014-07-12.