Ruby自己。 vs @ in initialize

时间:2015-12-17 18:50:58

标签: ruby

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

3 个答案:

答案 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=usernameinitialize=,因此使用没有参数的方法覆盖我们刚刚定义的方法。

这就是为什么两个示例是相同的:虽然两个initialize方法不同最初,但它们立即会被相同的方法覆盖。

(我想,从技术上讲,你可以观察到差异,如果你设法在正好的另一个线程中调用initialize,直接在第一次定义之后时间,但在它被覆盖之前。但这是一个非常小的窗口。)

请注意,您发布的代码会产生相应的警告:

initialize

你可以在行号中看到严格评估参数的效果:它抱怨该方法在第2行被覆盖但先前在第3行定义,实际上是在第2行之后但是被评估之前它。

这显示了我一遍又一遍地写的内容:你应该读取警告。他们被放在那里是有原因的。