Ruby Variables
Variables are fundamental concepts in programming used to store and manipulate data. Ruby provides multiple types of variables, each with specific scope and usage. This chapter will introduce in detail the various variable types in Ruby and how to use them.
📦 Variable Types Overview
Ruby has four main variable types:
- Local Variables - Used within methods or code blocks
- Instance Variables - Belong to object instances
- Class Variables - Belong to the class itself
- Global Variables - Accessible throughout the program
🏠 Local Variables
Basic Concepts
Local variables are only visible within the methods or code blocks where they are defined, starting with lowercase letters or underscores.
# Local variable definition
name = "Zhang San"
age = 25
_score = 95
# Using local variables in methods
def calculate_area(length, width)
# length and width are parameter local variables
area = length * width # area is a local variable within the method
area # Return value
end
puts calculate_area(5, 3) # 15Scope
def method1
local_var = "Local variable in method 1"
puts local_var
end
def method2
# puts local_var # Error: Cannot access local variables from other methods
local_var = "Local variable in method 2"
puts local_var
end
method1 # Output: Local variable in method 1
method2 # Output: Local variable in method 2Local Variables in Code Blocks
# Code blocks can access external local variables
outer_var = "External variable"
[1, 2, 3].each do |item|
# item is a code block parameter
puts "#{outer_var}: #{item}"
end
# Output:
# External variable: 1
# External variable: 2
# External variable: 3
# Use semicolons to separate code block local variables
[1, 2, 3].each do |item; block_local|
block_local = item * 2
puts "#{item} * 2 = #{block_local}"
endVariable Assignment and Parallel Assignment
# Basic assignment
x = 10
y = 20
# Parallel assignment
a, b = 1, 2
puts "a = #{a}, b = #{b}" # a = 1, b = 2
# Swap variable values
a, b = b, a
puts "a = #{a}, b = #{b}" # a = 2, b = 1
# Array destructuring
first, *rest = [1, 2, 3, 4, 5]
puts "first = #{first}" # first = 1
puts "rest = #{rest}" # rest = [2, 3, 4, 5]
# Ignore certain values
_, second, _ = [1, 2, 3]
puts "second = #{second}" # second = 2🎯 Instance Variables
Basic Concepts
Instance variables belong to specific object instances, starting with @ symbol, and exist throughout the object's lifecycle.
class Person
def initialize(name, age)
@name = name # Instance variable
@age = age # Instance variable
end
def introduce
puts "I am #{@name}, I am #{@age} years old"
end
def have_birthday
@age += 1 # Modify instance variable
puts "Happy birthday! Now #{@age} years old"
end
def name
@name # Access instance variable
end
end
person = Person.new("Zhang San", 25)
person.introduce # I am Zhang San, I am 25 years old
person.have_birthday # Happy birthday! Now 26 years old
puts person.name # Zhang SanInstance Variable Scope
class Counter
def initialize
@count = 0 # Each instance has its own @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 (different instances)
counter2.increment
puts counter2.count # 1
puts counter1.count # 2 (not affected)Instance Variable Default Values
class Example
def initialize
# Uninitialized instance variables default to nil
puts @uninitialized.inspect # nil
end
def set_value
@value = "Set"
end
def get_value
@value # Returns nil if not set
end
end
example = Example.new
puts example.get_value.inspect # nil
example.set_value
puts example.get_value # Set🏢 Class Variables
Basic Concepts
Class variables belong to the class itself, shared by all instances of that class, starting with @@ symbol.
class Counter
@@total_count = 0 # Class variable
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 # Access class variable
end
def self.reset_total
@@total_count = 0 # Modify class variable
end
end
# Create instances
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 (different instance variables)
# All instances share class variables
puts Counter.total_count # 3Class Variable Inheritance
class Parent
@@class_var = "Parent variable"
def self.get_class_var
@@class_var
end
def self.set_class_var(value)
@@class_var = value
end
end
class Child < Parent
# Subclass shares parent's class variable
end
puts Parent.get_class_var # Parent variable
puts Child.get_class_var # Parent variable
# Modifying class variable affects all classes
Child.set_class_var("Modified value")
puts Parent.get_class_var # Modified value
puts Child.get_class_var # Modified valueClass Variable Considerations
class A
@@value = 1
def self.value
@@value
end
end
class B < A
@@value = 2 # Modifies parent's class variable
end
class C < A
# Inherits the modified value
end
puts A.value # 2 (modified by B)
puts B.value # 2
puts C.value # 2
# This behavior can lead to unexpected results🌍 Global Variables
Basic Concepts
Global variables are accessible throughout the entire program, starting with $ symbol.
# Define global variable
$global_counter = 0
class GlobalCounter
def increment
$global_counter += 1
end
def self.global_count
$global_counter
end
end
# Access global variables anywhere
puts $global_counter # 0
counter1 = GlobalCounter.new
counter2 = GlobalCounter.new
counter1.increment
counter2.increment
counter1.increment
puts GlobalCounter.global_count # 3
puts $global_counter # 3Predefined Global Variables
# Ruby provides some predefined global variables
puts $0 # Current script name
puts $: # Load path ($LOAD_PATH alias)
puts $" # List of loaded files ($LOADED_FEATURES alias)
puts $$ # Current process ID
puts $? # Last executed child process exit status
puts $! # Last raised exception
puts $@ # Backtrace of last raised exception
# Input/output related
puts $_ # String last read by gets
puts $. # Last read file line number
puts $; # Default separator for splitAlternatives to Global Variables
# Avoid overuse of global variables; use module constants instead
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🔤 Constants
Basic Concepts
Constants start with uppercase letters, typically all uppercase, used to store values that should not change.
# Define constants
PI = 3.14159
MAX_SIZE = 100
DEFAULT_NAME = "Anonymous User"
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.53975Constant Scope
OUTER_CONSTANT = "Outer Constant"
class MyClass
INNER_CONSTANT = "Inner Constant"
def self.show_constants
puts OUTER_CONSTANT # Can access outer constant
puts INNER_CONSTANT # Can access inner constant
end
end
puts OUTER_CONSTANT # Outer Constant
# puts INNER_CONSTANT # Error: Cannot directly access class internal constant
puts MyClass::INNER_CONSTANT # Access via class name
MyClass.show_constants # Display both constantsReassigning Constants
# Ruby allows reassigning constants, but issues a warning
WARNING_LEVEL = 1
puts WARNING_LEVEL # 1
WARNING_LEVEL = 2 # warning: already initialized constant WARNING_LEVEL
puts WARNING_LEVEL # 2
# Freeze object to prevent modification
FROZEN_ARRAY = [1, 2, 3].freeze
# FROZEN_ARRAY << 4 # RuntimeError: can't modify frozen Array🔄 Variable Scope Details
Nested Scope
def outer_method
outer_var = "Outer method variable"
def inner_method
# Cannot access outer_var
# puts outer_var # Error
inner_var = "Inner method variable"
end
inner_method
# puts inner_var # Error: Cannot access inner method's variables
end
# Code block scope
def block_scope_example
outer_value = "Outer value"
[1, 2, 3].each do |item|
block_var = "Block variable"
puts "#{outer_value} - #{item} - #{block_var}"
end
# puts block_var # Error: Cannot access block variable
end
block_scope_example
# Output:
# Outer value - 1 - Block variable
# Outer value - 2 - Block variable
# Outer value - 3 - Block variableVariable Lookup Order
global_var = "Global Variable"
class MyClass
@@class_var = "Class Variable"
def initialize
@instance_var = "Instance Variable"
end
def method_with_local
local_var = "Local Variable"
# Variable lookup order: local -> instance -> class -> global
puts local_var # Local Variable
puts @instance_var # Instance Variable
puts @@class_var # Class Variable
# puts global_var # Error: Cannot directly access local variable outside method
end
end
obj = MyClass.new
obj.method_with_local🛡️ Variable Security and Best Practices
Variable Naming Conventions
# Good naming conventions
user_name = "Zhang San" # Local variable
@user_email = "user@example.com" # Instance variable
@@active_users = 0 # Class variable
$global_config = {} # Global variable
MAX_LOGIN_ATTEMPTS = 3 # Constant
# Avoid naming
userName = "Li Si" # camelCase (not recommended)
UserName = "Wang Wu" # Looks like class name
user_name_ = "Zhao Liu" # Trailing underscore (unclear)Variable Initialization
class SafeVariableExample
def initialize
@initialized_var = "Initialized"
@lazy_var = nil # Explicitly initialize to nil
end
def get_lazy_var
# Lazy initialization
@lazy_var ||= expensive_computation
end
private
def expensive_computation
puts "Executing expensive computation..."
"Computed result"
end
endVariable Validation
class ValidatedVariables
def initialize(name, age)
self.name = name # Validate via setter method
self.age = age
end
def name=(name)
raise ArgumentError, "Name cannot be empty" if name.nil? || name.empty?
@name = name
end
def age=(age)
raise ArgumentError, "Age must be positive" unless age.is_a?(Integer) && age > 0
@age = age
end
attr_reader :name, :age
end
# Usage example
begin
person = ValidatedVariables.new("Zhang San", 25)
puts "Created successfully: #{person.name}, #{person.age}"
# person.age = -5 # Will raise ArgumentError
rescue ArgumentError => e
puts "Error: #{e.message}"
end🧪 Variable Practice Examples
Configuration Management Class
class ConfigManager
@@configs = {} # Class variable to store all configs
@@default_config = { # Default configuration
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
# Use configuration manager
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"]Counter Class
class AdvancedCounter
@@total_counters = 0 # Total counter count
@@global_count = 0 # Global count
def initialize(name)
@name = name
@count = 0
@@total_counters += 1
end
def increment(step = 1)
@count += step
@@global_count += step
self # Return self for chaining
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
# Use advanced counter
counter1 = AdvancedCounter.new("Counter 1")
counter2 = AdvancedCounter.new("Counter 2")
counter1.increment(5).increment(3) # Chained calls
counter2.increment(2).decrement(1)
puts counter1.info # Counter 1: 8
puts counter2.info # Counter 2: 1
puts "Global count: #{AdvancedCounter.global_count}" # Global count: 9
puts "Total counters: #{AdvancedCounter.total_counters}" # Total counters: 2🎯 Variable Usage Best Practices
1. Minimize Scope
# Good practice: Define variables only when needed
def process_users(users)
users.map do |user|
# processed_user only used within map block
processed_user = user.dup
processed_user[:processed_at] = Time.now
processed_user
end
end
# Avoid: Defining variables too early
def bad_example(users)
processed_user = nil # Unnecessary early definition
results = []
users.each do |user|
processed_user = user.dup
processed_user[:processed_at] = Time.now
results << processed_user
end
results
end2. Use Descriptive Names
# Good naming
user_authentication_token = "abc123"
maximum_retry_attempts = 3
database_connection_timeout = 30
# Avoid vague naming
token = "abc123"
max_retries = 3
timeout = 303. Use Different Variable Types Appropriately
class UserService
@@active_users = Set.new # Class variable: track all active users
DEFAULT_PAGE_SIZE = 20 # Constant: default page size
def initialize(current_user)
@current_user = current_user # Instance variable: current user
end
def list_users(page = 1)
page_size = DEFAULT_PAGE_SIZE # Local variable: page size
offset = (page - 1) * page_size
# Query logic...
end
end📚 Next Steps
After mastering Ruby variables, it is recommended to continue learning:
- Ruby Data Types - Deep dive into Ruby's various data types
- Ruby Scope and Binding - Learn more complex variable scope concepts
- Ruby Blocks and Iterators - Master variable usage in code blocks
- Ruby Memory Management - Understand variable memory allocation and garbage collection
Continue your Ruby learning journey!