Ruby private attr_accessor和意外的nil

fzz*_*fzz 3 ruby

当我经常使用Ruby时,我养成了将所有内容都公开并忽视隐私的坏习惯.不幸的是,这种无知又回来困扰着我.这是我的问题的一个更简单的版本:

class Something
    private
    attr_accessor :sneaky
    public

    def initialize
        @sneaky = 0
    end

    def test
        while sneaky < 10
            puts "#{sneaky}"
            sneaky = (sneaky + 1)
        end
    end
end

test = Something.new
test.test
Run Code Online (Sandbox Code Playgroud)

这会输出sneaky(0)的正确值,然后输出错误sneaky = (sneaky + 1),说sneakynil:

0
test.rb:13:in `test': undefined method `+' for nil:NilClass (NoMethodError)
    from test.rb:19:in `<main>'
Run Code Online (Sandbox Code Playgroud)

那是怎么回事?@sneaky在构造函数中被设置为0.如果它真的是零,那不应该puts打印一个空行而不是一个0

编辑:是的,替换sneaky = (sneaky + 1)self.sneaky = sneaky + 1解决问题,即使self.sneaky=看起来像隐私侵犯,因为它有一个明确的接收器.显然,对于setter来说是一个例外.但与隐私的奇怪互动意味着你不能说self.sneaky += 1(你最终得到test.rb:14:in 'test': private method 'sneaky' called for #<Something:0x000001019004c8 @sneaky=0> (NoMethodError)).幸运的是,我不是唯一一个认为这很奇怪的人.

Jör*_*tag 5

foo = bar分配给称为的局部变量的形式foo.如果你想调用一个attr_writer,你需要使用一个明确的接收器:self.sneaky += 1.

这与此无关private,它只是局部变量赋值的基本Ruby语法.

  • 是的,这是Ruby规范中的疏忽.我在6个月前报告了它,它可能会包含在Ruby 2.3中,因此`self.sneaky + = 1`可以工作.我完全忘了我正在运行一个2.2-trunk的版本,并且应用了bugreport的补丁,这样我就不会收到错误. (2认同)