gpt4 book ai didi

与 Enumerable 类链接的 Ruby 方法

转载 作者:太空宇宙 更新时间:2023-11-03 17:43:26 25 4
gpt4 key购买 nike

我正在尝试调整此帖子 (Method chaining and lazy evaluation in Ruby) 中引用的方法链接示例,以与实现 Enumerable 的对象一起使用类 ( Implement a custom Enumerable collection class in Ruby )

咖啡类:

class Coffee

attr_accessor :name
attr_accessor :strength

def initialize(name, strength)
@name = name
@strength = strength
end

def <=>(other_coffee)
self.strength <=> other_coffee.strength
end

def to_s
"<name: #{name}, strength: #{strength}>"
end

end

条件类:

class Criteria

def initialize(klass)
@klass = klass
end

def criteria
@criteria ||= {:conditions => {}}
end

# only show coffee w/ this strength
def strength(strength)
criteria[:strength] = strength
self
end

# if there are multiple coffees, choose the first n=limit
def limit(limit)
criteria[:limit] = limit
self
end

# allow collection enumeration
def each(&block)
@klass.collection.select { |c| c[:strength] == criteria[:strength] }.each(&block)
end

end

CoffeeShop 类:

class CoffeeShop

include Enumerable

def self.collection
@collection=[]
@collection << Coffee.new("Laos", 10)
@collection << Coffee.new("Angkor", 7)
@collection << 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

end

当我运行这段代码时:

CoffeeShop.strength(10).each { |c| puts c.inspect }

我得到一个错误:

criteria.rb:32:in block in each': undefined method '[]' for #<Coffee:0x007fd25c8ec520 @name="Laos", @strength=10>

我确定我没有定义 Criteria.each方法正确,但我不确定如何更正它。我该如何纠正这个问题?

此外,each方法不支持 limit如目前所写。是否有更好的方法来过滤数组,以便更容易同时支持 strengthlimit

感谢其他编码建议。

最佳答案

您的Coffee 类定义了namestrength 的方法访问器。对于单个 coffee 对象,您可以通过

获取属性
coffee.name
# => "Laos"
coffee.strength
# => 10

在您的 Criteria#each 方法中,您尝试使用下标运算符访问属性,即 c[:strength](使用 c 在本例中是 Coffee 的一个实例)。现在,在您的 Coffee 类中,您还没有实现下标访问器,这导致了您在那里看到的 NoMethodError

因此,您可以按如下方式调整您的 Criteria#each 方法:

def each(&block)
@klass.collection.select { |c| c.strength == criteria[:strength] }.each(&block)
end

或者您可以在您的 Coffee 类上实现下标运算符:

class Coffee
attr_accessor :name
attr_accessor :strength

# ...

def [](key)
public_send(key)
end

def []=(key, value)
public_send(:"#{key}=", value)
end
end

不,作为附录,您可能希望在任何情况下扩展您的 each 方法。一个常见的(通常是隐式预期的)模式是,如果没有给出 block ,像 each 这样的方法返回一个 Enumerator。这允许像 CoffeeShop.strength(10).each.group_by(&:strength) 这样的模式。

您可以在您的方法中实现一个简单的在线程序:

def each(&block)
return enum_for(__method__) unless block_given?
@klass.collection.select { |c| c.strength == criteria[:strength] }.each(&block)
end

关于与 Enumerable 类链接的 Ruby 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48471052/

25 4 0