Ruby 编程/Ruby 基础
与本教程的其余部分一样,我们假设您对编程语言概念(例如 if 语句、while 循环)有一定的了解,并且还对面向对象编程有一定的了解。
当我们讨论类和对象时,我们将更深入地处理变量。现在,让我们简单地说,您的基本局部变量名称应该以小写字母或下划线开头,并且应该包含大写或小写字母、数字和下划线字符。全局变量以$.
Ruby 包含一套非常标准的循环和分支结构if, while和case
例如,这里是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 中的语法,其中if和unless语句可以用作语句之后的条件修饰符。例如
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 是非常面向对象的。一切都是对象 - 即使是您可能认为是常量的东西。这也意味着,您可能认为的“标准函数”绝大多数并不存在于某个库中的某个地方,而是给定变量的方法。
这里有一个我们已经看到的例子
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 的。