Skip to content

Ruby 条件判断

条件判断是编程中的基本控制结构,用于根据不同的条件执行不同的代码路径。Ruby提供了多种条件判断语句,使代码能够根据运行时的情况做出决策。本章将详细介绍Ruby中的各种条件判断语句及其使用方法。

🎯 条件判断基础

布尔值和真值

在Ruby中,除了falsenil之外的所有值都被视为真值(truthy):

ruby
# 真值 (truthy)
puts !!true        # true
puts !!1           # true (数字)
puts !!"Hello"     # true (非空字符串)
puts !![]          # true (空数组)
puts !!{}          # true (空哈希)
puts !!0           # true (零也是真值!)

# 假值 (falsy)
puts !!false       # false
puts !!nil         # false

条件表达式

ruby
# 基本比较
puts 5 > 3         # true
puts 5 == 5        # true
puts "apple" < "banana"  # true

# 复杂条件
age = 25
has_license = true

if age >= 18 && has_license
  puts "可以开车"
end

# 字符串和数字的比较
puts "10" == 10    # false (类型不同)
puts "10" == "10"  # true
puts 10 == 10      # true

🔀 if语句

基本if语句

ruby
# 简单条件判断
age = 18

if age >= 18
  puts "你已经成年了"
end

# if-else语句
if age >= 18
  puts "成年人"
else
  puts "未成年人"
end

# if-elsif-else语句
if age < 13
  puts "儿童"
elsif age < 18
  puts "青少年"
elsif age < 60
  puts "成年人"
else
  puts "老年人"
end

单行if语句

ruby
# 修饰符形式的if语句
puts "成年人" if age >= 18

name = "张三"
puts "欢迎, #{name}!" if name

# 多个条件
score = 85
puts "优秀" if score >= 90
puts "良好" if score >= 80 && score < 90
puts "及格" if score >= 60 && score < 80

if语句的返回值

ruby
# if语句有返回值
result = if age >= 18
  "成年人"
else
  "未成年人"
end

puts result  # 成年人

# 更复杂的返回值
grade = 85
level = if grade >= 90
  "优秀"
elsif grade >= 80
  "良好"
elsif grade >= 60
  "及格"
else
  "不及格"
end

puts level  # 良好

🔁 unless语句

基本unless语句

ruby
# unless等同于if not
age = 16

unless age >= 18
  puts "未成年人"
end

# unless-else语句
unless age >= 18
  puts "未成年人"
else
  puts "成年人"
end

# 单行unless语句
puts "未成年人" unless age >= 18

unless的使用场景

ruby
# 适合用于否定条件的检查
user = nil
puts "请先登录" unless user

file_exists = File.exist?("config.txt")
puts "配置文件不存在" unless file_exists

# 避免双重否定
# 不推荐: if !user.nil?
# 推荐: unless user.nil? 或者更简洁: if user

🔄 case语句

基本case语句

ruby
# 简单的case语句
grade = "B"

case grade
when "A"
  puts "优秀"
when "B"
  puts "良好"
when "C"
  puts "及格"
else
  puts "不及格"
end

# case语句的返回值
score = 85
level = case score
when 90..100
  "优秀"
when 80...90
  "良好"
when 60...80
  "及格"
else
  "不及格"
end

puts level  # 良好

多值匹配

ruby
# 一个when子句匹配多个值
day = "Saturday"

case day
when "Saturday", "Sunday"
  puts "周末"
when "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"
  puts "工作日"
end

# 使用数组进行匹配
weekend_days = ["Saturday", "Sunday"]
work_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

case day
when *weekend_days
  puts "周末"
when *work_days
  puts "工作日"
end

范围匹配

ruby
# 使用范围进行匹配
score = 85

case score
when 90..100
  puts "优秀"
when 80...90
  puts "良好"
when 70...80
  puts "中等"
when 60...70
  puts "及格"
else
  puts "不及格"
end

正则表达式匹配

ruby
# 使用正则表达式进行匹配
email = "user@example.com"

case email
when /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  puts "有效的邮箱地址"
when /\A\d{11}\z/
  puts "可能是手机号码"
else
  puts "未知格式"
end

case语句的工作原理

ruby
# case使用===运算符进行比较
# 不同类型的对象有不同的===实现

# 数值比较
case 5
when 1..10
  puts "在1到10之间"
end

# 类型检查
case "Hello"
when String
  puts "这是一个字符串"
when Numeric
  puts "这是一个数字"
end

# 自定义类的===方法
class Priority
  def self.===(value)
    value.is_a?(Integer) && value > 100
  end
end

case 150
when Priority
  puts "高优先级"
else
  puts "普通优先级"
end

🎯 三元运算符

基本语法

ruby
# 三元运算符: condition ? value_if_true : value_if_false
age = 20
status = age >= 18 ? "成年人" : "未成年人"
puts status  # 成年人

