How to make instance variables private in Ruby?

后端 未结 6 1230
孤城傲影
孤城傲影 2020-12-04 17:52

Is there any way to make instance variables \"private\"(C++ or Java definition) in ruby? In other words I want following code to result in an error.

class B         


        
6条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-04 18:27

    It is possible (but inadvisable) to do exactly what you are asking.

    There are two different elements of the desired behavior. The first is storing x in a read-only value, and the second is protecting the getter from being altered in subclasses.


    Read-only value

    It is possible in Ruby to store read-only values at initialization time. To do this, we use the closure behavior of Ruby blocks.

    class Foo
      def initialize (x)
        define_singleton_method(:x) { x }
      end
    end
    

    The initial value of x is now locked up inside the block we used to define the getter #x and can never be accessed except by calling foo.x, and it can never be altered.

    foo = Foo.new(2)
    foo.x  # => 2
    foo.instance_variable_get(:@x)  # => nil
    

    Note that it is not stored as the instance variable @x, yet it is still available via the getter we created using define_singleton_method.


    Protecting the getter

    In Ruby, almost any method of any class can be overwritten at runtime. There is a way to prevent this using the method_added hook.

    class Foo
      def self.method_added (name)
        raise(NameError, "cannot change x getter") if name == :x
      end
    end
    
    class Bar < Foo
      def x
        20
      end
    end
    
    # => NameError: cannot change x getter
    

    This is a very heavy-handed method of protecting the getter.

    It requires that we add each protected getter to the method_added hook individually, and even then, you will need to add another level of method_added protection to Foo and its subclasses to prevent a coder from overwriting the method_added method itself.

    Better to come to terms with the fact that code replacement at runtime is a fact of life when using Ruby.

提交回复
热议问题