1

我一直在通过将笔和纸 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哈希的迭代器看起来很笨重,但我没有找到更好的方法来完成这项任务。

4

2 回答 2

3

你甚至没有[]=在你的例子中调用你的方法。这将像这样完成:

newChar[:str] = 123

代替

newChar.stats[:str] = 123

所以打电话给newChar.stats[:str] = 123你甚至不需要你的方法定义。原因是两者newChar.statsnewChar.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
于 2013-08-15T18:47:43.330 回答
3

如果您需要一个公共 getter 来获取哈希,但您不希望用户修改哈希 -<em>您的类的实例变量 -,您可以使用 dup 来完成。

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

freeze如上所述,如果使用 .dup-solution 的解决方案甚至会为您的班级冻结哈希,则 .dup-solution 将允许您从班级内部而不是外部修改哈希。

于 2013-08-15T20:49:41.593 回答