Skip to content

Ruby Data Types

Ruby is a dynamically typed language where variables don't need explicit type declarations. This chapter will introduce in detail the various data types in Ruby and how to use them.

🎯 Ruby Type System Features

Dynamic Typing

ruby
# Variables can store any type of value
variable = 42           # Integer
variable = "Hello"      # String
variable = [1, 2, 3]    # Array
variable = {:name => "Zhang San"}  # Hash

Strong Typing

ruby
# Ruby is a strongly typed language and does not allow implicit type conversion
number = 10
text = "20"
# result = number + text  # This will raise TypeError
result = number + text.to_i  # Explicit conversion required

Everything is an Object

ruby
# In Ruby, all values are objects
puts 42.class        # Integer
puts "Hello".class   # String
puts true.class      # TrueClass
puts nil.class       # NilClass

🔢 Numeric Types

Integers (Integer)

ruby
# Integer types
positive = 42
negative = -17
zero = 0
large_number = 123456789012345678901234567890

# Integer base representation
decimal = 42           # Decimal
binary = 0b101010      # Binary (42)
octal = 0o52           # Octal (42)
hexadecimal = 0x2A     # Hexadecimal (42)

# Integer methods
puts 42.even?          # true (is even)
puts 42.odd?           # false (is odd)
puts 42.times { |i| print "#{i} " }  # 0 1 2 ... 41
puts 42.next           # 43 (next integer)
puts 42.pred           # 41 (previous integer)

Floats (Float)

ruby
# Float types
pi = 3.14159
negative_float = -2.5
scientific = 1.23e4    # 12300.0 (scientific notation)

# Float precision issues
puts 0.1 + 0.2         # 0.30000000000000004
puts (0.1 + 0.2).round(1)  # 0.3

# Float methods
puts 3.14.floor        # 3 (floor)
puts 3.14.ceil         # 4 (ceiling)
puts 3.14.round        # 3 (round)
puts 3.14.round(2)     # 3.14 (keep 2 decimal places)
puts 3.14.abs          # 3.14 (absolute value)

Rational Numbers (Rational)

ruby
# Rational number type (exact fraction representation)
require 'rational'

fraction = Rational(2, 3)    # 2/3
puts fraction                # (2/3)
puts fraction.to_f           # 0.6666666666666666

# Rational number operations (no precision loss)
result = Rational(1, 2) + Rational(1, 3)
puts result                  # (5/6)

# Other ways to create rationals
fraction1 = 2/3r             # Using r suffix
fraction2 = Rational("2/3")  # Create from string

Complex Numbers (Complex)

ruby
# Complex number type
require 'complex'

complex_number = Complex(3, 4)  # 3+4i
puts complex_number             # (3+4i)
puts complex_number.real        # 3 (real part)
puts complex_number.imag        # 4 (imaginary part)
puts complex_number.abs         # 5.0 (modulus)

# Complex number operations
a = Complex(1, 2)
b = Complex(3, 4)
puts a + b                      # (4+6i)
puts a * b                      # (-5+10i)

📝 Text Types

Strings (String)

ruby
# String creation
single_quoted = 'Single-quoted string'
double_quoted = "Double-quoted string"
heredoc = <<~TEXT
  Multi-line string
  Can contain multiple lines
  Supports indentation
TEXT

# String interpolation (double-quotes only)
name = "Zhang San"
age = 25
greeting = "Hello, #{name}! You are #{age} years old."
puts greeting

# String methods
text = "Hello, World!"
puts text.length           # 13 (length)
puts text.upcase           # HELLO, WORLD! (uppercase)
puts text.downcase         # hello, world! (lowercase)
puts text.capitalize       # Hello, world! (capitalize first letter)
puts text.reverse          # !dlroW ,olleH (reverse)
puts text.include?("World") # true (contains substring)

# String operations
original = "Ruby Programming"
puts original[0]           # R (index access)
puts original[0..3]        # Ruby (slice)
puts original[4..-1]       # Programming (from 5th character to end)

# String modification
mutable_string = "Hello"
mutable_string << " World"  # Append
puts mutable_string         # Hello World

# String encoding
chinese_text = "Chinese Text"
puts chinese_text.encoding   # UTF-8

🧠 Boolean Types

TrueClass and FalseClass

ruby
# Boolean values
is_true = true
is_false = false

# Boolean methods
puts true.class             # TrueClass
puts false.class            # FalseClass

# Boolean operations
puts true && false          # false (and)
puts true || false          # true (or)
puts !true                  # false (not)

