【Ruby】Learn To Program读后总结

700 阅读7分钟

Learn To Program


《Learn To Program》是一本初学者编程入门书,作者通过 Ruby 作为教学语言,以精炼却生动的例子带你进入编程的世界。

此书即是初学者编程入门教程,也是Ruby的入门教程。因此对于有一定编程基础并想学习Ruby的也在这本书上获得不菲的知识。

全书共分12课,这里将他们列出来并加入了链接,感兴趣的可以自行前往阅读。

  1. Getting Started
  2. Numbers
  3. Letters
  4. Variables and Assignment
  5. Mixing It Up
  6. More About Methods
  7. Flow Control
  8. Arrays and Iterators
  9. Writing Your Own Methods
  10. Classes
  11. Blocks and Procs
  12. Beyond This Tutorial

既然以Ruby作为本书的教程语言,那么环境安装自然不再话下。课程1就是教你如何安装Ruby,并且推荐使用一款趁手的IDE来编写Ruby。笔者使用VSCode来编写Ruby,个人感觉还不赖。在初学阶段,笔者建议可以直接通过irb来学习或调试Ruby,直接在终端输入irb试试吧。

Numbers

Ruby中的Number类型,有Integer和Float(注意Ruby中没有int、long之分,也没有float、double之分,只有两种数字类型,Integer和Float。)。以及Number之间的逻辑运算+-*/

练习下下面的打印,看看是不是和想的一样。

puts 1+2
puts 2*3
puts 5-8
puts 9/2

3
6
-3
4

Letters

在Ruby中,字符串的表示以一对‘’或者""来表示。

puts 'Hello, world!'
puts ''
puts "Good-bye."

而字符串的拼接可以简单的通过+来表示。

puts 'I like' + ' apple pie.'

I like apple pie.

拼接重复字符串,我们还可以借助于*运算符。

puts 'blink ' * 4

blink blink blink blink

当然以上字符串和数字的组合是因为不管是+还是*,都是String的一个函数,因此,我们才可以像调用函数那样使用他们。

我们也可以按如下方式调用:

puts 'I like'.+(' apple pie.')

I like apple pie.

他们的伪代码如下:

class String
    def +(other)
        "#{self}#{other}"
    end

    def *(other)
        s = self
        other.times do
            s = s + self
        end
        return s
    end

end

Variables and Assignment

这一课讲的是变量的赋值取值,以一个例子说明:(注意,Ruby的变量是不需要指定类型的,这是一门动态语言,会根据赋值来改变变量的类型,非常灵活)

composer = 'Mozart'
puts composer + ' was "da bomb", in his day.'

Mixing It Up

当我们运行下面的例子时程序就会提示我们语法错误。这是为什么呢?类型不匹配了,所以在运行时报错。数字和字符串怎么能加在一起,只有数字和数字,字符串和字符串之间才能相加。

var1 = 2
var2 = '5'

puts var1 + var2

这就需要Number和String之间能够相互转换。

to_s表示转换成字符串。因此下面的表达式成立。

var1 = 2
var2 = '5'

puts var1.to_s + var2

其他还有to_i转换成整型,to_f转换成浮点型。

puts '15'.to_f
puts "10".to_i

More About Methods

Ruby以.语法来调用函,以字符串为例。

var1 = 'stop'
puts var1.reverse

pots

通过调用gets函数来获取用户输入。gets.chomp在用户输入后自动换行。

puts 'What is your full name?'
name = gets.chomp
puts 'Did you know there are ' + name.length.to_s +
     ' characters in your name, ' + name + '?'

What is your full name?
User Input
Did you know there are 22 characters in your name, Christopher David Pine?

# 5的2次方
puts 5**2
# 取余
puts 7%3
# 绝对值
puts((5-2).abs)
puts((2-5).abs)
# 不大于1的随机数(浮点型)
puts rand
# 0<=x<10的随机整数
puts rand(10)

Flow Control

控制流,也就是比较>、<、=>、==、<=、!、!=

puts 1 == 1
puts 2 != 1
puts 1 > 2

true
true
false

条件分支if、else、elif、end

puts 'Hello, what\'s your name?'
name = gets.chomp
puts 'Hello, ' + name + '.'
if name == 'Chris'
  puts 'What a lovely name!'
end

Hello, what's your name?
Your input...
Hello, Chris.
What a lovely name!

循环语句while

command = ''

while command != 'bye'
  puts command
  command = gets.chomp
end

puts 'Come again soon!'

Hello?
Hello?
Hi!
Hi!
Very nice to meet you.
Very nice to meet you.
Oh... how sweet!
Oh... how sweet!
bye
Come again soon!

逻辑判断合并or(||)、and(&&)、not(!)

puts 'Hello, what\'s your name?'
name = gets.chomp
puts 'Hello, ' + name + '.'
if (name == 'Chris' or name == 'Katy')
  puts 'What a lovely name!'
elsif name == 'Jack' and name.length == 4
    puts ""
end

Hello, what's your name?
Katy
Hello, Katy.
What a lovely name!

Arrays and Iterators

Ruby中表示数组的方式为array = [1,2,3,"3"],其中数组中每个元素的类型都可以不一样。

获取数组内元素

puts array[0]
puts array[1]
puts array[-1]

1
2
"3"

要获取数组中的每一个元素,可以通过each方法遍历。

languages = ['English', 'German', 'Ruby']

languages.each do |lang|
  puts 'I love ' + lang + '!'
  puts 'Don\'t you?'
end

puts 'And let\'s hear it for C++!'
puts '...'

I love English!
Don't you?
I love German!
Don't you?
I love Ruby!
Don't you?
And let's hear it for C++!
...

