连续添加数字

时间:2017-07-26 14:33:28

标签: ruby

我正在尝试学习Ruby,我遇到了一个在线问题,我需要创建类似于此的东西:

add(1)         # => 1
add(1).(2)     # => 3
add(1).(2).(3) # => 6

等等。

我已经阅读过,最接近我的工作是使用以下代码:

def add(n)
  Proc.new { |s| s + n }
end

在某种程度上有效。

我可以运行以下内容:

add(1)     # => #<Proc:0x007fb8aac309f0@(pry):2>
# or
add(1).(2) # => 3

但是我尝试这样做的那一刻:

add(1).(2).(3)

我收到以下错误:

  

NoMethodError:3的未定义方法callInteger

为什么我会收到此错误?如何更改此方法以便它接受尽可能多的新值,因为我将其添加为自身而不会给出错误?

2 个答案:

答案 0 :(得分:3)

作为参考,此问题来自CodeWars "A Chain Adding Function"

实现此目标的最简单方法是定义Integer#call

class Integer
  def call(n)
    self + n
  end
end

def add(n)
  n
end

puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6

返回的对象是纯Ruby整数,而不是代理对象。

请注意,修改这样一个重要的类可能不是一个好主意。可以使用refinements以避免破坏其他Ruby部分:

module ChainAdding
  refine Integer do
    def call(n)
      self + n
    end
  end
end

def add(n)
  n
end

using ChainAdding

puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6

如果你正在学习Ruby,那么这种元编程技巧并不是你应该首先关注的。很高兴知道我们可以做到这一点,但这并不意味着我们应该这样做。

答案 1 :(得分:2)

你不能完全按照自己的意愿去做。原因是你必须返回一些东西,并且根据你是否要继续使用链条,某些东西不能改变。

请注意,一些Rails对象会让您在REPL(irb,pry)中产生错觉,但它们实际上只是重新定义#inspect,这是在所述REPL可视化时调用的。

相反,你可以做一些非常相似的事情,它有一个更好的界面IMO:

def add(starting_number)
  sum = starting_number

  accumulator = proc do |next_number|
    if next_number
      sum += next_number
      accumulator
    else
      sum
    end
  end
end

add(1)                # => #<Proc:0x007fb8ae20e860@(pry):4>
add(1).(2)            # => #<Proc:0x007fb8ae4894f0@(pry):4>

add(1).()             # => 1
add(1).(2).()         # => 3
add(1).(2).(3).(4).() # => 10