[翻译]Ruby教程4——变量

变量

在这章的教程中我们将详细介绍变量。


变量是保存数据的地址。每个变量都有唯一的一个名字,变量命名存在着一些约定。变量保存着数据对象,更确切的说变量是对数据所在的计算机内存地址的引用。每一个对象都具有一定的数据类型,内置的类型或者自定义的类型。Ruby属于动态语言,与Java、C或者Pascal之类的强类型语言不同,动态语言不用为变量定义确切数据类型,而是解释器在分配变量时决定它的类型。在Ruby中程序运行过程变量可以包含不同类型的不同值。



#!/usr/bin/ruby


i = 5

puts i

i = 7

puts i



变量是可变的,与常量不同,在程序运行过程中它们可以保存不同的值。在上面这个例子中有一个名为i的变量,首先赋值为5,然后又改为7。


命名约定


与其他语言一样,Ruby对变量标识符也有些命名约定。

Ruby是区分大小写的,这意味着ageAge是两个变量名。许多语言都是区分大小写的,但是BASIC例外。我们改变字符的大小写可以创建不同的变量,但是不推荐这种做法。



#!/usr/bin/ruby


i = 5

p i

I = 7

p I



这个例子定义了两个变量Ii,它们保存了不同的值。


./case.rb

5

7


以上是case.rb脚本的输出结果。




在Ruby中变量名可由字母数字和下划线组成。为了使解释器能简单的从字面上区分数字和变量,变量名不能以数字开头。变量名同样也不能以大写字母开头,在Ruby中以大写字母开头会被认为是常量。



#!/usr/bin/ruby


name = “Jane”

placeOfBirth = “Bratislava”

placeOfBirth = “Kosice”

favorite_season = “autumn”


n1 = 2

n2 = 4

n3 = 7


p name, placeOfBirth, favorite_season

p n1, n2, n3



在这个脚本中我们展示一些变量的命名。




变量名应该是有意义的。好的编程习惯是给变量取个具有描述性的名字,使得程序更加可读。


#!/usr/bin/ruby

name = “Jane”
place_of_birth = “Bratislava”
occupation = “student”

i = 5
while i > 0 do
puts name
i -= 1
end

这个脚本展示三个具有描述性的变量名。对于程序员来说place_of_birth比其他的名字如pob更具有描述性。在循环的时候通常选择一个比较简单的变量名。


印章(Sigils)


变量标识符可以以一些特殊的印章(Sigils)符号开头。印章(Sigils)是附加在标识符上的符号。在Ruby中变量印章(Sigils)表示了变量的作用域范围。在Perl中它是表示数据的类型。Ruby的变量印章(Sigils)符号有$@



#!/usr/bin/ruby


tree_name = “pine”

$car_name = “Peugeot”

@sea_name = “Black sea”

@@species = “Cat”


p local_variables

p global_variables.include? :$car_name

p self.instance_variables

p Object.class_variables



我们定义了四个不同作用域范围的变量。作用域表示了该变量可以被引用到的范围。我们使用了内置的方法来决定变量的作用域。



tree_name = “pine”



不包含印章(Sigils)符号的变量是一个局部变量。局部变量只在局部有效,如在方法、代码块、模块内。



$car_name = “Peugeot”



全局变量以$符号开头。它们在所有地方都是有效的。在程序中不要滥用全局变量。



@sea_name = “Black sea”



实例变量是以@符号开头。它只有在实例对象中才有效。



@@species = “Cat”



最后我们定义了一个类变量。它在所有属于这个类的实例中都有效。



p local_variables



local_variables是保存了当前环境下所有定义的局部变量的数组。



p global_variables.include? :$car_name



类似的,global_variables是保存的全部全局变量的数组。由于全局变量很多,我们就不将它们全部在终端上打印了。每次Ruby脚本启动时都会预定义一些变量。我们使用数组的include?方法来检查我们全局变量是否定义了。同时请注意我们引用变量是用的符号。(符号是以一个冒号开头)



p self.instance_variables



self伪变量指向了instance_variables方法的接收对象。这个例子中的接收对象是main,Ruby的顶级执行区域。



p Object.class_variables



最后我们获取所有的类变量数组。main是一个Object类的实例。


$ ./sigils.rb

[:tree_name]

true

[:@sea_name]

[:@@species]


以上是这个例子的输出结果,我们看到了变量的符号名。


局部变量


局部变量是只在Ruby源代码的局部区域有效。这个区域也称为局部作用域。局部变量是在Ruby的模块、方法、类中定义。


#!/usr/bin/ruby

def method1
x = 5
p x
end

method1

p x

我们定义了一个名为method1的方法,它有一个变量。这个变量是局部变量。这意味着这个变量只在这个方法内有效。我们只能在这个方法名到end关键字之间访问x变量。


