Ruby 如何在没有其他可枚举类的情况下创建可枚举类?

Ruby 如何在没有其他可枚举类的情况下创建可枚举类?,ruby,Ruby,几天前,我问了同样的问题,但不知怎么的,沟通没有发生。我重组了我的问题,希望我们能集中精力解决我需要解决的问题 问题基本上是这样的:如何创建一个不只是使用另一个可枚举类的可枚举类?作为我需要做的一个简单而完整的例子,请考虑这个类: class MyClass include Enumerable def get_next return_val = rand.to_s if return_val.match(/33/) r

几天前,我问了同样的问题,但不知怎么的,沟通没有发生。我重组了我的问题,希望我们能集中精力解决我需要解决的问题

问题基本上是这样的:如何创建一个不只是使用另一个可枚举类的可枚举类?作为我需要做的一个简单而完整的例子,请考虑这个类:

class MyClass
    include Enumerable

    def get_next
        return_val = rand.to_s

        if return_val.match(/33/)
            return nil
        else
            return return_val
        end
    end

    def each
        # ??????
    end
end
在这个类中,get_接下来计算一个随机值。然后,如果该值有两个相邻的3,则该方法返回nil。否则返回值。因此,您可以反复运行get_next,通常运行不到十次:

myob = MyClass.new

while not myob.get_next.nil?
    puts 'got one'
end
事实上,get_下一步将通过数千个数据点进行搜索。当它找到下一项时,它返回一个相当大的对象。MyClass对象不可能将所有项都拖到一个数组中。一次只需要一个

事实上,我的课和上面的结构一样好。然而,我想以一种鲁比的方式实现它

因此,考虑到上述工人阶级,请填空。每个()中有什么内容可以使其成为可枚举类?

类MyClass
class MyClass
  include Enumerable

  def enum
    @enum ||= Enumerator.new do |y|
      loop do  
        value = get_next
        raise StopIteration.new("nil") if value.nil?
        y << value
      end    
    end  
  end

  def each
    return enum_for(:each) unless block_given?
    enum.each(&Proc.new)
  end

  def get_next
    return_val = rand.to_s
    return_val.match(/33/) ? nil : return_val
  end
end

mc = MyClass.new
mc.each { |e| puts e }
#⇒ 0.9354594959902887
#  0.6425492923024724
#  0.24551401459676037
#  0.17117672854168786
#  0.15611540754420283
#  0.3914491388594509
#  0.40243662946930725
#  0.3792875585148314
#  0.11978219941961588
#  0.49891129730441874
包括可枚举的 定义枚举 @enum | |=枚举器。新do | y| 环道 value=get\u next 如果value.nil,则引发StopIteration.new(“nil”)? y
类MyClass
包括可枚举的
定义枚举
@enum | |=枚举器。新do | y|
环道
value=get\u next
如果value.nil,则引发StopIteration.new(“nil”)?
Y
填空。每个()中都有哪些内容使其成为可枚举类

class MyClass
  include Enumerable

  def enum
    @enum ||= Enumerator.new do |y|
      loop do  
        value = get_next
        raise StopIteration.new("nil") if value.nil?
        y << value
      end    
    end  
  end

  def each
    return enum_for(:each) unless block_given?
    enum.each(&Proc.new)
  end

  def get_next
    return_val = rand.to_s
    return_val.match(/33/) ? nil : return_val
  end
end

mc = MyClass.new
mc.each { |e| puts e }
#⇒ 0.9354594959902887
#  0.6425492923024724
#  0.24551401459676037
#  0.17117672854168786
#  0.15611540754420283
#  0.3914491388594509
#  0.40243662946930725
#  0.3792875585148314
#  0.11978219941961588
#  0.49891129730441874
医生说。因此,您可以这样做,只要它们不是
nil
,就继续生成值

def each
  while val = get_next
    yield val
  end
end
演示:

另一个演示(显示可枚举的
中的方法):


因此,这就足以让它成为“可枚举的”,在某种意义上说,它成功地融入了
可枚举的
(我认为Ruby没有正式定义“可枚举的”)。顺便说一句,你的问题并不清楚你是否真的需要它。如果你只想用
每个
检查值,那么你甚至不需要包括
可枚举的
。所做的只是为您提供额外的方法,如
map
select
。即使是
for
循环也可以通过
每个
工作,而不包括
可枚举的

