Ruby 零基础教程

Ruby 变量与作用域

变量是 Ruby(以及大多数编程语言)中最基础的构建块。它们就像是带有名称的“容器”,用于存储数据,让你能在程序的各个地方操作和重复使用这些数据。

本章将详细探讨变量赋值和作用域的概念,为你高效使用变量打下坚实的基础。

1. Ruby 中的变量赋值

赋值(Assignment)就是给变量指定一个特定值的过程。在 Ruby 中,我们使用等号 = 作为赋值运算符。变量名放在 = 的左侧,要赋予的值放在右侧。

1.1 基础赋值

最简单的赋值形式是将一个字面量(比如数字、字符串或布尔值)赋给一个变量。

# 将一个整数赋值给名为 'age' 的变量
age = 30

# 将一个字符串赋值给名为 'name' 的变量
name = "Alice"

# 将一个布尔值赋值给名为 'is_student' 的变量
is_student = true

puts age        # 输出: 30
puts name       # 输出: Alice
puts is_student # 输出: true

在上述例子中,我们直接将值赋给了变量。Ruby 是动态类型语言,这意味着你不需要显式声明变量的数据类型。Ruby 会根据赋给它的值自动推断出类型。

1.2 表达式赋值

你也可以将一个表达式的计算结果赋值给变量。Ruby 会先计算 = 右侧的表达式,然后将得到的结果存入左侧的变量中。

# 赋值算术表达式的结果
width = 10
height = 5
area = width * height  # area 的值将是 50
puts area              # 输出: 50

# 赋值字符串拼接的结果
first_name = "Bob"
last_name = "Johnson"
full_name = first_name + " " + last_name # 字符串拼接
puts full_name                           # 输出: Bob Johnson

1.3 多重赋值 (Multiple Assignment)

Ruby 允许你同时为多个变量赋值,这被称为多重赋值或平行赋值。

# 将同一个值赋给多个变量
a = b = c = 10
puts a # 输出: 10
puts b # 输出: 10
puts c # 输出: 10

# 平行地将不同的值赋给多个变量
x, y, z = 1, 2, 3
puts x # 输出: 1
puts y # 输出: 2
puts z # 输出: 3

# 交换两个变量的值
a = 5
b = 10
a, b = b, a # 平行赋值轻松完成交换
puts a # 输出: 10
puts b # 输出: 5

平行赋值在需要交换变量值时特别有用,你完全不需要引入第三个临时变量。

1.4 复合赋值运算符 (Shorthand Assignment Operators)

Ruby 提供了一系列复合赋值运算符,用于简化常见的操作。这些运算符将算术或逻辑运算与赋值操作结合在了一起。

运算符示例等同于 (Equivalent to)
+=x += 5x = x + 5
-=x -= 2x = x - 2
*=x *= 3x = x * 3
/=x /= 4x = x / 4
%=x %= 2x = x % 2
**=x **= 2x = x ** 2


x = 10
x += 5  # x 现在是 15
puts x

y = 7
y *= 2  # y 现在是 14
puts y

z = 20
z /= 4  # z 现在是 5
puts z

这些复合运算符能让你的代码更加简洁易读。

2. Ruby 中的变量作用域 (Variable Scope)

作用域指的是程序中可以访问某个变量的区域。理解作用域对于避免命名冲突和确保变量被正确使用至关重要。

Ruby 有几种不同类型的作用域:局部 (local)、实例 (instance)、类 (class) 和全局 (global)。本章我们将重点关注局部作用域全局作用域。(实例变量和类变量将在后续的面向对象编程课程中介绍)。

2.1 局部变量 (Local Variables)

局部变量是最常见的变量类型。它们的作用域仅限于定义它们的代码块内部(例如,在一个方法、循环或条件语句内)。局部变量的名称必须以小写字母或下划线开头。

def my_method
  x = 10  # x 是 my_method 方法内的一个局部变量
  puts x
end

my_method # 输出: 10

# puts x  # 这行代码会引发错误,因为 x 在 my_method 方法外部是无法访问的

在这个例子中,x 只能在 my_method 方法内部访问。试图在方法外部访问它会导致错误。

# 循环中的局部变量示例
y = 20 # y 在这里可以被访问

5.times do |i|
  z = i * 2  # z 是这个 'times' 定义的区块 (block) 内的局部变量
  puts z
  puts y     # y 可以在这个区块内部被访问
end

# puts z # 这行代码会引发错误,因为 z 只存在于循环区块内部
puts y   # 没问题,输出 20

z 仅仅存在于 5.times 循环的 do...end 区块内部。而 y 存在于外部作用域,因此它在区块定义之前和区块内部都可以被访问;但如果它是在区块内部定义的,区块结束后就无法访问了。

2.2 全局变量 (Global Variables)

全局变量拥有最广的作用域;它们可以在你程序的任何地方被访问。全局变量的名称必须以美元符号 $ 开头。

虽然全局变量看起来很方便,但它们会让代码变得难以理解和维护,并且极易引发命名冲突和意想不到的副作用。因此,最佳实践是:除非绝对必要,否则尽量避免使用全局变量。

$my_global = 100  # $my_global 是一个全局变量

def another_method
  puts $my_global  # 访问全局变量
  $my_global = 200 # 修改全局变量
end

another_method     # 输出: 100
puts $my_global    # 输出: 200

在这个例子中,$my_global 可以从 another_method 内部被访问和修改。修改全局变量时必须非常小心,因为程序某个部分的更改可能会以意想不到的方式影响到其他部分。

2.3 作用域解析顺序 (Scope Resolution)

当 Ruby 代码中出现一个变量名时,Ruby 会按以下顺序寻找该变量:

  1. 局部作用域: 当前的代码块(例如:方法、循环)。
  2. 全局作用域: 全局范围(如果变量以 $ 开头)。

如果在一个更近的作用域中找到了变量名,Ruby 就会使用那个变量。如果在任何作用域中都找不到,Ruby 会抛出一个错误(如果你试图读取它的值),或者在当前作用域创建一个新的局部变量(如果你正在给它赋值)。

x = 5 # 外部的 x

def my_function
  puts x # 试图读取一个未初始化的局部变量。
  x = 10 # 内部的 x
  puts x
end

# my_function # 调用这行会引发错误

def my_function_2
  $x = 10 # 内部修改全局变量
  puts $x
end

$x = 5 # 外部的全局变量
my_function_2 # 输出: 10
puts $x       # 输出: 10

my_function 中,局部作用域内没有初始化外部变量,因此 Ruby 试图在其作用域外寻找变量。但是,因为我们在下方写了 x = 10 的赋值语句,Ruby 会认为这里的 x 是一个尚未被初始化的局部变量(从而抛出错误)。为了避免这种情况,你可以要么在读取之前初始化 x,要么使用带 $ 的全局变量。