def method1
x = 5
p x
end

以上定义了一个method1方法。在方法内部创建了一个局部变量x,然后将它的值打印到终端。



method1



方法被调用。



p x



我们试图在方法外部访问这个局部变量。这将导致NameError错误,Ruby解释器找不到这个标识符。


$ ./locals.rb

5

./locals.rb:11:in <main>’: undefined local variable
or method
x’ for main:Object (NameError)


以上是这个例子的输出结果。




以下例子是对前一个例子的简单修改。


#!/usr/bin/ruby

x = 5

def method1
x = 10
p x
end

method1

p x

我们定义了两个x变量。一个是在method1内部定义的,另一个是在外部定义的。他们是两个不同的局部变量,并不会相互冲突。


x = 5

我们创建了一个局部变量,它的值为5。这个变量的局部作用范围是main区域。它在method1内部是无效的。


def method1
x = 10
p x
end

method1内部创建了一个新的x局部变量,它的值是10.它存在于method1方法内部,在end关键字之后就会失效。


$ ./locals2.rb

10

5


以上是输出结果。




如果一个方法接收了参数,那么就会创建与这些参数相对应的局部变量。


#!/usr/bin/ruby


def rectangle_area a, b
puts local_variables
return a b
end

puts rectangle_area 5, 6

我们定义了一个方法,它接收两个值,然后返回这个矩形的面积。


def rectangle_area a, b
puts local_variables
return a b
end

rectangle_area方法接收两个参数。它们是矩形的边长,然后我们计算它的面积。对应于标识符ab的两个局部变量将自动创建了。我们调用local_variables方法查看方法内部的所有局部变量。


puts rectangle_area 5, 6

这里我们给rectangle_area方法传了两个值。这两个值将会分配给在方法内部创建的两个局部变量。


$ ./parameters.rb

a

b

30


输出了三个结果。前两个是rectangle_area方法内部的局部变量名。第三个是面积的计算结果。




一个方法可以定义在另一个方法的内部。内嵌方法有它自己的局部变量。


#!/usr/bin/ruby

def method1

def method2

def method3
m5, m6 = 3
puts “Level 3”
puts local_variables
end

m3, m4 = 3
puts “Level 2”
puts local_variables
method3
end

m1, m2 = 3
puts “Level 1”
puts local_variables
method2

end

method1

在这个Ruby脚本中我们创建了三个方法。method2method3是内嵌方法。method2定义在method1内部,method3又定义在method2内部。每一个方法的局部变量仅在这个方法内是可访问的。


$ ./lms.rb

Level 1

m1

m2

Level 2

m3

m4

Level 3

m5

m6


从输出结果我们可以知道method1有两个局部变量m1m2。内嵌方法method2的局部变量有m3m4。最内部的方法method3的局部变量是m5m6




这一节的最后一个例子将展示一些局部作用域的示范。


module ModuleM
m1, m2 = 4

puts “Inside module”
puts local_variables
end


def method1
v, w = 3
puts “Inside method”
puts local_variables
end


class Some
x, y = 2
puts “Inside class”
puts local_variables
end

method1

t1, t2 = 7

puts “Inside toplevel”
puts local_variables

在这个例子我们分别在模块、方法、类和顶级环境中创建局部变量。local_variables是内核模块的一个方法,用于获取当前的所有局部变量。


module ModuleM
m1, m2 = 4

puts “Inside module”
puts local_variables
end

模块是一个方法和常量的集合。我们创建了两个局部变量m1m2


def method1
v, w = 3
puts “Inside method”
puts local_variables
end

method1方法中创建了两个局部变量vw


class Some
x, y = 2
puts “Inside class”
puts local_variables
end

Some类中创建了两个局部变量xy


t1, t2 = 7

最后我们为Ruby顶级环境创建两个局部变量。


$ ./locals3.rb

Inside module

m1

m2

Inside class

x

y

Inside method

v

w

Inside toplevel

t1

t2


输出结果展示了各个作用域的局部变量。


全局变量


全局变量可以在脚本的任何地方访问到。它们以$符号开头。

全局变量可能会引起很多程序错误,因此不鼓励使用全局变量。除非有原因要使用,否则建议使用局部变量。


#!/usr/bin/ruby

$gb = 6


module ModuleM
puts “Inside module”
puts $gb
end


def method1
puts “Inside method”
puts $gb
end


class Some
puts “Inside class”
puts $gb
end

method1

puts “Inside toplevel”
puts $gb
puts global_variables.include? :$gb

在这个例子中我们创建了一个全局变量$gb。这个变量在模块、方法、类和顶级环境都可以访问。全部变量$gb是所有的实体中都是有效的。