# 嵌套三元运算符(谨慎使用)
score = 85
grade = score >= 90 ? "优秀" : 
        score >= 80 ? "良好" : 
        score >= 60 ? "及格" : "不及格"
puts grade  # 良好

三元运算符的应用场景

ruby
# 简单的条件赋值
user = nil
display_name = user ? user.name : "匿名用户"
# 或者使用更简洁的形式
display_name = user&.name || "匿名用户"

# 条件输出
debug_mode = true
puts "调试信息" if debug_mode

# 条件方法调用
class Calculator
  def initialize(debug = false)
    @debug = debug
  end
  
  def add(a, b)
    result = a + b
    puts "计算: #{a} + #{b} = #{result}" if @debug
    result
  end
end

🔄 修饰符形式

if和unless修饰符

ruby
# if修饰符
puts "成年人" if age >= 18
raise "年龄无效" if age < 0
return unless user

# unless修饰符
puts "请登录" unless user
exit unless ready?

# 多个修饰符组合
puts "成年人且已登录" if age >= 18 && user
puts "未成年或未登录" unless age >= 18 && user

while和until修饰符

ruby
# while修饰符
counter = 0
counter += 1 while counter < 5
puts counter  # 5

# until修饰符
counter = 5
counter -= 1 until counter <= 0
puts counter  # 0

🎯 复杂条件判断

逻辑运算符组合

ruby
# 与运算 (&&)
user = {name: "张三", age: 25, active: true}
if user[:age] >= 18 && user[:active]
  puts "#{user[:name]}可以访问"
end

# 或运算 (||)
role = "admin"
if role == "admin" || role == "moderator"
  puts "具有管理权限"
end

# 非运算 (!)
logged_in = false
puts "请登录" if !logged_in

# 复杂条件组合
if (user[:age] >= 18 && user[:active]) || user[:role] == "admin"
  puts "允许访问"
end

短路求值

ruby
# && 短路:如果左边为false,不计算右边
def expensive_check
  puts "执行昂贵检查"
  true
end

false && expensive_check  # 不会输出"执行昂贵检查"

# || 短路:如果左边为true,不计算右边
true || expensive_check   # 不会输出"执行昂贵检查"

# 利用短路求值的安全访问
user = nil
# 安全地访问嵌套属性
name = user && user.profile && user.profile.name
# 或使用安全导航运算符 (Ruby 2.3+)
name = user&.profile&.name

条件赋值

ruby
# ||= 条件赋值
cache = nil
cache ||= expensive_computation  # 第一次执行计算
cache ||= another_computation    # 不会执行,使用缓存值

# &&= 条件赋值
value = 10
value &&= value * 2  # value = 20
value = nil
value &&= value * 2  # value 保持为 nil

🧪 条件判断实践示例

用户权限检查系统

ruby
class PermissionChecker
  def initialize(user)
    @user = user
  end
  
  def can_access?(resource)
    # 管理员可以访问所有资源
    return true if admin?
    
    # 检查具体权限
    case resource
    when :public
      true
    when :private
      logged_in?
    when :admin_only
      admin?
    when :premium
      premium_user?
    else
      false
    end
  end
  
  def check_access(resource)
    if can_access?(resource)
      puts "访问授权: #{resource}"
      true
    else
      puts "访问拒绝: #{resource}"
      false
    end
  end
  
  private
  
  def logged_in?
    !@user.nil?
  end
  
  def admin?
    @user && @user[:role] == :admin
  end
  
  def premium_user?
    @user && (@user[:role] == :premium || @user[:role] == :admin)
  end
end

# 使用权限检查系统
users = [
  nil,  # 未登录用户
  {name: "普通用户", role: :user},
  {name: "高级用户", role: :premium},
  {name: "管理员", role: :admin}
]

resources = [:public, :private, :premium, :admin_only]

checker = PermissionChecker.new(nil)
users.each do |user|
  checker.instance_variable_set(:@user, user)
  user_name = user ? user[:name] : "访客"
  puts "\n=== #{user_name} ==="
  
  resources.each do |resource|
    checker.check_access(resource)
  end
end

成绩等级评定系统

ruby
class GradeEvaluator
  def self.evaluate(score)
    case score
    when 90..100
      "优秀"
    when 80...90
      "良好"
    when 70...80
      "中等"
    when 60...70
      "及格"
    when 0...60
      "不及格"
    else
      raise ArgumentError, "无效的成绩: #{score}"
    end
  end
  
  def self.detailed_evaluate(score)
    grade = evaluate(score)
    
    description = case grade
    when "优秀"
      "表现卓越,继续保持"
    when "良好"
      "表现良好,还有提升空间"
    when "中等"
      "达到基本要求,需要努力"
    when "及格"
      "刚好及格,需要加强学习"
    when "不及格"
      "未达到要求,需要重修"
    end
    
    {
      grade: grade,
      score: score,
      description: description
    }
  end
  
  def self.batch_evaluate(scores)
    results = []
    scores.each_with_index do |score, index|
      begin
        result = detailed_evaluate(score)
        result[:student_id] = index + 1
        results << result
      rescue ArgumentError => e
        results << {
          student_id: index + 1,
          error: e.message
        }
      end
    end
    results
  end
