Ruby 变量
变量是编程中的基本概念,用于存储和操作数据。Ruby提供了多种类型的变量,每种都有其特定的作用域和用途。本章将详细介绍Ruby中的各种变量类型及其使用方法。
📦 变量类型概述
Ruby中有四种主要的变量类型:
- 局部变量 - 在方法或代码块内使用
- 实例变量 - 属于对象实例
- 类变量 - 属于类本身
- 全局变量 - 在整个程序中都可访问
🏠 局部变量
基本概念
局部变量只在定义它们的方法或代码块内可见,以小写字母或下划线开头。
ruby
# 局部变量定义
name = "张三"
age = 25
_score = 95
# 在方法中使用局部变量
def calculate_area(length, width)
# length和width是参数局部变量
area = length * width # area是方法内的局部变量
area # 返回值
end
puts calculate_area(5, 3) # 15作用域
ruby
def method1
local_var = "方法1中的局部变量"
puts local_var
end
def method2
# puts local_var # 错误:无法访问其他方法的局部变量
local_var = "方法2中的局部变量"
puts local_var
end
method1 # 输出: 方法1中的局部变量
method2 # 输出: 方法2中的局部变量代码块中的局部变量
ruby
# 代码块可以访问外部的局部变量
outer_var = "外部变量"
[1, 2, 3].each do |item|
# item是代码块参数
puts "#{outer_var}: #{item}"
end
# 输出:
# 外部变量: 1
# 外部变量: 2
# 外部变量: 3
# 使用分号分隔代码块局部变量
[1, 2, 3].each do |item; block_local|
block_local = item * 2
puts "#{item} * 2 = #{block_local}"
end变量赋值和并行赋值
ruby
# 基本赋值
x = 10
y = 20
# 并行赋值
a, b = 1, 2
puts "a = #{a}, b = #{b}" # a = 1, b = 2
# 交换变量值
a, b = b, a
puts "a = #{a}, b = #{b}" # a = 2, b = 1
# 数组解构
first, *rest = [1, 2, 3, 4, 5]
puts "first = #{first}" # first = 1
puts "rest = #{rest}" # rest = [2, 3, 4, 5]
# 忽略某些值
_, second, _ = [1, 2, 3]
puts "second = #{second}" # second = 2🎯 实例变量
基本概念
实例变量属于特定的对象实例,以@符号开头,在对象的整个生命周期内都存在。
ruby
class Person
def initialize(name, age)
@name = name # 实例变量
@age = age # 实例变量
end
def introduce
puts "我是#{@name},今年#{@age}岁"
end
def have_birthday
@age += 1 # 修改实例变量
puts "生日快乐!现在#{@age}岁了"
end
def name
@name # 访问实例变量
end
end
person = Person.new("张三", 25)
person.introduce # 我是张三,今年25岁
person.have_birthday # 生日快乐!现在26岁了
puts person.name # 张三实例变量的作用域
ruby
class Counter
def initialize
@count = 0 # 每个实例都有自己的@count
end
def increment
@count += 1
end
def count
@count
end
def reset
@count = 0
end
end
counter1 = Counter.new
counter2 = Counter.new
counter1.increment
counter1.increment
puts counter1.count # 2
puts counter2.count # 0 (不同的实例)
counter2.increment
puts counter2.count # 1
puts counter1.count # 2 (不受影响)实例变量的默认值
ruby
class Example
def initialize
# 未初始化的实例变量默认为nil
puts @uninitialized.inspect # nil
end
def set_value
@value = "已设置"
end
def get_value
@value # 如果未设置,返回nil
end
end
example = Example.new
puts example.get_value.inspect # nil
example.set_value
puts example.get_value # 已设置🏢 类变量
基本概念
类变量属于类本身,被该类的所有实例共享,以@@符号开头。
ruby
class Counter
@@total_count = 0 # 类变量
def initialize
@instance_count = 0
@@total_count += 1
end
def increment
@instance_count += 1
end
def instance_count
@instance_count
end
def self.total_count
@@total_count # 访问类变量
end
def self.reset_total
@@total_count = 0 # 修改类变量
end
end
# 创建实例
counter1 = Counter.new
counter2 = Counter.new
counter3 = Counter.new
puts Counter.total_count # 3
counter1.increment
counter1.increment
puts counter1.instance_count # 2
puts counter2.instance_count # 0 (不同的实例变量)
# 所有实例共享类变量
puts Counter.total_count # 3类变量的继承
ruby
class Parent
@@class_var = "父类变量"
def self.get_class_var
@@class_var
end
def self.set_class_var(value)
@@class_var = value
end
end
class Child < Parent
# 子类共享父类的类变量
end
puts Parent.get_class_var # 父类变量
puts Child.get_class_var # 父类变量
# 修改类变量会影响所有类
Child.set_class_var("修改后的值")
puts Parent.get_class_var # 修改后的值
puts Child.get_class_var # 修改后的值类变量的注意事项
ruby
class A
@@value = 1
def self.value
@@value
end
end
class B < A
@@value = 2 # 修改父类的类变量
end
class C < A
# 继承了被修改的值
end
puts A.value # 2 (被B修改了)
puts B.value # 2
puts C.value # 2
# 这种行为可能导致意外的结果🌍 全局变量
基本概念
全局变量在整个程序中都可访问,以$符号开头。
ruby
# 定义全局变量
$global_counter = 0
class GlobalCounter
def increment
$global_counter += 1
end
def self.global_count
$global_counter
end
end
# 在任何地方访问全局变量
puts $global_counter # 0
counter1 = GlobalCounter.new
counter2 = GlobalCounter.new
counter1.increment
counter2.increment
counter1.increment
puts GlobalCounter.global_count # 3
puts $global_counter # 3预定义全局变量
ruby
# Ruby提供了一些预定义的全局变量
puts $0 # 当前脚本的名称
puts $: # 负载路径 ($LOAD_PATH的别名)
puts $" # 已加载的文件列表 ($LOADED_FEATURES的别名)
puts $$ # 当前进程ID
puts $? # 最后执行的子进程退出状态
puts $! # 最后引发的异常
puts $@ # 最后引发异常的回溯信息
# 输入输出相关
puts $_ # gets最后读取的字符串
puts $. # 最后读取的文件行号
puts $; # split的默认分隔符全局变量的替代方案
ruby
# 避免过度使用全局变量,可以使用模块常量
module AppConfig
DEFAULT_TIMEOUT = 30
MAX_RETRIES = 3
DEBUG_MODE = false
def self.timeout
@timeout ||= DEFAULT_TIMEOUT
end
def self.timeout=(value)
@timeout = value
end
end
puts AppConfig::DEFAULT_TIMEOUT # 30
AppConfig.timeout = 60
puts AppConfig.timeout # 60🔤 常量
基本概念
常量以大写字母开头,通常全部大写,用于存储不应该改变的值。
ruby
# 定义常量
PI = 3.14159
MAX_SIZE = 100
DEFAULT_NAME = "匿名用户"
class MathConstants
E = 2.71828
GOLDEN_RATIO = 1.61803
def self.calculate_circle_area(radius)
PI * radius * radius
end
end
puts PI # 3.14159
puts MathConstants::E # 2.71828
puts MathConstants.calculate_circle_area(5) # 78.53975常量的作用域
ruby
OUTER_CONSTANT = "外部常量"
class MyClass
INNER_CONSTANT = "内部常量"
def self.show_constants
puts OUTER_CONSTANT # 可以访问外部常量
puts INNER_CONSTANT # 可以访问内部常量
end
end
puts OUTER_CONSTANT # 外部常量
# puts INNER_CONSTANT # 错误:无法直接访问类内部常量
puts MyClass::INNER_CONSTANT # 通过类名访问
MyClass.show_constants # 显示两个常量重新赋值常量
ruby
# Ruby允许重新赋值常量,但会发出警告
WARNING_LEVEL = 1
puts WARNING_LEVEL # 1
WARNING_LEVEL = 2 # 警告: already initialized constant WARNING_LEVEL
puts WARNING_LEVEL # 2
# 冻结对象防止修改
FROZEN_ARRAY = [1, 2, 3].freeze
# FROZEN_ARRAY << 4 # RuntimeError: can't modify frozen Array🔄 变量作用域详解
嵌套作用域
ruby
def outer_method
outer_var = "外部方法变量"
def inner_method
# 不能访问outer_var
# puts outer_var # 错误
inner_var = "内部方法变量"
end
inner_method
# puts inner_var # 错误:无法访问内部方法的变量
end
# 代码块作用域
def block_scope_example
outer_value = "外部值"
[1, 2, 3].each do |item|
block_var = "块变量"
puts "#{outer_value} - #{item} - #{block_var}"
end
# puts block_var # 错误:无法访问块变量
end
block_scope_example
# 输出:
# 外部值 - 1 - 块变量
# 外部值 - 2 - 块变量
# 外部值 - 3 - 块变量变量查找顺序
ruby
global_var = "全局变量"
class MyClass
@@class_var = "类变量"
def initialize
@instance_var = "实例变量"
end
def method_with_local
local_var = "局部变量"
# 变量查找顺序:局部变量 -> 实例变量 -> 类变量 -> 全局变量
puts local_var # 局部变量
puts @instance_var # 实例变量
puts @@class_var # 类变量
# puts global_var # 错误:无法直接访问方法外部的局部变量
end
end
obj = MyClass.new
obj.method_with_local🛡️ 变量安全和最佳实践
变量命名约定
ruby
# 好的命名约定
user_name = "张三" # 局部变量
@user_email = "user@example.com" # 实例变量
@@active_users = 0 # 类变量
$global_config = {} # 全局变量
MAX_LOGIN_ATTEMPTS = 3 # 常量
# 避免的命名
userName = "李四" # 驼峰命名(不推荐)
UserName = "王五" # 看起来像类名
user_name_ = "赵六" # 末尾下划线(不清晰)变量初始化
ruby
class SafeVariableExample
def initialize
@initialized_var = "已初始化"
@lazy_var = nil # 明确初始化为nil
end
def get_lazy_var
# 惰性初始化
@lazy_var ||= expensive_computation
end
private
def expensive_computation
puts "执行昂贵的计算..."
"计算结果"
end
end变量验证
ruby
class ValidatedVariables
def initialize(name, age)
self.name = name # 通过setter方法验证
self.age = age
end
def name=(name)
raise ArgumentError, "姓名不能为空" if name.nil? || name.empty?
@name = name
end
def age=(age)
raise ArgumentError, "年龄必须是正数" unless age.is_a?(Integer) && age > 0
@age = age
end
attr_reader :name, :age
end
# 使用示例
begin
person = ValidatedVariables.new("张三", 25)
puts "创建成功: #{person.name}, #{person.age}"
# person.age = -5 # 会引发ArgumentError
rescue ArgumentError => e
puts "错误: #{e.message}"
end🧪 变量实践示例
配置管理类
ruby
class ConfigManager
@@configs = {} # 类变量存储所有配置
@@default_config = { # 默认配置
timeout: 30,
retries: 3,
debug: false
}
def initialize(config_name)
@config_name = config_name
@@configs[@config_name] = @@default_config.dup
end
def set(key, value)
@@configs[@config_name][key] = value
end
def get(key)
@@configs[@config_name][key]
end
def self.get_config(config_name)
@@configs[config_name]
end
def self.list_configs
@@configs.keys
end
end
# 使用配置管理器
db_config = ConfigManager.new("database")
api_config = ConfigManager.new("api")
db_config.set(:host, "localhost")
db_config.set(:port, 5432)
api_config.set(:base_url, "https://api.example.com")
api_config.set(:timeout, 60)
puts db_config.get(:host) # localhost
puts api_config.get(:timeout) # 60
puts ConfigManager.list_configs.inspect # ["database", "api"]计数器类
ruby
class AdvancedCounter
@@total_counters = 0 # 总计数器数量
@@global_count = 0 # 全局计数
def initialize(name)
@name = name
@count = 0
@@total_counters += 1
end
def increment(step = 1)
@count += step
@@global_count += step
self # 返回self支持链式调用
end
def decrement(step = 1)
@count -= step
@@global_count -= step
self
end
def count
@count
end
def name
@name
end
def reset
@@global_count -= @count
@count = 0
self
end
def self.total_counters
@@total_counters
end
def self.global_count
@@global_count
end
def self.reset_all
@@global_count = 0
end
def info
"#{@name}: #{@count}"
end
end
# 使用高级计数器
counter1 = AdvancedCounter.new("计数器1")
counter2 = AdvancedCounter.new("计数器2")
counter1.increment(5).increment(3) # 链式调用
counter2.increment(2).decrement(1)
puts counter1.info # 计数器1: 8
puts counter2.info # 计数器2: 1
puts "全局计数: #{AdvancedCounter.global_count}" # 全局计数: 9
puts "总计数器: #{AdvancedCounter.total_counters}" # 总计数器: 2🎯 变量使用最佳实践
1. 最小化作用域
ruby
# 好的做法:在需要时才定义变量
def process_users(users)
users.map do |user|
# processed_user只在map块中使用
processed_user = user.dup
processed_user[:processed_at] = Time.now
processed_user
end
end
# 避免:过早定义变量
def bad_example(users)
processed_user = nil # 不必要的早期定义
results = []
users.each do |user|
processed_user = user.dup
processed_user[:processed_at] = Time.now
results << processed_user
end
results
end2. 使用描述性名称
ruby
# 好的命名
user_authentication_token = "abc123"
maximum_retry_attempts = 3
database_connection_timeout = 30
# 避免模糊命名
token = "abc123"
max_retries = 3
timeout = 303. 合理使用不同类型的变量
ruby
class UserService
@@active_users = Set.new # 类变量:跟踪所有活跃用户
DEFAULT_PAGE_SIZE = 20 # 常量:默认分页大小
def initialize(current_user)
@current_user = current_user # 实例变量:当前用户
end
def list_users(page = 1)
page_size = DEFAULT_PAGE_SIZE # 局部变量:分页大小
offset = (page - 1) * page_size
# 查询逻辑...
end
end📚 下一步学习
掌握了Ruby变量后,建议继续学习:
- Ruby 数据类型 - 深入了解Ruby的各种数据类型
- Ruby 作用域和绑定 - 学习更复杂的变量作用域概念
- Ruby 块和迭代器 - 掌握代码块中的变量使用
- Ruby 内存管理 - 了解变量的内存分配和回收
继续您的Ruby学习之旅吧!