irb(main):003:0> MyClass.new.map(&:to_f)
=> [0.6368065208805999, 0.6926393662295052, 0.9911564544581742, 0.35788099831068787]
irb(main):002:0> for e in MyClass.new
irb(main):003:1>   puts e
irb(main):004:1> end
0.7638166357043203
0.18409214000273166
0.39757329498164495
0.14658393540113002
0.948396753859117
0.3157122887487579
0.4804571082701993
(但请注意,
for
循环通常是不被鼓励的:,。我展示这一点只是为了进一步证明
每个
的重要性,以及
可枚举
对于基本迭代的不重要。)

填空。每个()中都有哪些内容使其成为可枚举类

class MyClass
  include Enumerable

  def enum
    @enum ||= Enumerator.new do |y|
      loop do  
        value = get_next
        raise StopIteration.new("nil") if value.nil?
        y << value
      end    
    end  
  end

  def each
    return enum_for(:each) unless block_given?
    enum.each(&Proc.new)
  end

  def get_next
    return_val = rand.to_s
    return_val.match(/33/) ? nil : return_val
  end
end

mc = MyClass.new
mc.each { |e| puts e }
#⇒ 0.9354594959902887
#  0.6425492923024724
#  0.24551401459676037
#  0.17117672854168786
#  0.15611540754420283
#  0.3914491388594509
#  0.40243662946930725
#  0.3792875585148314
#  0.11978219941961588
#  0.49891129730441874
医生说。因此,您可以这样做,只要它们不是
nil
,就继续生成值

def each
  while val = get_next
    yield val
  end
end
演示:

另一个演示(显示可枚举的
中的方法):


因此,这就足以让它成为“可枚举的”,在某种意义上说,它成功地融入了
可枚举的
(我认为Ruby没有正式定义“可枚举的”)。顺便说一句,你的问题并不清楚你是否真的需要它。如果你只想用
每个
检查值,那么你甚至不需要包括
可枚举的
。所做的只是为您提供额外的方法,如
map
select
。即使是
for
循环也可以通过
每个
工作,而不包括
可枚举的

irb(main):003:0> MyClass.new.map(&:to_f)
=> [0.6368065208805999, 0.6926393662295052, 0.9911564544581742, 0.35788099831068787]
irb(main):002:0> for e in MyClass.new
irb(main):003:1>   puts e
irb(main):004:1> end
0.7638166357043203
0.18409214000273166
0.39757329498164495
0.14658393540113002
0.948396753859117
0.3157122887487579
0.4804571082701993

(但请注意,
for
循环通常是不被鼓励的:,。我展示这一点只是为了进一步证明
每个
的重要性,以及
可枚举
对于基本迭代的不重要。)

看一看示例–调用
Take(10)
只返回前10项,虽然数字是在无限循环中产生的。值得一读:看一看示例–调用
Take(10)
只返回前10项,尽管数字是在无限循环中生成的。值得一读:太棒了!就像我需要的一样。谢谢好极了就像我需要的一样。谢谢如果您希望
each
不带参数返回枚举数(就像stdlib enumerables一样),请将
return to_enum,除非block_gived?
添加到方法顶部。此实现与
next
契约不兼容,后者要求在没有要迭代的项时抛出
StopIteration
。这就是说,这个实现与ruby完全不兼容,并且可能有许多隐藏的故障,这些故障将在以后成为生产运行时的错误。正确的方法是使用
枚举器,正如我在回答中所显示的那样,这显然是错误的,甚至更危险。@mudasobwa,嗯?我正按照文件上说的做。“与ruby完全不兼容”?你是否忽略了我证明它有效的部分?顺便说一句,因为您的演示甚至没有使用
Enumerable
中的任何内容。以及“
next
contract”?它甚至没有
next
方法。这是一个
枚举器
的东西,而不是
可枚举的
东西。如果您确实想要一个非块
枚举数
结果,只需添加mwp所说的内容。你甚至可以自己做(只是时间更长)。然后还有一个
next
,它将执行
StopIteration
。你能展示一个实际的问题吗?当然。试着让它变得懒惰,好吧,我刚试过,效果很好。(顺便说一句,它已经很懒了,不是吗?)…如果您希望
each
不带任何参数返回枚举数(就像stdlib enumerables一样),请将
return to_enum,除非给出block_?
添加到方法顶部。此实现与
next
契约不兼容,当没有要迭代的项时,期望抛出
StopIteration
。也就是说,这个实现是不兼容的