You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中基于Enumerable类的方法链实现错误及优化求助

解决方法及优化建议

首先咱们拆解你遇到的问题,一步步来修复和优化代码:

1. 核心错误原因

你看到的undefined method '[]' for #<Coffee:...>错误,是因为在Criteria#each里把Coffee实例当成哈希来访问属性了——c[:strength]是哈希的写法,但c是Coffee对象,应该用它的实例方法c.strength来获取强度值。

2. 修正并增强Criteria#each方法

咱们不仅要修复错误,还要同时支持strength过滤和limit限制,并且让代码更具扩展性。这里是修正后的Criteria类:

class Criteria
  include Enumerable # 让Criteria直接支持Enumerable的所有方法(map/select等)

  def initialize(klass)
    @klass = klass
  end

  def criteria
    @criteria ||= { conditions: {}, limit: nil }
  end

  # 过滤指定强度的咖啡
  def strength(strength)
    criteria[:conditions][:strength] = strength
    self # 返回self以支持方法链
  end

  # 限制返回结果数量
  def limit(limit)
    criteria[:limit] = limit
    self
  end

  def each(&block)
    # 第一步:根据条件过滤咖啡(支持未来扩展更多条件)
    filtered_coffees = @klass.collection.select do |coffee|
      criteria[:conditions].all? do |attr_name, target_value|
        coffee.send(attr_name) == target_value
      end
    end

    # 第二步:应用limit限制(仅当设置了limit时生效)
    filtered_coffees = filtered_coffees.take(criteria[:limit]) if criteria[:limit]

    # 第三步:遍历最终结果
    filtered_coffees.each(&block)
  end
end

3. 修复CoffeeShop的小问题

你的CoffeeShop.collection方法每次调用都会重新创建数组,这会导致数据丢失或重复初始化,咱们改成只初始化一次:

class CoffeeShop
  include Enumerable

  def self.collection
    # 用||=确保集合只初始化一次
    @collection ||= [
      Coffee.new("Laos", 10),
      Coffee.new("Angkor", 7),
      Coffee.new("Nescafe", 1)
    ]
  end

  def self.limit(*args)
    Criteria.new(self).limit(*args)
  end

  def self.strength(*args)
    Criteria.new(self).strength(*args)
  end

  # 实现Enumerable要求的each方法,让CoffeeShop本身也支持枚举
  def each(&block)
    self.class.collection.each(&block)
  end
end

4. 测试验证

现在运行你的测试代码:

CoffeeShop.strength(10).each { |c| puts c.inspect }
# 输出:#<Coffee:0x00... @name="Laos", @strength=10>

还可以链式调用多个条件+Enumerable方法:

# 获取强度>=7的前1个咖啡的名字
CoffeeShop.collection.select { |c| c.strength >=7 }.limit(1).map(&:name)
# 输出:["Laos"]

额外编码建议

  • 扩展性优化:现在的Criteria支持轻松添加更多条件方法(比如name),只需新增一个方法把条件加入criteria[:conditions]即可,不用修改过滤逻辑。
  • 代码风格:Ruby里更推荐用符号作为哈希键(比如:conditions而非"conditions"),保持代码风格一致性。
  • Enumerable复用:让Criteria包含Enumerable后,你可以直接使用map、select、sort等所有Enumerable方法,无需自己重复实现。

内容的提问来源于stack exchange,提问作者craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:42:19