首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Ruby自定义迭代器

Ruby自定义迭代器
EN

Stack Overflow用户
提问于 2013-08-30 05:31:51
回答 3查看 3.5K关注 0票数 1

我有一个类game,它包含一些定制对象数组(恐龙、仙人掌等),这些对象由不同的访问器(如game.dinosaursgame.cavemen等)返回。

目前,所有这些访问器都只是返回内部存储的数组。但是现在我想向这些访问器返回的这些数组添加一些自定义迭代方法,以便能够编写类似于game.dinosaurs.each_carnivore { ... }等代码,类似于LibXML::XML::Node中的each_elementeach_attr迭代器。但是,从我的访问器game.dinosaursgame.cavemen返回的对象仍然必须像数组一样运行。

在Ruby中,这样的事情通常是如何实现的?我是否应该使从我的访问器返回的对象成为从Ruby的Array类派生的一些自定义类?或者我应该创建一个混合了Enumerable的自定义类?

我知道我可以在我的集合中外部使用mapselect,但是我想在内部封装这些迭代,这样我们类的用户就不需要费心如何设置一个迭代,只从内部数组中选择食肉恐龙。

编辑:我问的不是如何使用迭代器或如何实现迭代器,而是如何向对象添加一些自定义迭代器(以前只是普通数组)(而且仍然需要这样做)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-30 06:47:40

这取决于(一如既往)。您可以使用数组子类,也可以构建自定义类并使用组合和委托。下面是一个带有数组子类的简单示例:

代码语言:javascript
运行
复制
class DinosaurArray < Array
  def carnivores
    select { |dinosaur| dinosaur.type == :carnivore }
  end

  def herbivores
    select { |dinosaur| dinosaur.type == :herbivore }
  end

  def each_carnivore(&block)
    carnivores.each(&block)
  end

  def each_herbivore(&block)
    herbivores.each(&block)
  end
end

这里有一个简单的组合和授权:

代码语言:javascript
运行
复制
class DinosaurArray
  def initialize
    @array = []
  end

  def <<(dinosaur)
    @array << dinosaur
  end

  def carnivores
    @array.select { |dinosaur| dinosaur.type == :carnivore }
  end

  def herbivores
    @array.select { |dinosaur| dinosaur.type == :herbivore }
  end

  def each(&block)
    @array.each(&block)
  end

  def each_carnivore(&block)
    carnivores.each(&block)
  end

  def each_herbivore(&block)
    herbivores.each(&block)
  end
end

这两种实现都可以这样使用:

代码语言:javascript
运行
复制
require 'ostruct'

dinosaurs = DinosaurArray.new
dinosaurs << OpenStruct.new(type: :carnivore, name: "Tyrannosaurus")
dinosaurs << OpenStruct.new(type: :carnivore, name: "Allosaurus")
dinosaurs << OpenStruct.new(type: :herbivore, name: "Apatosaurus")

puts "Dinosaurs:"
dinosaurs.each.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }
puts

但也有自定义迭代器:

代码语言:javascript
运行
复制
puts "Carnivores:"
dinosaurs.each_carnivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }
puts

puts "Herbivores:"
dinosaurs.each_herbivore.with_index(1) { |dinosaur, i| puts "#{i}. #{dinosaur.name}" }

输出:

代码语言:javascript
运行
复制
Dinosaurs:
1. Tyrannosaurus
2. Allosaurus
3. Apatosaurus

Carnivores:
1. Tyrannosaurus
2. Allosaurus

Herbivores:
1. Apatosaurus
票数 7
EN

Stack Overflow用户

发布于 2013-08-30 05:48:20

你可以用红宝石块来做这件事。Read more

下面是一个简单的例子:

代码语言:javascript
运行
复制
class Game

  def initialize
    @carnivoures = [1,2,3]
  end

  def each_carnivoures
    @carnivoures.each do |carni|
      yield carni
    end
  end

end

Game.new.each_carnivoures{ |c| p c}
票数 1
EN

Stack Overflow用户

发布于 2018-04-23 18:43:42

这也将是一个很好的可能性,链接这样的过滤器。您可以通过将select方法包装到自定义方法中,返回新类而不是数组来实现这一点。您还可以包装其他一些方法,例如map

代码语言:javascript
运行
复制
class Units < Array
  def select
    self.class.new(super)
  end

  def dinosaurs
    select{ |unit| unit.kind == 'dinosaur' }
  end

  def cavemen
    select{ |unit| unit.kind == 'caveman' }
  end

  def carnivore
    select{ |unit| unit.type == 'carnivore' }
  end

  def herbivore
    select{ |unit| unit.type == 'herbivore' }
  end
end

Units.dinosaurs.carnivore
Units.cavemen.herbivore
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18525645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档