Ruby 变量
变量是编程最基础的概念。但 Ruby 的变量系统比一般语言更"丰富"——它有五种变量,以前缀符号区分作用域。本章把每种变量的命名、作用域、用法讲透,并附带常量与并行赋值两个 Ruby 特色。
1. 局部变量(local variable)
最常见、最安全的变量。命名以小写字母或下划线开头,只在定义它的作用域里可见(方法内、块内、if 内):
# 局部变量:小写或下划线开头,只在当前作用域生效
name = "小明"
age = 18
_count = 0
puts name, age
# 出了方法就访问不到
def greet
message = "hi" # message 只在 greet 内部可见
puts message
end
greet
# puts message # ❌ 报错:undefined local variable局部变量的好处是不会污染外部作用域。方法用完就被回收,不会影响其他代码。日常写代码 95% 的变量都是局部变量。
2. 动态类型
Ruby 是动态类型语言——变量本身没有类型,值才有类型。同一个变量可以重新指向不同类型的值:
# Ruby 是动态类型:变量本身没有类型,值才有
x = 10 # 此时 x 是 Integer
puts x.class # Integer
x = "hello" # 同一个 x 重新指向字符串
puts x.class # String
x = [1, 2, 3] # 又指向数组
puts x.class # Array灵活但要注意:别滥用这个特性在同一变量上来回切换类型,会让代码难读。一般约定"一个变量一种语义"。
3. 实例变量(instance variable)
以 @ 开头,属于某个具体对象。不同对象的同名实例变量互不影响:
# 实例变量:@ 开头,属于"某个对象"
class Person
def initialize(name)
@name = name # 每个对象有自己的 @name
end
def name
@name # 实例方法里直接用
end
end
p1 = Person.new("小明")
p2 = Person.new("小红")
puts p1.name # 小明
puts p2.name # 小红
puts p1.instance_variables # [:@name]实例变量是面向对象的核心——它保存对象的"状态"。后面类与面向对象一章会深入讲。@name 这种变量在对象创建时初始化,对象销毁时被回收。
注意:未初始化的实例变量返回 nil(不是报错),所以读 @foo 不存在时得到 nil。这跟局部变量不一样——局部变量未定义就读会报错。
4. 类变量(class variable)
以 @@ 开头,属于类本身,所有对象共享同一份:
# 类变量:@@ 开头,所有对象共享
class Counter
@@count = 0 # 类变量,所有实例共享
def initialize
@@count += 1
end
def self.total
@@count
end
end
Counter.new
Counter.new
Counter.new
puts Counter.total # 3类变量常用来统计"全局信息"——比如已经创建了多少个对象、缓存配置。但现代 Ruby 社区倾向用类实例变量(@count 写在 class 上下文里)替代类变量,因为类变量在继承时行为容易出错。
5. 全局变量(global variable)
以 $ 开头,程序任何地方都能访问。但社区强烈不推荐用——它破坏封装、让代码难以追踪:
# 全局变量:$ 开头,程序任何地方都能访问(谨慎使用!)
$app_name = "我的应用"
$debug = true
def show
puts $app_name # 方法里也能访问
end
show
puts defined?($app_name) # "global-variable"
# Ruby 预定义了一些全局变量:
puts $0 # 当前脚本名
puts $$ # 当前进程 PID
puts $: # load 路径数组Ruby 预定义了一些特殊全局变量用得比较多,如 $0(脚本名)、$$(进程 PID)、$DEBUG。这些是约定俗成的,不算坏味道。但你自己写的全局变量,99% 都应该改成实例变量或常量。
6. 常量(constant)
命名以大写字母开头,约定是全程大写下划线(SCREAMING_SNAKE_CASE)。Ruby 的常量是"软"常量——重新赋值会警告但不报错:
# 常量:大写字母开头,赋值后"不应该"改(改了只警告,不报错)
MAX_SIZE = 100
API_URL = "https://api.example.com"
class Config
TIMEOUT = 30 # 类内部的常量
end
puts MAX_SIZE
puts Config::TIMEOUT # 用 :: 访问类里的常量
# 重新赋值会警告:
MAX_SIZE = 200
# warning: already initialized constant MAX_SIZE类内部的常量用 :: 访问(如 Config::TIMEOUT),这是 Ruby 的作用域操作符。
7. 并行赋值(Ruby 特色)
Ruby 支持一次性给多个变量赋值,甚至能直接交换变量:
# 并行赋值:Ruby 一个很有特色的语法
a, b, c = 1, 2, 3
puts a, b, c # 1 2 3
# 交换两个变量,不需要临时变量
a, b = b, a
puts a, b # 2 1
# 从方法返回多个值
def min_max(arr)
[arr.min, arr.max]
end
lo, hi = min_max([3, 1, 4, 1, 5, 9])
puts lo, hi # 1 9这个语法在实际项目里用得很多,尤其是方法返回多值的场景。本质是利用了 Ruby 的"多返回值是数组解构"的语法糖。
8. 五种变量对照表
- 局部变量
name:方法/块内可见,小写开头。 - 实例变量
@name:某个对象内部可见,对象销毁即回收。 - 类变量
@@count:类与所有实例共享。 - 全局变量
$app:整个程序可见,谨慎用。 - 常量
MAX:大写开头,定义后不应改。
小结
本章你认识了 Ruby 的五种变量,以及它们的作用域前缀符号。记住口诀:无前缀是局部,@ 是对象,@@ 是类,$ 是全局,大写是常量。下一篇我们看 数据类型——这些变量里能装什么样的值。
← 上一篇 Ruby 基础语法
下一篇 Ruby 数据类型 →