$gb = 6

创建全局变量$gb,它的值为6。


module ModuleM
puts “Inside module”
puts $gb
end

在一个模块定义中我们打印全局变量的值。


def method1
puts “Inside method”
puts $gb
end

在一个方法定义中我们打印全局变量的值。


class Some
puts “Inside class”
puts $gb
end

在一个类定义中我们打印全局变量的值。


puts $gb
puts global_variables.include? :$gb

在顶级环境下打印全局变量的值,并检查这个变量是否为全局变量。


$ ./globals.rb

Inside module

6

Inside class

6

Inside method

6

Inside toplevel

6

true


这个例子的输出结果确认了全局变量可以任何地方访问到。




当一个Ruby脚本启动时,它会访问多个预定义的全局变量。这些全局变量不认为有害并且能帮助完成一些常见的任务。


#!/usr/bin/ruby

p $LOAD_PATH
p $:

这个脚本显示了$LOAD_PATH这个全局变量。这个变量列出了require方法会搜索的所有目录。$:$LOAD_PATH的缩写。

更多的全局变量会在本章的变量预定义这节中介绍。


实例变量、类变量


在这节将简要的介绍下实例变量和类变量。它们将会在面向对象那一章详细介绍。

实例变量是属于具体某个对象实例的变量。每个对象都有它自己的变量。实例变量以@符号开头。类变量属于特定某个类的。这个类所创建的对象实例共享这个类的类变量。类变量以@@符号开头。


#!/usr/bin/ruby

class Being

@@is = true

def initialize nm
@name = nm
end

def to_s
“This is #{@name}”
end

def does_exist?
@@is
end
end

b1 = Being.new “Being 1”
b2 = Being.new “Being 2”
b3 = Being.new “Being 3”

p b1, b2, b3

p b1.does_exist?
p b2.does_exist?
p b3.does_exist?

我们创建一个自定义Being类。这个Being类有一个类变量和一个实例变量。


class Being
@@is = true

@@is是一个类变量。这个类变量被所有Being类的实例所共享。这个例子的逻辑是判断是不是Being


def initialize nm
@name = nm
end

initialize方法是构造函数。这个方法在对象被创建时调用。用于创建@name实例变量。


def to_s
“This is #{@name}”
end

当这个对象作为打印方法如p或者puts的参数时to_s method方法会被调用。这个方法返回这个对象便于人类阅读的描述内容。


def does_exist?
@@is
end

does_exist?返回类变量。


b1 = Being.new “Being 1”
b2 = Being.new “Being 2”
b3 = Being.new “Being 3”

创建Being类的三个实例对象。每个对象拥有不同的名字。这个名字存储在实例变量中,对于每个对象它是唯一的。名字将会在to_s方法中使用,用于返回一个对该对象的简短描述。


p b1, b2, b3

这个方法将刚创建的三个对象作为参数,它将调用每个对象的to_s方法。


p b1.does_exist?
p b2.does_exist?
p b3.does_exist?

最后我们调用每个实例对象的does_exist?方法。这三个方法会输出相同的结果,因为这个方法返回的是类变量。


$ ./icvars.rb
This is Being 1
This is Being 2
This is Being 3
true
true
true

以上是这个例子的输出结果。前三条信息是唯一的,因为这个字符串是存储在实例变量中的。true值是类变量,它被调用的三次。


环境&命令行变量


可以用ENV常量来访问环境变量。它是一个Ruby的hash对象。每个环境变量都是ENV这个hash对象的键值。


ARGV常量存储了命令行的参数值。它们是在脚本启动时传递的。ARGV是一个数组,参数以字符串存储。SARGV的别名。


ENVARGV都是全局常量。


#!/usr/bin/ruby

ARGV.each do |a|
puts “Argument: #{a}”
end

这个脚本我们通过循环遍历打印了ARGV的每个值。


$ ./commandline.rb 1 2 3

Argument: 1

Argument: 2

Argument: 3


我们给了三个命令行参数。它们在终端上各打印了一行。




接下来的例子介绍了处理环境变量。


#!/usr/bin/ruby

puts ENV[‘SHELL’]
puts ENV[‘LANG’]
puts ENV[‘TERM’]

这个脚本在终端上打印了三个环境变量的值。这些变量值的内容依赖于我们操作系统的系统设置。


$ ./environment.rb

/bin/bash

en_US.utf8

xterm


以上是一个输出例子。


伪变量


在Ruby中有一些变量被称作伪变量。它们不同于常规的变量,不能给它们设置值。

self是当前方法的接收者。nilNilClass的唯一实例,它代表值不存在。trueTrueClass的唯一实例,它代表布尔真。flaseFalseClass是唯一实例,它代表布尔假。

