跳转到内容

Ruby 编程/Ruby 基础

来自维基教科书,开放世界中的开放书籍

← 对象简介 | 数据类型 →


与本教程的其余部分一样,我们假设您对编程语言概念(例如 if 语句、while 循环)有一定的了解,并且还对面向对象编程有一定的了解。

处理变量

[编辑 | 编辑源代码]

当我们讨论类和对象时,我们将更深入地处理变量。现在,让我们简单地说,您的基本局部变量名称应该以小写字母或下划线开头,并且应该包含大写或小写字母、数字和下划线字符。全局变量以$.

程序流程

[编辑 | 编辑源代码]

Ruby 包含一套非常标准的循环和分支结构if, whilecase

例如,这里是if在行动中

a = 10 * rand

if a < 5
  puts "#{a} less than 5"
elsif a > 7
  puts "#{a} greater than 7"
else
  puts "Cheese sandwich!"
end

[与其他语言一样,rand函数生成 0 到 1 之间的随机数]

在后面的章节中,我们将有更多时间讨论条件语句。上面的例子应该非常清楚。

Ruby 还包含if的否定形式,称为unless它有点像

unless a > 5
  puts "a is less than or equal to 5"
else
  puts "a is greater than 5"
end

一般来说,Ruby 会保持一个if语句直线,只要条件(if ...)和相关的代码块在不同的行上。如果您必须将所有内容放在一行上,您需要在条件之后放置then关键字

if a < 5 then puts "#{a} less than 5" end 
if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end

请注意,if语句也是一个表达式;它的值是执行的块的最后一行。因此,上面的行也可以写成

puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end)

Ruby 还采用了 Perl 中的语法,其中ifunless语句可以用作语句之后的条件修饰符。例如

puts "#{a} less than 5" if a < 5
puts "Cheese sandwich" unless a == 4

while的行为与其他语言中的行为相同 - 只要条件为真,就会运行后面的代码块,运行零次或多次

while a > 5
  a = 10*rand
end

if一样,也存在while的否定形式,称为until的否定版本,它直到条件为真才运行代码块。

最后是case语句,我们将在这里简单举例说明。case实际上是if ... elsif...系统

a = rand(11) # Outputs a random integer between 0 and 10

case a
when 0..5
  puts "#{a}: Low"
when 6
  puts "#{a}: Six"
else
  puts "#{a}: Cheese toast!"
end

的非常强大的超级版本。在这个例子中,有一些其他有趣的事情,但是case语句是关注的中心。

编写函数

[编辑 | 编辑源代码]

为了保持 Ruby 的始终面向对象的设计,函数通常被称为方法。没有区别。当我们进入对象和类时,我们将更详细地介绍方法。现在,基本的函数编写如下所示(将以下代码保存在名为 func1.rb 的文件中)

# Demonstrate a method with func1.rb
def my_function( a )
  puts "Hello, #{a}"
  return a.length
end

len = my_function( "Giraffe" )
puts "My secret word is #{len} characters long"

现在运行脚本

$ func1.rb
Hello, Giraffe
My secret word is 7 characters long

方法是用def关键字定义的,后面是函数名称。与变量一样,局部方法和类方法应该以小写字母开头。

在这个例子中,函数接受一个参数(a)并返回一个值。请注意,输入参数没有类型(即a不需要是字符串)... 这允许很大的灵活性,但也可能导致很多麻烦。该函数还使用return关键字返回单个值。从技术上讲,这不是必需的 - 函数中执行的最后一行代码的值用作返回值 - 但大多数情况下,使用return明确地使事情更加清晰。

与其他语言一样,Ruby支持参数的默认值和可变长度参数列表,我们将在适当的时候介绍这两者。还支持代码块,如下所述。

代码块

[编辑 | 编辑源代码]

Ruby 中一个非常重要的概念是代码块。这实际上并不是一个特别革命性的概念 - 每当你编写过if ... { ... }在 C 或 Perl 中,你已经定义了一个代码块,但在 Ruby 中,代码块有一些隐藏的秘密力量...

Ruby 中的代码块是用关键字do..end或花括号{..}

do
  print "I like "
  print "code blocks!"
end

{
  print "Me too!"
}

代码块的一个非常强大的用法是,方法可以将代码块作为一个参数并执行它。

[编者注:The Pragmatic Programmers 实际上想要指出,这样描述它没有太大用处。相反,代码块的行为就像一个“伙伴”,函数偶尔会将控制权交给它]

这个概念第一次解释时可能很难理解。这里有一个例子

$ irb --simple-prompt
>> 3.times { puts "Hi!" }
Hi!
Hi!
Hi!
=> 3

惊喜!你一直认为 3 只是一个数字,但它实际上是一个对象(类型为Fixnum)。因为它是一个对象,它有一个成员函数times,它将一个代码块作为参数。该函数运行代码块 3 次。

代码块实际上可以接收参数,使用特殊符号|..|。在这种情况下,快速检查times的文档表明它将把一个参数传递给代码块,指示它是哪个循环

$ irb --simple-prompt
>> 4.times { |x| puts "Loop number #{x}" }
Loop number 0
Loop number 1
Loop number 2
Loop number 3
=> 4

times函数将一个数字传递给代码块。代码块在变量x中获得该数字(由|x|设置),然后打印出结果。

函数通过yield与代码块交互。每次函数调用yield时,控制权就会传递给代码块。只有当代码块完成时,它才会返回到函数。这里有一个简单的例子

# Script block2.rb

def simpleFunction
  yield 
  yield
end

simpleFunction { puts "Hello!" }
$ block2.rb
Hello!
Hello!

simpleFunction只是简单地将控制权让给代码块两次 - 所以代码块运行两次,我们得到两倍的输出。这里有一个函数将参数传递给代码块的例子

# Script block1.rb

def animals
  yield "Tiger"
  yield "Giraffe"
end

animals { |x| puts "Hello, #{x}" }
$ block1.rb
Hello, Tiger
Hello, Giraffe

可能需要阅读几遍才能弄清楚这里发生了什么。我们定义了函数“animals” - 它期望一个代码块。当执行时,该函数调用代码块两次,第一次使用参数“Tiger”,然后再次使用参数“Giraffe”。在这个例子中,我们编写了一个简单的代码块,它只是打印出对动物的问候。我们可以编写一个不同的代码块,例如

animals { |x| puts "It's #{x.length} characters long!" }

这将给出

It's 5 characters long!
It's 7 characters long!

使用相同的函数运行两个不同的代码块会得到完全不同的结果。

代码块有很多强大的用途。您遇到的第一个用途之一是each函数用于数组 - 它为数组中的每个元素运行一个代码块 - 非常适合迭代列表。

Ruby 是真正面向对象的

[编辑 | 编辑源代码]

Ruby 是非常面向对象的。一切都是对象 - 即使是您可能认为是常量的东西。这也意味着,您可能认为的“标准函数”绝大多数并不存在于某个库中的某个地方,而是给定变量的方法。

这里有一个我们已经看到的例子

3.times { puts "Hi!" }

即使 3 看起来只是一个常数,但它实际上是类Fixnum(它继承自类Numeric,它又继承自类Object)的实例。方法times来自Fixnum,并且它只是做它声称做的事情。

这里有一些其他例子

$ irb --simple-prompt
>> 3.abs
=> 3
>> -3.abs
=> 3
>> "giraffe".length
=> 7
>> a = "giraffe"
=> "giraffe"
>> a.reverse
=> "effarig"

在接下来的章节中,我们将有充足的时间来考虑面向对象设计是如何贯穿 Ruby 的。

华夏公益教科书