end

# 使用成绩评定系统
scores = [95, 87, 76, 65, 45, 105, -5]
results = GradeEvaluator.batch_evaluate(scores)

results.each do |result|
  if result[:error]
    puts "学生#{result[:student_id]}: #{result[:error]}"
  else
    puts "学生#{result[:student_id]}: #{result[:score]}分 - #{result[:grade]} - #{result[:description]}"
  end
end

配置文件解析器

ruby
class ConfigParser
  def self.parse(config)
    parsed = {}
    
    config.each do |key, value|
      parsed[key] = parse_value(key, value)
    end
    
    parsed
  end
  
  private
  
  def self.parse_value(key, value)
    case key.to_s
    when /_enabled$/, /_active$/
      parse_boolean(value)
    when /_count$/, /_size$/, /_limit$/
      parse_integer(value)
    when /_timeout$/, /_delay$/
      parse_float(value)
    when /_list$/, /_array$/
      parse_array(value)
    when /_path$/
      parse_path(value)
    else
      value  # 保持原值
    end
  end
  
  def self.parse_boolean(value)
    case value
    when true, false
      value
    when String
      case value.downcase
      when "true", "1", "yes", "on"
        true
      when "false", "0", "no", "off"
        false
      else
        raise ArgumentError, "无效的布尔值: #{value}"
      end
    when Numeric
      value != 0
    else
      !!value
    end
  end
  
  def self.parse_integer(value)
    case value
    when Integer
      value
    when String
      Integer(value)
    when Float
      value.to_i
    else
      raise ArgumentError, "无效的整数值: #{value}"
    end
  rescue ArgumentError
    raise ArgumentError, "无效的整数值: #{value}"
  end
  
  def self.parse_float(value)
    case value
    when Float, Integer
      value.to_f
    when String
      Float(value)
    else
      raise ArgumentError, "无效的浮点数值: #{value}"
    end
  rescue ArgumentError
    raise ArgumentError, "无效的浮点数值: #{value}"
  end
  
  def self.parse_array(value)
    case value
    when Array
      value
    when String
      value.split(",").map(&:strip)
    else
      [value]
    end
  end
  
  def self.parse_path(value)
    case value
    when String
      # 简单的路径清理
      value.gsub(/[<>:"|?*]/, "")  # 移除非法字符
    else
      value.to_s
    end
  end
end

# 使用配置解析器
config = {
  debug_enabled: "true",
  max_connections: "100",
  request_timeout: "30.5",
  allowed_hosts: "localhost,127.0.0.1,example.com",
  log_path: "/var/log/app.log",
  cache_size: 1024
}

begin
  parsed_config = ConfigParser.parse(config)
  parsed_config.each do |key, value|
    puts "#{key}: #{value} (#{value.class})"
  end
rescue ArgumentError => e
  puts "配置解析错误: #{e.message}"
end

🎯 条件判断最佳实践

1. 保持条件简单

ruby
# 好的做法:将复杂条件提取为方法
class UserValidator
  def self.valid_user?(user)
    user &&
    user.active? &&
    user.email_verified? &&
    user.age >= 18
  end
  
  def self.premium_user?(user)
    valid_user?(user) && user.subscription == "premium"
  end
end

# 使用
if UserValidator.premium_user?(user)
  # 处理高级用户
end

2. 合理使用case语句

ruby
# 好的做法:多个离散值使用case
case action
when "create"
  create_resource
when "update"
  update_resource
when "delete"
  delete_resource
else
  raise ArgumentError, "未知操作: #{action}"
end

# 避免:简单条件使用case
# 不推荐:
case
when score >= 90
  puts "优秀"
when score >= 80
  puts "良好"
end

# 推荐:
if score >= 90
  puts "优秀"
elsif score >= 80
  puts "良好"
end

3. 避免深层嵌套

ruby
# 不好的做法:深层嵌套
if user
  if user.active?
    if user.age >= 18
      if user.subscription == "premium"
        # 处理逻辑
      end
    end
  end
end

# 好的做法:早期返回
def process_user(user)
  return unless user
  return unless user.active?
  return unless user.age >= 18
  return unless user.subscription == "premium"
  
  # 处理逻辑
end

# 或者合并条件
def process_user(user)
  if user && user.active? && user.age >= 18 && user.subscription == "premium"
    # 处理逻辑
  end
end

4. 使用安全导航运算符

ruby
# 旧方式:多重nil检查
if user && user.profile && user.profile.address && user.profile.address.city
  puts user.profile.address.city
end

# 新方式:安全导航运算符 (Ruby 2.3+)
puts user&.profile&.address&.city

# 结合条件赋值
city = user&.profile&.address&.city || "未知城市"

📚 下一步学习

掌握了Ruby条件判断后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。