truefalse是布尔数据类型。从另一个角度来看他们是特殊的类实例,这是因为在Ruby中一切皆对象。


#!/usr/bin/ruby

p self
p nil
p true
p false

p self.class
p nil.class
p true.class
p false.class

这是一个伪变量的例子。我们打印所有的伪变量,然后再看它们的类名。


p self

在当前上下文self伪变量返回的是main执行的上下文。


$ ./pseudo.rb

main

nil

true

false

Object

NilClass

TrueClass

FalseClass


以上是例子的输出结果。




在本节的第二个例子,我们将进一步分析self


#!/usr/bin/ruby

class Some
puts self
end

class Other
puts self
end

puts self

之前我们说过,self是对当前方法接收者的引用。以上例子展示了三个不同的接收者。


class Some
puts self
end

这个接收者名为Some


class Other
puts self
end

这是另一个接收者,名为:Other


puts self

第三个接收者是Ruby顶级环境。


$ ./pseudoself.rb

Some

Other

main


以上是例子的输出结果。




本节的最后一个例子展示了另外三个伪变量。


#!/usr/bin/ruby

if true
puts “This message is shown”
end

if false
puts “This message is not shown”
end

p $name
p $age

上面的例子展示了truefalsenil伪变量。


if true
puts “This message is shown”
end

true用于布尔表达式中。这条消息总是会打印的。


if false
puts “This message is not shown”
end

这条消息永远不会打印。这个条件不成立。这个布尔表达式总是会返回一个负值。


p $name
p $age

如果全局变量没有初始化就引用,那么它们就会包含一个nil伪变量。这代表值不存在。


$ ./pseudo2.rb

This message is shown

nil

nil


以上是pseudo2.rb脚本的输出结果。


预定义变量


Ruby中有很多预定义的全局变量。这是继承到Perl,Ruby受Perl的影响很大。Ruby脚本启动之后就可以访问这些变量了。接下来有些例子展示预定义变量。


#!/usr/bin/ruby

print “Script name: “, $0, “\n”
print “Command line arguments: “, $, “\n”

puts “Process number of this script: #{$$}”

以上使用了三个预定义变量。$0$$$$0存储了当前脚本的名字。$存储了命令行参数。 $$存储了当前脚本程序的PID。


$ ./predefined.rb 1 2 3

Script name: ./predefined.rb

Command line arguments: [“1”, “2”, “3”]

Process number of this script: 3122


以上是一个输出例子。




$?全局变量存储了最后一个子进程的退出状态。


#!/usr/bin/ruby

system ‘echo “Ruby”‘
puts $?

%x[exit ‘1’]
puts $?

我们执行两个子进程,然后使用$?查看它们的退出状态。


system ‘echo “Ruby”‘
puts $?

使用system方法启动一个子进程。它是一个bash的echo命令,用于在终端输出消息。


%x[exit ‘1’]
puts $?

第二个情况是使用状态1执行bash的exit命令。这次我们使用%x 操作符,用于执行一条被分隔符所选择的命令。


$ ./predefined2.rb

Ruby

pid 3131 exit 0

pid 3133 exit 1


第一个子进程退出状态为0,第二为1。




$;变量存储了字符串split方法的默认分隔符。


#!/usr/bin/ruby

str = “1,2,3,4,5,6,7”
p str.split

$; = “,”
p str.split

我们使用$;变量来控制字符串的split方法是如何分隔的。这个方法接收一个参数,用于确定字符串应该何处分隔。 如果这个参数省略了,那么将会使用$;的值。


$; = “,”
p str.split

我们为$;分隔符指定个值。当split方法没有传递参数时,$;的值将会被使用。


$ ./predefined3.rb

[“1,2,3,4,5,6,7”]

[“1”, “2”, “3”, “4”, “5”, “6”, “7”]


在第一种情况下字符串没有被分割,第二种情况下字符串正确的被分割了。




最后我们展示三个用于正则表达式的全局预定义变量。


#!/usr/bin/ruby

“Her name is Jane” =~ /name/

p $p $&amp; p $' </code></pre> <p>当我们对字符串使用<em>=~</em>保用符时,Ruby设置了一些变量。<em>$&amp;</em>变量设为最后一个匹配该正则式的内容。<em>$设为$&之前的内容.$’$&之后的内容。


$ ./predefined4.rb

“Her “

“name”

“ is Jane”


以上是这个例子的输出结果。


在这一章的教程中我们深入的学习了Ruby的变量。




原文地址: http://zetcode.com/lang/rubytutorial/variables/

翻译:龙昌 admin@longchangjin.cn

完整教程:https://github.com/wusuopu/Ruby-tutorial