# Truthy and falsy values
# In Ruby, only false and nil are falsy, everything else is truthy
puts !!true                 # true
puts !!false                # false
puts !!nil                  # false
puts !!0                    # true (0 is truthy!)
puts !!""                   # true (empty string is truthy!)
puts !!"Hello"              # true

📦 Collection Types

Arrays (Array)

ruby
# Array creation
empty_array = []
numbers = [1, 2, 3, 4, 5]
mixed_array = ["String", 42, true, nil]
nested_array = [[1, 2], [3, 4], [5, 6]]

# Array access
fruits = ["Apple", "Banana", "Orange"]
puts fruits[0]              # Apple
puts fruits[-1]             # Orange (last element)
puts fruits[1..2]           # ["Banana", "Orange"] (slice)

# Array methods
puts fruits.length          # 3 (length)
puts fruits.size            # 3 (size)
puts fruits.empty?          # false (is empty)
puts fruits.include?("Apple") # true (contains)

# Array operations
fruits.push("Grape")          # Add to end
fruits << "Strawberry"        # Add to end (shorthand)
first_fruit = fruits.shift     # Remove and return first element
last_fruit = fruits.pop        # Remove and return last element
fruits.unshift("Watermelon")   # Add to beginning

# Array iteration
numbers = [1, 2, 3, 4, 5]
numbers.each { |n| puts n }  # Traverse
doubled = numbers.map { |n| n * 2 }  # Transform
evens = numbers.select { |n| n.even? }  # Filter
sum = numbers.reduce(0) { |acc, n| acc + n }  # Reduce

Hashes (Hash)

ruby
# Hash creation
empty_hash = {}
person = {
  "name" => "Zhang San",
  "age" => 25,
  "city" => "Beijing"
}

# Using symbols as keys (recommended)
person_symbol = {
  name: "Zhang San",
  age: 25,
  city: "Beijing"
}

# Hash access
puts person["name"]         # Zhang San
puts person_symbol[:name]   # Zhang San

# Hash methods
puts person.keys            # ["name", "age", "city"]
puts person.values          # ["Zhang San", 25, "Beijing"]
puts person.length          # 3
puts person.empty?          # false

# Hash operations
person["job"] = "Programmer"     # Add key-value pair
person[:age] = 26           # Modify value
person.delete("city")       # Delete key-value pair

# Hash iteration
person_symbol.each do |key, value|
  puts "#{key}: #{value}"
end

# Hash default values
scores = Hash.new(0)        # Default value is 0
scores[:math] = 95
puts scores[:english]       # 0 (default value)

Ranges (Range)

ruby
# Range creation
inclusive_range = 1..10     # Includes 10
exclusive_range = 1...10    # Does not include 10

# Character ranges
letters = 'a'..'z'

# Range methods
puts (1..5).include?(3)     # true
puts (1..5).min             # 1
puts (1..5).max             # 5
puts (1..5).size            # 5

# Range conversion
array_from_range = (1..5).to_a  # [1, 2, 3, 4, 5]
string_from_range = ('a'..'e').to_a.join  # "abcde"

# Range iteration
(1..5).each { |n| puts n }  # 1 2 3 4 5

🎭 Special Types

Symbols (Symbol)

ruby
# Symbol creation
symbol1 = :name
symbol2 = :"user-name"
symbol3 = :"user name"

# Difference between symbols and strings
string_key = "name"
symbol_key = :name

puts string_key.object_id    # Different every time
puts symbol_key.object_id    # Always the same

# Symbol methods
puts :hello.to_s             # hello
puts "hello".to_sym          # :hello
puts :Name.capitalize        # :Name

# Symbols in hashes
user = {
  name: "Zhang San",
  age: 25,
  email: "zhangsan@example.com"
}

Nil (NilClass)

ruby
# Nil values
value = nil
puts value.class              # NilClass

# Nil checks
puts value.nil?              # true
puts value == nil            # true

# Safe navigation operator
user = nil
puts user&.name              # nil (won't raise error)
puts user&.name&.upcase      # nil

# Nil's boolean value
puts !!nil                   # false

Regular Expressions (Regexp)

