Ruby - 哈希属性的Setter方法

时间:2013-08-15 18:17:25

标签: ruby oop hash setter

我通过将笔和纸RPG转换为脚本来一直使用Ruby。

现在我将一个角色的统计数据保存在哈希中,我希望能够通过公共方法设置。我得到了这个:

class Character
    attr_reader :str, :con, :dex, :wis, :int, :level, :mods, :stats
    def initialize str, con, dex, wis, int, cha, level = 1
        @stats = { :str => str, :con => con, :dex => dex, :wis => wis, :int => int, :cha => cha }
        @mods = {}
        @level = level

        @stats.each_pair do |key, value|
            @mods[key] = ((value / 2 ) -5).floor
        end
    end

    def []=(index, value)
        @stats[index] = value
    end
end

这允许我实例化一个新角色,然后通过运行@stats来更新newChar.stats[:str] = 12

但是,我似乎也能够使用这种方法修改@mods,这是不可取的。 newChar.mods[:str] = 15将成功更改@mods哈希值,根据我的理解,使用当前的setter方法无法实现这一点。

在一个稍微单独的注释中,我用来创建我的@mods哈希的迭代器似乎很笨拙,但我没有找到更好的任务来完成任务。

2 个答案:

答案 0 :(得分:3)

您甚至没有在示例中调用[]=方法。这将是这样做的:

newChar[:str] = 123

而不是

newChar.stats[:str] = 123

所以要调用newChar.stats[:str] = 123你甚至不需要方法定义。原因是newChar.stats以及newChar.mods都会返回实际的哈希值,然后可以更改。

一种可能的解决方法是冻结@mods变量,使其不再被更改:

def initialize str, con, dex, wis, int, cha, level = 1
    # omitted ...

    @stats.each_pair do |key, value|
        @mods[key] = ((value / 2 ) -5).floor
    end

    @mods.freeze
end

如果您不希望再次更改@mods,这是一个很好的解决方案。尝试设置值将导致错误:

newChar.mods[:con] = 123
# RuntimeError: can't modify frozen Hash

在课堂上,您可以完全覆盖@mods

总结一下,完整的课程将是:

class Character
    attr_reader :str, :con, :dex, :wis, :int, :level, :mods, :stats
    def initialize str, con, dex, wis, int, cha, level = 1
        @stats = { :str => str, :con => con, :dex => dex, :wis => wis, :int => int, :cha => cha }
        @mods = {}
        @level = level

        @stats.each_pair do |key, value|
            @mods[key] = ((value / 2 ) -5).floor
        end

        @mods.freeze
    end
end

答案 1 :(得分:3)

如果你需要一个公共getter来获取哈希,但是你不希望用户修改哈希 - 你的类的实例变量 - 你可以用dup来做。

class MyClass
  ....
  def my_hash
    @my_hash.dup
  end
end

如上所述,带freeze的解决方案即使对您的类也会冻结哈希,.dup-solution将允许您修改类中的哈希值,但不能从外部修改哈希值。