变量是存储数据的地方,每个变量都有一个唯一的名称。 有一些命名约定适用于变量名。 变量保存对象。 更准确地说,它们是指位于计算机内存中的特定对象。 每个对象都是特定的数据类型。 有内置数据类型和自定义数据类型。 Ruby 属于动态语言家族。 与 Java,C 或 Pascal 等强类型语言不同,动态语言不会将变量声明为某些数据类型。 取而代之的是,解释器在分配时确定数据类型。 随着时间的流逝,Ruby 中的变量可以包含不同的值和不同类型的值。
变量一词来自这样一个事实,即变量与常量不同,可以随时间采用不同的值。 在上面的示例中,有一个名为 i 的变量。 首先为它分配一个值 5,然后给它一个不同的值 7。
Ruby 变量命名约定
像其他任何编程语言一样,Ruby 也有一些变量标识符的命名约定。
Ruby 是区分大小写的语言。 这意味着 age 和 Age 是两个不同的变量名称。 大多数语言区分大小写。 BASIC 是一个例外。 这是一种不区分大小写的语言。 虽然我们可以通过更改字符的大小写来创建不同的名称,但不建议这样做。
该代码示例定义了两个变量:I 和 i。 它们具有不同的价值。
case.rb 示例的输出。
Ruby 中的变量名可以由字母数字字符和下划线_
字符创建。 变量不能以数字开头。 这使解释器更容易区分文字数和变量。 变量名不能以大写字母开头。 如果标识符以大写字母开头,则在 Ruby 中将其视为常量。
在此脚本中,我们显示了一些有效的变量名。
变量名应为有意义的。 选择变量的描述性名称是一种很好的编程习惯。 这些程序更具可读性。
该脚本显示了三个描述性变量名。 与程序员相比,place_of_birth 对程序员的描述更多。 pob。 通常认为在循环中选择简单的变量名是可以的。
Ruby 标记
变量标识符可以以也称为信号符的特殊字符开头。 标记是附加到标识符的符号。 Ruby 中的变量信号表示变量作用域。 这与 Perl 相反,后者的信号符号表示数据类型。 Ruby 变量信号为$
和@
。
我们有四个范围不同的变量。 范围是可以引用变量的范围。 我们使用特殊的内置方法来确定变量的范围。
没有符号的变量是局部变量。 局部变量仅在局部有效:例如,在方法,块或模块内部。
全局变量以$
字符开头。 它们在任何地方都有效。 程序中应限制全局变量的使用。
以@
标记开头的变量名称是实例变量。 此变量在对象内部有效。
最后,我们有一个类变量。 此变量对特定类的所有实例均有效。
local_variables
给出了在特定上下文中定义的所有局部变量的数组。 我们的上下文是 Ruby 顶级。
同样,global_variables
产生一个全局数组。 我们不会将所有全局变量打印到终端,因为其中有很多。 每个 Ruby 脚本都以一堆预定义变量开头。 取而代之的是,我们调用数组的include?
方法来检查是否在数组中定义了我们的全局变量。 还要注意,我们使用变量符号来引用变量。 (符号以冒号开头。)
self
伪变量指向instance_variables
方法的接收者。 在我们的例子中,接收者是main
,这是 Ruby 顶级执行区域。
最后,我们有一组类变量。 main
是Object
类的实例。
示例的输出。 我们看到变量的符号名称。
Ruby 局部变量
局部变量是在 Ruby 源代码的局部区域内有效的变量。 该区域也称为本地范围。 局部变量存在于 Ruby 模块,方法,类的定义中。
我们有一个叫做method1
的方法,它有一个变量。 该变量是局部的。 这意味着它仅在方法定义内有效。 我们只能在方法名称和end
关键字之间引用x
变量。
这是method1
方法的定义。 在方法内部,我们创建一个本地x
变量。 我们将变量的值打印到终端。
该方法被调用。
我们尝试引用方法定义之外的局部变量。 这导致NameError
。 Ruby 解释器找不到此类标识符。
运行示例将得到以上输出。
以下示例是对先前示例的略微修改。
我们有两个x
变量。 一个在method1
内部定义,另一个在外部定义。 它们是两个不同的局部变量。 他们不会互相冲突。
我们创建了一个本地x
变量,该变量保留值 5。该变量在主执行区的本地范围内有效。 在method1
内部无效。
在method1
的定义内,定义了一个新的局部变量x
。 它的值为 10。它存在于method1
方法的主体中。 在end
关键字之后,它不再存在。
输出。
如果方法采用参数,则会为每个参数创建一个局部变量。
我们有一个方法定义,它有两个值。 该方法返回矩形的面积。
rectangular_area 方法采用两个参数。 它们是矩形的边,我们将为其计算面积。 将自动为标识符 a 和 b 创建两个局部变量。 我们调用local_variables
方法来查看该方法中包含哪些局部变量。
在这里,我们将两个值传递给方法rectangle_area
。 这些值将分配给在方法内部创建的两个局部变量。
输出显示三件事。 前两个是 rectangular_area 方法中局部变量的名称。 第三是给定矩形的计算面积。
可以在另一个方法内部定义一个方法。 内部方法具有自己的局部变量。
在这个 Ruby 脚本中,我们创建三个方法。 method2
和method3
是内部方法。 method2
定义在method1
内部,method3
定义在method2
内部。 每个方法的局部变量只能在定义它们的方法中访问。
从输出中我们可以看到 method1 有两个局部变量m1
和m2
。 内部的method2
具有局部变量m3
和m4
。 最里面的方法method3
具有局部变量m5
和m6
。
本节的最后一个示例将展示本地范围的一些演示。
在代码示例中,我们在模块,方法,类和顶层内部创建局部变量。 local_variables
是Kernel
模块的一种方法,它返回所有当前的局部变量。
模块是方法和常量的集合。 我们创建两个局部变量m1
和m2
。
在method1
中创建了两个局部变量v
和w
。
x
和y
局部变量在Some
类的定义内创建。
最后,创建两个属于 Ruby 顶级本地范围的本地变量。
输出显示每个局部作用域的局部变量。
Ruby 全局变量
全局变量在脚本中的任何地方都有效。 他们以 Ruby 中的$
标记开头。
不鼓励使用全局变量。 全局变量很容易导致许多编程错误。 仅在有理由时才使用全局变量。 建议程序员尽可能使用局部变量来代替全局变量。
在示例中,我们有一个全局变量$gb
。 我们展示了可以在模块,方法,类和顶级中引用该变量。 全局变量$gb
在所有这些实体中均有效。
创建一个全局变量$gb
; 它的价值为 6。
在模块的定义内,我们打印全局变量的值。
在方法的定义内,我们打印全局变量的值。
在类的定义内,我们打印全局变量的值。
最后,在顶层执行区域中,我们将打印全局变量的值以及该变量是否在global_variables
方法生成的数组中。
该示例的输出确认了全局变量可在任何地方访问。
当 Ruby 脚本启动时,它可以访问多个预定义的全局变量。 这些全局变量不被认为是有害的,可以帮助解决常见的编程工作。
该脚本显示了$LOAD_PATH
全局变量。 该变量列出了通过load
和require
方法搜索的目录。 $:
是$LOAD_PATH
名称的简短同义词。
更多全局变量将在本章的“预定义变量”部分中介绍。
Ruby 实例,类变量
在本节中,我们将简要介绍实例变量和类变量。 它们将在面向对象的编程章节中更详细地描述。
实例变量是属于特定对象实例的变量。 每个对象都有其自己的对象变量。 实例变量以@
标记开头。 类变量属于特定类。 从特定类创建的所有对象共享类变量。 类变量以@@
字符开头。
我们创建一个自定义的Being
类。 Being
类具有一个类和一个实例变量。
@@is
是一个类变量。 Being
类的所有实例都共享此变量。 此示例的逻辑是Being
是,NotBeing 不是。
initialize
方法是一个构造函数。 创建对象时将调用该方法。 创建一个@name
实例变量。 此变量特定于具体对象。
当对象是打印方法的参数(例如p
或puts
)时,将调用to_s
方法。 在我们的情况下,该方法给出了对象的简短人类可读描述。
does_exist?
方法返回类变量。
从Being
类中创建了三个对象。 每个对象都有不同的名称。 对象的名称将存储在实例方法中,该方法对于每个对象实例都是唯一的。 这将在to_s
方法中使用,该方法给出了对象的简短说明。
p
方法将创建的对象作为三个参数。 它在每个这些对象上调用to_s
方法。
最后,我们调用每个实例的does_exist?
方法并打印其返回值。 这三个方法的输出是相同的,因为每个方法都返回类变量。
示例的输出。 前三个消息是唯一的。 字符串存储在对象的实例变量中。 真实值是类变量的值,它被调用了三次。
Ruby 环境&命令行变量
ENV
常数允许访问环境变量。 这是一个 Ruby 哈希。 每个环境变量都是ENV
哈希的键。
ARGV
常量保存命令行参数值。 它们在脚本启动时由程序员传递。 ARGV
是一个将参数存储为字符串的数组。 $*
是ARGV
的别名。
ENV
和ARGV
都是全局常数。
在脚本中,我们遍历ARGV
数组并打印其每个值。
我们给出了三个命令行参数。 它们被打印到控制台,每个都打印在单独的行上。
以下示例将处理环境变量。
该脚本会将三个环境变量的值输出到终端。 这些值取决于我们操作系统的 OS 设置。
样本输出。
Ruby 伪变量
Ruby 具有一些称为伪变量的变量。 它们不同于常规变量。 我们不能为伪变量赋值。
self
是当前方法的接收者。 nil
是NilClass
的唯一实例。 它表示一个值的缺失。 true
是TrueClass
的唯一实例。 它表示布尔值 true。 false
是FalseClass
的唯一实例。 它表示布尔值 false。
true 和 false 是布尔数据类型的值。 从另一个角度来看,它们是特定类的实例。 这是因为 Ruby 中的所有内容都是一个对象。 这看起来不必要地复杂。 但这是上述 Ruby 习惯用法的结果。
这是伪变量的示例。 我们使用p
方法打印所有四个伪变量。 然后我们找出所有它们的类名。
在这种情况下,self
伪变量返回主执行上下文。
示例输出。
在本节的第二个示例中,我们将进一步查看self
。
如前所述,self
引用了当前方法的接收者。 上面的示例显示了不同接收器的三个示例。
接收器是称为Some
的类。
这是另一个接收器:名为Other
的类。
第三个接收器是 Ruby 顶级。
示例输出。
本节的最后一个示例将展示其他三个伪变量。
上面的示例显示了正在使用的true
,false
和nil
伪变量。
true
用于布尔表达式。 该消息始终被打印。
此消息从不打印。 不满足条件。 在布尔表达式中,我们总是得到一个负值。
如果引用了全局值且尚未初始化,则它们包含nil
伪变量。 它代表没有价值。
伪脚本 pseudo2.rb 的输出。
Ruby 预定义变量
Ruby 有很多预定义的全局变量。 这是 Perl 语言的传承。 Ruby 受 Perl 的强烈影响。 当 Ruby 脚本启动时,它们是可访问的。 我们为预定义的 Ruby 变量提供了一些示例。
已经使用了三个预定义变量:$0
,$*
和$$
。 $0
存储当前脚本名称。 $*
变量存储命令行参数。 并且$$
存储脚本的 PID(进程 ID)。
样本输出。
$?
全局变量存储最后执行的子进程的退出状态。
我们运行两个外部子进程,并使用$?
变量检查其退出状态。
使用system
方法,我们启动了一个子进程。 这是一个 echo bash 命令,该命令将消息输出到终端。
在第二种情况下,我们以状态 1 执行 bash exit
命令。这一次,我们使用%x
运算符在两个选定的定界符之间执行命令。 我们选择了[]
字符。
第一个子进程以状态 0 终止,第二个子进程以退出状态 1 终止。
$;
变量具有String
类的split
方法的默认分隔符。
我们使用$;
变量来控制如何使用split
方法剪切字符串。 该方法带有一个参数,该参数指示应在何处分割字符串。 如果省略该参数,则使用$;
中的值。
我们为$;
变量指定分隔符。 split 方法不带参数,因此使用$;
的值。
在第一种情况下,字符串未拆分。 在第二种情况下,按照我们的预期正确分割了字符串。
在最后一个示例中,我们显示了三个与正则表达式一起使用的全局预定义变量。
当我们在字符串上应用=~
运算符时,Ruby 会设置一些变量。 $&
变量的字符串与最后一个正则表达式匹配相匹配。 $``在
$&之前有一个字符串,
$’在
$&`之后有一个字符串。