Ruby中的新功能,试图找出为什么选择一种变体而不是另一种变体。你能不能写一个例子,其中一个比另一个更受欢迎?
class User
attr_accessor :username
def initialize(username)
self.username = username
end
end
class User
attr_accessor :username
def initialize(username)
@username = username
end
end
答案 0 :(得分:4)
他们是一回事。
self.username =
调用由attr_accessor定义的username=
函数。该功能如下所示:
def username=(value)
@username = value
end
正如您所看到的,它与"替代品#34;相同。你提到过。
编辑使用访问器(即调用attr_accessor / reader / etc定义的函数)比其他形式的访问快得多。评论中有一些链接,详细说明了这一点。
答案 1 :(得分:1)
一个例子是当你需要只读属性时。像这样:
class ProjectProcessor
attr_reader :project # attr_reader, not attr_accessor
def initialize(project)
@project = project
end
# more code
end
由于attr_reader
没有定义一个setter方法,所以一旦创建了处理器,外部代码就不能改变project
(无论如何都不方便)。
答案 2 :(得分:1)
由于第2行中的逗号,两种情况完全相同:逗号表示您将两个参数传递给attr_accessor
,而不是一个。
第二个论点是什么?嗯,这是逗号后面的内容,当然是def
表达式。在旧版本的Ruby中,方法定义表达式的返回值是实现定义的(在某些实现中它返回nil
,在某些已编译的方法字节码中),但在当前版本的Ruby中,返回值为def
表达式标准化为Symbol
,表示方法的名称为def
。因此,在这种情况下,def
表达式的计算结果为:initialize
。
现在,因为Ruby是一种严格的语言,所以在传递参数之前对它们进行评估,这意味着def initialize
首先被评估为 ,它定义了一个initialize
方法。参数。
然而,在此之后,attr_accessor
会立即使用两个参数:username
和:initialize
进行调用,因此attr_accessor
将创建四种方法:{{1} }},username=
,username
和initialize=
,因此使用没有参数的方法覆盖我们刚刚定义的方法。
这就是为什么两个示例是相同的:虽然两个initialize
方法不同最初,但它们立即会被相同的方法覆盖。
(我想,从技术上讲,你可以观察到差异,如果你设法在正好的另一个线程中调用initialize
,直接在第一次定义之后时间,但在它被覆盖之前。但这是一个非常小的窗口。)
请注意,您发布的代码会产生相应的警告:
initialize
你可以在行号中看到严格评估参数的效果:它抱怨该方法在第2行被覆盖但先前在第3行定义,实际上是在第2行之后但是被评估之前它。
这显示了我一遍又一遍地写的内容:你应该读取警告。他们被放在那里是有原因的。