首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法在Ruby 2.0上修改冻结的Fixnum

无法在Ruby 2.0上修改冻结的Fixnum
EN

Stack Overflow用户
提问于 2013-04-06 01:46:40
回答 3查看 2K关注 0票数 4

我有以下代码:

代码语言:javascript
复制
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

它输出一个错误,并显示:

代码语言:javascript
复制
> 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上运行,没有问题。发生什么事了呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-06 02:30:35

@divisors是Fixnum实例上的一个实例变量,因此您正在尝试修改它。你可能不应该这么做。

那这个呢?

代码语言:javascript
复制
module Divisors
  def self.for(number)
    @divisors ||= { }
    @divisors[number] ||= begin
      case (number)
      when 1
        [ number ]
      else
        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(:*) } - [ number ]
      end
    end
  end

  def self.sum(number)
     @divisors_sum ||= { }
     @divisors_sum[number] ||= divisors(number).reduce(:+)
  end
end

class Numeric
  #... math helpers

  def divisors
    Divisors.for(self)
  end

  def divisors_sum
     Divisors.sum(self)
  end
end

这意味着Numeric中的方法不修改任何实例,缓存存储在其他地方。

票数 4
EN

Stack Overflow用户

发布于 2013-04-06 02:42:50

除了@tadman的回答之外,为什么在1.9.3中工作而不是在2.0.0中工作的原因是因为2年前决定冻结Fixnums (和Bignums),thisthis证明了这一点。

票数 4
EN

Stack Overflow用户

发布于 2013-04-06 03:36:50

正如其他人指出的那样,ruby核心已经决定Fixnums和Bignums现在是冻结的,所以你不能在这些类的对象中设置实例变量。

一种解决方法是创建一个外部模块,该模块保留由这些冻结对象的值索引的散列缓存,并使用这些散列的元素而不是实例变量:

代码语言:javascript
复制
require 'prime'

module FrozenCacher
  def FrozenCacher.fcache
    @frozen_cache ||= {}
  end

  def fcache
    FrozenCacher.fcache[self] ||= {}
  end
end

class Numeric
  include FrozenCacher
  #... math helpers

  def divisors
    return [self] if self == 1
    fcache[: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
    fcache[:divisors_sum] ||= divisors.reduce(:+)
  end

   #... more methods that evaluate code and 'caches' and assigns (||=) to instance variables
end

puts 4.divisors.inspect           # => [1, 2]
puts FrozenCacher.fcache.inspect  # => {4=>{:divisors=>[1, 2]}}
puts 10.divisors.inspect          # => [1, 5, 2]
puts FrozenCacher.fcache.inspect  # => {4=>{:divisors=>[1, 2]}, 10=>{:divisors=>[1, 5, 2]}}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15840233

复制
相关文章

相似问题

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