尝试学习/理解Ruby的setter和getter方法

47

我刚开始学习编程,决定尝试Ruby。但是我的讲师在谈论setter和getter方法时,我感到困惑。以下是示例:

class Human
  def noise=(noise)
    @noise = noise
  end

  def noise
    @noise
  end
end

从这里,类被实例化了,然后我可以输出这个:

man = Human.new
man.noise=("Howdie!")
puts man.noise

这将导致Howdie!

现在让我困惑的是,教练说如果没有getter方法(两个方法中的第二个方法),就无法与实例变量@noise交互。

但是当我删除getter方法时,仍然可以访问@noise,参见下面的示例:

class Human
  def noise=(noise)
    @noise = noise
  end
end

man = Human.new
puts man.noise=("Howdie!")

这与使用getter方法时相同。

所以现在我有点困惑。为什么需要getter?教练说的没有使用它无法访问实例变量是什么意思?他可能在使用旧版Ruby吗?

非常感谢您的帮助。


1
你真的能够访问@noise吗?还是你所看到的只是你调用的函数的副作用... - LVB
4个回答

35

即使没有getter方法,您也可以从属于该实例的其他方法与该实例变量交互:

def noise=(noise)
  @noise = noise
end

def last_noise
  @noise
end
不需要定义与方法同名的getter方法,两者没有任何联系。getter方法用于以简短的语法"获取"实例变量的值。
在你的示例中发生的是,你正在初始化一个新对象(Human.new),然后使用一个方法(noise=,是的,方法名称包含=符号)来定义一个实例变量(也就是一个仅对该实例可见的变量),最后通过另一个方法调用来检索该实例变量的值。
实际上,你甚至可以使用instance_variable_get方法来获取实例变量而无需定义任何getter方法:
man = Human.new
man.noise = "Howdie"
man.instance_variable_get("@noise")
这将返回"Howdie",即使没有定义getter方法。 而且,我不认为他在使用旧版本的Ruby。

2
+1 Ryan。像往常一样,您的专业知识非常出色,我之前不知道instance_variable_get! - Michael Durrant
嘿,那不会覆盖attr_protected吧? - Michael Durrant
回答了自己的问题:- API说:“在该宏中命名的属性受到批量分配的保护”。 - Michael Durrant
关于attr_accessible和attr_accessible的aame,请参见http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000350,对于http://ar.rubyonrails.org/classes/ActiveRecord/Base.html#M000351则不会防止直接设置器。 - Michael Durrant
ok attr_readonly(*attributes)列出的属性可以在新记录中设置,但在数据库更新后将被忽略。现在看起来更像了! - Michael Durrant
显示剩余2条评论

15

代码行

puts man.noise=("Howdie!")

该行代码不使用getter方法,因此不需要定义getter方法即可正常工作。那行代码只使用了setter方法。setter方法的返回值自动等于等号右侧的值,因此"Howdie!"被传递给puts

这行代码:

puts man.noise

使用了Getter方法,如果您删除Getter方法,则无法正常工作。


所以我想问的是,为什么要使用getter和setter方法?为什么不只使用setter方法(或基本方法让我传递一个值到方法),然后在那个方法上加上“return”呢?我并不是在建议更好的做法,我真的很想知道为什么?我不理解。 - Nathan
1
你需要getter方法,因为有时候你想获取变量的值而不改变它。setter方法总是将值设置为某个值,因此无法使用setter方法获取值而不修改它! - David Grayson
只有在希望变量可以被类外的方法读取时,才需要使用getter方法。如果你只想从类中的方法读取变量,可以直接使用@noise而不是getter方法。 - David Grayson
这个答案对我来说是最好的。getter和setter是答案的关键。如果我理解正确,只有在类内部存在默认值时,getter方法才有帮助。如果没有默认值,我们就不需要它。 - kouty
如果一个人写了 man.noise ||= value,那么getter和setter方法都需要被定义。我想这就是你所说的。 - David Grayson

5
肯定地说,这两种方式都会返回一个值,但它们的行为是不同的。
假设已经有了成员变量 @a
使用getter获取@a的当前值,而不对其进行修改。
使用setter修改@a,并获取其新值作为返回值。
在考虑setter的行为时,请注意:
  1. 使用setter无法获取@a的旧值,因为它已经被覆盖了。

  2. setter返回的实际上是在调用setter之前就已知的值。


直到我读了别人的回复,现在我明白了(并且思考了一段时间),我认为你的答案有助于突出我所提出的问题。如果您改进您的答案以减少像我这样的新手阅读其他人的回答,那么我想选择您的答案。 - Nathan

1

可能对于getter和setter的关注是因为其他一些语言允许您直接访问类变量。Python:

class k:
    i = 100

print k.i # 100
k.i = 200
print k.i # 200

相比之下,Ruby将所有变量完全私有化到类中,并仅通过访问器方法公开它们。
在您的示例中,如果您删除getter,确实可以通过setter与变量交互(即:更改它),但是当您需要时,您无法以常规方式获取它。

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