理解Ruby类实例变量

8

可能是重复问题:
为什么Ruby中的setter需要在类中添加“self.”限定符?

有人能解释一下以下内容之间的区别,以及为什么它不像我们期望的那样:

# version #1
class User
  def initialize(name, age)
    @name = name
    @age = age
  end
end

#version #2
class User
  attr_accessor :name, :age
  def initialize(name, age)
    @name = name
    @age = age
  end
end

#version #3
class User
  attr_accessor :name, :age
  def initialize(name, age)
    self.name = name
    self.age = age
  end
end

据我所知,在方法中,当你进行赋值时,必须使用 self 关键字。那么为什么在 initialize 方法中不能使用它呢?或者说可以吗?我尝试使用它,但似乎并没有按预期工作,我只是对何时以及更重要的是为什么要使用哪种技术感到困惑。

我真的希望有人能够彻底澄清这个问题 :)


1
你能否更具体地说明哪个出错了,以及你期望的输出是什么? - Gareth
1
这与类实例变量有什么关系? - Joshua Cheek
2个回答

16

第一种版本:构造函数创建了两个实例变量@name@age。这两个变量是私有的(所有的Ruby实例变量都是私有的),所以你无法在类外面访问它们。

第二种版本:与第一种版本完全相同,只是你还定义了两个变量的getter和setter方法。attr_accessor会为每个参数创建两个方法,允许你使用相同名称的实例变量来获取/设置实例变量的值。

第三种版本:与第二种版本完全相同,只是在构造函数中你不是直接设置实例变量,而是调用User#name=User#age=方法来设置实例变量的值。

要澄清直接设置实例变量和调用setter方法之间的区别,请考虑以下示例:

user = User.new "Rob", 26
user.name = "Joe"

在这里,你实际上并没有直接设置user@name变量,而是调用了一个名为name=的方法来为你设置@name的值。当你在版本#2和#3中调用attr_accessor时,它会为你定义该方法。但是,在版本#1中,你没有调用attr_accessor,因此上面的示例将无效,因为没有name=方法。


在Java中,self和this是相同的吗? - Blankman
是的,self是指向“它自己”的引用,就像this一样。 - DGM

0

在方法中,您不需要使用self; 对于实例变量,应直接使用@进行分配,例如版本1或2。self不像Python中的那样使用;它被用于声明类方法(如C ++中的静态函数)。


是否应该直接分配实例变量是模糊的。我在这个问题上两边都很强烈,不认为你可以说你应该直接分配它,因为使用setter有许多真正的好处。我认为唯一能够证明直接分配ivars值是值得的论点是当你没有setter时(使用attr_reader而不是attr_accessor)。 - Joshua Cheek
嗯...我认为在类方法中直接分配ivars更有意义,因为ivars应该是类的实现层的一部分,而这正是类方法使用的层(换句话说,我认为ivars应该在类方法中引用,出于与它们不应该在类方法之外的相同原因 - 将类的内部,“实现”,“私有”层与外部,“公共”层分离)。然而,我承认,在任何给定的上下文中,其中一个可能在语义上比另一个更有意义。 - Aleksander
在这种情况下,我有时会在 private 关键字后面加上 attr_accessor。这样做不太美观,但我可以获得使用setter的好处——它们对类的好处不如对实例来的大,因为类不太可能继承功能,而且可变类通常不是一个好主意,因为它们是单例)。 - Joshua Cheek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接