ruby
# Regular expression creation
pattern1 = /ruby/i           # Case insensitive
pattern2 = %r{https?://}     # Using %r delimiter

# Regular expression matching
text = "I love Ruby programming"
puts text =~ /ruby/i         # 7 (match position)
puts text.match?(/ruby/i)    # true (matches?)

# Regular expression capture
match_data = "2023-12-25".match(/(\d{4})-(\d{2})-(\d{2})/)
puts match_data[0]           # 2023-12-25
puts match_data[1]           # 2023
puts match_data[2]           # 12
puts match_data[3]           # 25

🔄 Type Conversion

Explicit Type Conversion

ruby
# String conversion
puts 42.to_s                 # "42"
puts true.to_s               # "true"
puts [1, 2, 3].to_s          # "[1, 2, 3]"

# Numeric conversion
puts "42".to_i               # 42
puts "3.14".to_f             # 3.14
puts "hello".to_i            # 0 (returns 0 for invalid)

# Array and hash conversion
puts "hello".chars           # ["h", "e", "l", "l", "o"]
puts [1, 2, 3].join("-")     # "1-2-3"
puts [["a", 1], ["b", 2]].to_h  # {"a"=>1, "b"=>2}

Type Checking

ruby
# Type checking methods
puts 42.is_a?(Integer)       # true
puts "hello".is_a?(String)   # true
puts [1, 2, 3].is_a?(Array)  # true
puts {:a => 1}.is_a?(Hash)   # true

# Respond to method check
puts "hello".respond_to?(:upcase)  # true
puts 42.respond_to?(:times)        # true

# Instance check
puts 42.instance_of?(Integer)      # true
puts 42.instance_of?(Numeric)      # false

🧪 Type System Practice

Advantages of Dynamic Typing

ruby
# Flexible parameter handling
def process_data(data)
  case data
  when String
    puts "Processing string: #{data.upcase}"
  when Numeric
    puts "Processing number: #{data * 2}"
  when Array
    puts "Processing array: #{data.join(', ')}"
  when Hash
    puts "Processing hash: #{data.keys.join(', ')}"
  else
    puts "Unknown type: #{data.class}"
  end
end

# Test with different types of data
process_data("hello")        # Processing string: HELLO
process_data(42)             # Processing number: 84
process_data([1, 2, 3])      # Processing array: 1, 2, 3
process_data({a: 1, b: 2})   # Processing hash: a, b

Type Safety Practices

ruby
# Type-safe method design
class Calculator
  def add(a, b)
    # Validate parameter types
    raise ArgumentError, "Parameters must be numbers" unless a.is_a?(Numeric) && b.is_a?(Numeric)
    a + b
  end
  
  def multiply_array(numbers)
    # Validate parameter type
    raise ArgumentError, "Parameter must be an array" unless numbers.is_a?(Array)
    
    # Validate array element types
    unless numbers.all? { |n| n.is_a?(Numeric) }
      raise ArgumentError, "Array elements must all be numbers"
    end
    
    numbers.reduce(1) { |product, n| product * n }
  end
end

# Usage example
calc = Calculator.new
puts calc.add(2, 3)          # 5
# puts calc.add("2", 3)      # Will raise ArgumentError

Custom Data Types

ruby
# Create custom class
class Point
  attr_accessor :x, :y
  
  def initialize(x, y)
    @x = x
    @y = y
  end
  
  def distance_from_origin
    Math.sqrt(@x**2 + @y**2)
  end
  
  def to_s
    "(#{@x}, #{@y})"
  end
end

# Use custom type
point = Point.new(3, 4)
puts point                   # (3, 4)
puts point.distance_from_origin  # 5.0

🎯 Data Type Best Practices

1. Choose Appropriate Data Types

ruby
# Use symbols as hash keys
# Good practice
user = {
  name: "Zhang San",
  age: 25,
  active: true
}

# Avoid using strings as keys
# Not recommended
user = {
  "name" => "Zhang San",
  "age" => 25,
  "active" => true
}

2. Safe Type Conversion

ruby
# Safe type conversion
def safe_to_integer(value)
  case value
  when Integer
    value
  when String
    Integer(value) rescue 0
  when Float
    value.to_i
  else
    0
  end
end

puts safe_to_integer("42")    # 42
puts safe_to_integer("abc")   # 0
puts safe_to_integer(3.14)    # 3

3. Handling Nil Values

ruby
# Safely handle nil values
def safe_string_operation(str)
  return "" if str.nil?
  str.to_s.strip
end

# Use ternary operator
def get_display_name(user)
  user&.name || "Anonymous User"
end

# Use default values
def process_options(options = {})
  debug = options[:debug] || false
  timeout = options[:timeout] || 30
  # Process options
end

📚 Next Steps

After mastering Ruby data types, it is recommended to continue learning:

Continue your Ruby learning journey!

Content is for learning and research only.