【问题标题】:understanding ruby class attributes, using accessor macros and self理解 ruby​​ 类属性,使用访问器宏和 self
【发布时间】:2012-03-21 17:33:25
【问题描述】:

所以我在 ruby​​ 中创建了一个类:

class User
  def initialize
  end
end

现在说我想创建一个带有 getter/setter 的哈希属性,我对这样做的选项感到困惑。

如果我这样做:

class User
  attr_accessor :some_hash
end

但我不希望这个散列永远为零,总是一个空散列。

我很困惑什么时候该做:

def some_hash
  self.some_hash ||= {}
end

然后做:

def some_hash
  @some_hash ||= {}
end

有什么区别?

如果我不使用 attr_accessor,我必须同时创建读取器和写入器(或 getter/setter):

def some_hash=()
end

def some_hash
end

我希望有人可以清除我创建 some_hash 属性的选项,该属性是一个哈希,如果它为空则永远不会返回 nil。

即使用 attr_accessor,手动创建方法,最后何时使用 @some_hash 和 self.some_hash

【问题讨论】:

    标签: ruby


    【解决方案1】:

    attr_accessor :some_hash 定义给定属性的读取器和写入器方法。相当于这样:

    class User
      def some_hash
        @some_hash
      end
    
      def some_hash=(some_hash)
        @some_hash = some_hash
      end
    end
    

    @some_hash 指的是对象的实例变量,而some_hashsome_hash=方法。前者返回变量的值,后者设置它。

    成语self.some_hash ||= {}等价于self.some_hash || self.some_hash = {}

    Ruby 中的布尔运算符short circuit,这意味着如果第一个表达式 (self.some_hash) 返回真值,则根本不会执行第二个表达式 (self.some_hash = {})。

    方法:

    def some_hash
      self.some_hash ||= {}
    end
    

    实际上是递归的,因为它扩展为some_hash || self.some_hash = {}。它会一直调用自己,直到你得到堆栈溢出。使用第二种形式:

    def some_hash
      @some_hash ||= {}
    end
    

    由于它直接设置实例变量,递归不会有问题,也不必调用 writer 方法。 some_hash 永远不能返回nil,因为如果@some_hashnil,在方法返回之前它会被分配一个空哈希。

    顺便说一句,这也称为lazy initialization,因为变量是在第一次访问时初始化的,而不是在创建User 实例时。

    【讨论】:

      【解决方案2】:

      除了马修斯的回答,再多说一点属性:

      属性是方法。它们定义了您如何处理某些符号。 attr_reader 定义 getter,attr_writer 定义 setter,attr_accessor 定义两者。虽然属性只接受符号,但它不会“声明”任何实例变量,因为在 Ruby 中没有声明变量这样的事情。它总是在第一次使用时被声明和初始化。

      所以在你说attr_accessor :some_hash 之后,运行时会知道访问一个名为some_hash 的变量的方法,但是这个变量在你使用它之前是不存在的。你可以试试:

      class User
        attr_accessor :some_hash
        attr_reader :some_other_hash
      end
      usr = User.new
      p usr.some_hash
      
      usr.some_hash = {}
      p usr.some_hash
      
      p usr.some_other_hash
      usr.some_other_hash = {}
      

      您将收到nil,{},nil, and an error。错误是因为只定义了 getter 方法但没有定义 setter。如果你想自己定义一个setter,你仍然可以写一个名为some_other_hash=()的方法

      我对实例变量的建议是(我可能还有很多其他人都在使用):

      class User
        attr_accessor :some_hash
      
        def initialize
          @some_hash = {}
        end
      
      end
      usr = User.new
      p usr.some_hash
      

      这种方式在为类创建对象时做一个“psudo”声明,实例变量也会被初始化。

      【讨论】:

      • 使用您的最后一个示例,如果我向名为print_meUser 类添加另一个方法,我应该在方法内部使用@some_hash 还是some_hash 来访问上下文中的变量?我的意思是:def print_me; puts @some_hash; enddef print_me; puts some_hash; end。我希望我的例子足够清楚!
      猜你喜欢
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-24
      • 2017-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多