所以我在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
答案 0 :(得分:8)
attr_accessor :some_hash
定义给定属性的reader和writer方法。它相当于:
class User
def some_hash
@some_hash
end
def some_hash=(some_hash)
@some_hash = some_hash
end
end
@some_hash
是指对象的实例变量,而some_hash
和some_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_hash
为nil
,则会在方法返回之前为其分配一个空哈希值。
顺便说一下,这也称为lazy initialization,因为变量在首次访问时初始化,而不是在创建User
实例时初始化。
答案 1 :(得分:4)
除了马修斯的答案之外,还有一些关于属性的内容:
属性是方法。它们定义了如何处理某些符号。 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”声明,并且实例变量也将被初始化。