【发布时间】:2013-04-05 17:46:39
【问题描述】:
我有以下代码:
require 'prime'
class Numeric
#... math helpers
def divisors
return [self] if self == 1
@divisors ||= prime_division.map do |n,p|
(0..p).map { |i| n**i }
end.inject([1]) do |a,f|
a.product(f)
end.map { |f| f.flatten.reduce(:*) } - [self]
end
def divisors_sum
@divisors_sum ||= divisors.reduce(:+)
end
#... more methods that evaluate code and 'caches' and assigns (||=) to instance variables
end
输出错误:
> 4.divisors
/home/cygnus/Projects/project-euler/stuff/numbers.rb:24:in `divisors_sum': can't modify frozen Fixnum (RuntimeError)
当我将缓存删除到实例变量 @divisors、@divisors_sum... 等时,错误消失了。这只发生在 ruby 2.0 上。在 1.9.3 上运行它没有问题。发生了什么事?
【问题讨论】:
-
已确认代码在 1.9.3 上可以正常工作,也确认在 2.0.0 中对我不起作用。不过,将实例变量添加到 Fixnum 是非常不寻常的。
-
试图加快进程。有些方法可能需要几秒钟的时间,并且为大量数字一遍又一遍地计算会导致执行时间增加。
-
prime是宝石吗?第 24 行是哪个语句? -
我认为冻结的 fixnums 会一直存在,来自 ruby-core 中这样的 cmets:atdot.net/sp/view/4qjkcm/readonly 所以我建议简单地在 Fixnum 之外缓存数据。
-
这真的很奇怪,我不是要修改 Fixnum 实例本身(这显然是做不到的),而是保存它的变量。