Ruby 如何创建inject方法的自定义实现?

Ruby 如何创建inject方法的自定义实现?,ruby,Ruby,开始看起来很容易。以下是我在几分钟内编写的第一个代码块: module Enumerable def my_inject(memo=false) memo = memo ? memo : self[0] self.my_each do |item| memo = yield(memo, item) end return memo end end 当使用初始值调用inject方法时,它会按预期工作。但是我还没有找到一种方法,使它在没有任何初

开始看起来很容易。以下是我在几分钟内编写的第一个代码块:

module Enumerable

  def my_inject(memo=false)
    memo = memo ? memo : self[0]
    self.my_each do |item|
      memo = yield(memo, item)
    end
    return memo
  end

end
当使用初始值调用inject方法时,它会按预期工作。但是我还没有找到一种方法,使它在没有任何初始值的情况下正常工作

例如:

puts [1,2,3,4].my_inject(0) { |memo, i| memo+i} #=> 10
puts [1,2,3,4].my_inject { |memo, i| memo+i} #=> 11
这就是原始Ruby inject方法的输出:

puts [1,2,3,4].inject { |memo, i| memo+i} #=> 10
Ruby医生说

如果未明确指定备注的初始值,则 集合的第一个元素用作备注的初始值

那么如何为初始值设置合适的数据类型呢?我们应该为Ruby中的每种数据类型设置一个条件,并为每种数据类型设置一个默认值吗

那么如何为初始值设置合适的数据类型呢?我们应该为Ruby中的每种数据类型设置一个条件,并为每种数据类型设置一个默认值吗

否,默认值是集合的第一个元素


Ruby允许您定义自己的类,因此为每种可能的类型编写一个案例是不可能的,因为它们的数量是无限的。

如果调试Ruby自己的实现,您将看到它在没有给出默认备注的情况下从第二个元素开始迭代:

> [1,2,3].inject { |m, i| puts "M: #{m} | I: #{i}"; break }
M: 1 | I: 2
因此,您的实现应该如下所示:

def my_inject(*args)
  init = args.size > 0
  memo = init ? args[0] : self[0]

  self.drop(init ? 0 : 1).my_each do |item|
    memo = yield(memo, item)
  end

  return memo
end

puts [1,2,3,4].my_inject(0) { |memo, i| memo+i} #=> 10
puts [1,2,3,4].my_inject { |memo, i| memo+i}    #=> 10

之所以使用
init=args.size>0
是因为您必须考虑到有人可能想要执行
[…].my_inject(false){…}
。因此,您无法检查
memo==false
要确定是否需要跳过第一个元素,您必须检查给出的实际参数计数。

只是出于好奇:

class Array
  def my_inject(memo = nil, enum = self.each)
    return enum_for(:my_inject) unless block_given?

    memo = enum.next if memo.nil?
    my_inject(yield(memo, enum.next), enum, &Proc.new)
  rescue StopIteration
    memo
  end 
end

[1,2,3].my_inject(3) { |memo, v| memo += v } 
#⇒ 9
[1,2,3].my_inject &:*
#⇒ 6

谢谢你的回答和解释“假”案例。你说得对。