而要重复操作一定次数,可以通过integer的times放啊实现。

3.times do
  puts 'Hip-Hip-Hooray!'
end

Hip-Hip-Hooray!
Hip-Hip-Hooray!
Hip-Hip-Hooray!

Writing Your Own Methods

在ruby中定义方法的格式为 ,参数可省

def sayMoo numberOfMoos
  puts 'mooooooo...'*numberOfMoos
end

sayMoo 3
puts 'oink-oink'
sayMoo 

mooooooo...mooooooo...mooooooo...
oink-oink

Classes

ruby使用关键字class来定义类,当这个类是已有的类时,表示往这个类中新增信息。

class Integer
  def to_eng
    if self == 5
      english = 'five'
    else
      english = 'fifty-eight'
    end

    english
  end
end


puts 5.to_eng
puts 58.to_eng

five
fifty-eight

类的实例变量通过 @+变量名表示,类变量则是@@+变量名

class Die

  def roll
    @numberShowing = 1 + rand(6)
  end

  def showing
    @numberShowing
  end

end

die = Die.new
die.roll
puts die.showing
puts die.showing
die.roll
puts die.showing
puts die.showing

4
4
6
6

Blocks and Procs

这一课讲Ruby中的闭包,可以理解成一个代码快,写在do end之间,用Proc类表示。do end也可以写成{}形式。闭包可以作为函数的参数使用,也可以直接像函数那样使用。

# 创建了一个闭包,存到变量toast中,调用call来执行闭包中的代码块
toast = Proc.new do
  puts 'Cheers!'
end

toast.call
toast.call
toast.call

Cheers!
Cheers!
Cheers!

闭包中还可以传入参数使用。

doYouLike = Proc.new do |aGoodThing|
  puts 'I *really* like '+aGoodThing+'!'
end

doYouLike.call 'chocolate'
doYouLike.call 'ruby'

I really like chocolate!
I really like ruby!

当闭包作为函数参数时:

def doSelfImportantly someProc
  puts 'Everybody just HOLD ON!  I have something to do...'
  someProc.call
  puts 'Ok everyone, I\'m done.  Go on with what you were doing.'
end

sayHello = Proc.new do
  puts 'hello'
end

sayGoodbye = Proc.new do
  puts 'goodbye'
end

doSelfImportantly sayHello
doSelfImportantly sayGoodbye

Everybody just HOLD ON! I have something to do...
hello
Ok everyone, I'm done. Go on with what you were doing.
Everybody just HOLD ON! I have something to do...
goodbye
Ok everyone, I'm done. Go on with what you were doing.

当闭包作为函数的返回值时:

def compose proc1, proc2
  Proc.new do |x|
    proc2.call(proc1.call(x))
  end
end

squareIt = Proc.new do |x|
  x * x
end

doubleIt = Proc.new do |x|
  x + x
end

doubleThenSquare = compose doubleIt, squareIt
squareThenDouble = compose squareIt, doubleIt

puts doubleThenSquare.call(5)
puts squareThenDouble.call(5)

100
50

我们还可以不以Proc的方式将闭包传入函数中,只要在参数前面加&.

class Array
# 如果像前面那样直接传入Proc对象,那么在调用时就不能直接在方法后面根do end的函数块,需要先创建Proc的对象再传入才能正常运行。
  def eachEven(&wasABlock_nowAProc)
    # We start with "true" because arrays start with 0, which is even.
    isEven = true

    self.each do |object|
      if isEven
        wasABlock_nowAProc.call object
      end

      isEven = (not isEven)  # Toggle from even to odd, or odd to even.
    end
  end
end

['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
  puts 'Yum!  I just love '+fruit+' pies, don\'t you?'
end

# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
  puts oddBall.to_s+' is NOT an even number!'
end

Yum! I just love apple pies, don't you?
Yum! I just love cherry pies, don't you?
1 is NOT an even number!
3 is NOT an even number!
5 is NOT an even number!

多参数时,block只能放在最后面

def profile descriptionOfBlock, &block
  startTime = Time.now

  block.call

  duration = Time.now - startTime

  puts descriptionOfBlock+':  '+duration.to_s+' seconds'
end

profile '25000 doublings' do
  number = 1

  25000.times do
    number = number + number
  end

  # Show the number of digits in this HUGE number.
  puts number.to_s.length.to_s+' digits'
end

profile 'count to a million' do
  number = 0

  1000000.times do
    number = number + 1
  end
end

7526 digits
25000 doublings: 0.026852 seconds
count to a million: 0.039258 seconds


接下来我们来做一个随书小练习。

part1: Grandfather Clock. Write a method which takes a block and calls it once for each hour that has passed today. That way, if I were to pass in the block do puts 'DONG!' end, it would chime (sort of) like a grandfather clock. Test your method out with a few different blocks (including the one I just gave you). Hint: You can use Time.now.hour to get the current hour. However, this returns a number between 0 and 23, so you will have to alter those numbers in order to get ordinary clock-face numbers (1 to 12).

意思就是我在1~12小时之间,每过一小时就打印一次‘DONG!’

def onHourAlarm(&block)
    hour = Time.new.hour
    if hour > 12 
        hour = hour - 12
    end
    block.call hour
end

onHourAlarm do |hour|
    puts "It is #{hour} o 'clock"
end

我们还可以隐式的调用函数的block,像下面这样:

def doItTwice
  if block_given?
    yield
    yield
  else
    puts 'no block'
  end
end

doItTwice do
  puts 'buritiate mustripe lablic acticise'
end

buritiate mustripe lablic acticise
buritiate mustripe lablic acticise

yield关键字表示隐式调用函数传入的闭包,block_given?就是判断这个函数是否有传入闭包。