In Ruby, how to write code inside a class so that getter foo and setter self.foo = … look more similar?

前端 未结 3 1457
面向向阳花
面向向阳花 2020-12-30 17:18

In Ruby, inside a class\'s instance method, we use a getter by

foo

and we use a setter by

self.foo = something
相关标签:
3条回答
  • 2020-12-30 17:40

    Since local scope takes precedence, when you say foo = something, a local variable foo will be created and assigned the contents of something.

    The reason you can write foo in order to use the getter is because Ruby will move up in scope when it can't find a variable with that name and it will eventually find the method.

    If there is a local variable with the same name as the getter method, Ruby will use its value instead:

    class Foo
    
      attr_accessor :foo
    
      def initialize
        @foo = :one
      end
    
      def f
        foo = :two
        foo
      end
    end
    
    Foo.new.f
    # => :two
    

    In order to make it clear that you want to access the setter, you must write self.foo = something. That will tell Ruby you want to execute the foo= method on the self object with something as parameter.

    0 讨论(0)
  • 2020-12-30 17:40

    As far as I know, there isn't a way around this in Ruby. I'm pretty confident this is simply how Ruby evaluates expressions.

    When given a value, Ruby will first check if there is a local variable within the context which matches the one being called. If there is (perhaps 'foo' in your case), that will be the value used. If there is no such value, then Ruby will try to look up the value as a method call (falling through to "self" as the caller). If no such method exists in the look up path, an error will be raised.

    The need to use "self" in the setter is to avoid Ruby setting the value as a local variable, while the lack of the use of "self" only works in the getter instance when there is no local variable of the same name being used in that context. It is probably better and clearer, albeit slightly more verbose, to be explicit with your use of self as to avoid confusion about where values are coming from.

    0 讨论(0)
  • 2020-12-30 17:44

    If you are willing to break the conventions, you can write your setters using jQuery style, using the same method for getter and setter, depending of whether it has arguments or not:

    def foo *args
      return @foo if args.empty?
      @foo = args.first
    end
    # => nil
    
    foo
    # => nil 
    foo(:bar) # foo = :bar
    # => :bar 
    foo
    # => :bar 
    
    0 讨论(0)
提交回复
热议问题