setter方法的“反私人”属性

除非存在具有相同名称的局部变量,否则可以在没有显式接收器的情况下使用Getter方法:

class A; attr_reader :foo end A.new.instance_eval do @foo = :foo p foo end # => :foo 

当存在具有相同名称的局部变量时,这将不成立,因为当存在歧义时,解释为局部变量具有优先级而不是方法调用。

 class A; attr_reader :foo end A.new.instance_eval do foo = :bar @foo = :foo p foo end # => :bar 

但是,即使没有在相关表达式之前分配具有相同名称的局部变量,也不能在没有显式接收器的情况下使用setter方法:

 class A; attr_writer :foo end A.new.instance_eval do foo = :foo #  nil 

这个setter方法的“反私人”属性如何合理?

如果ruby将您在上一个语句中的赋值解释为对self的赋值,那么您将无法设置局部变量。

它的方式不会让解释器处理不明确的问题:没有self赋值总是局部变量,对self的赋值总是试图在对象上使用writer。

如果是相反的方式

解释器必须查找上下文编写器方法并通过编写器分配它(如果有),这几乎肯定会对性能产生负面影响

 class A attr_writer :foo end A.new.instance_eval do # for each of these assignments, the interpreter has to look up if there's # a writer method defined foo = 'bar' bar = 'baz' fib = 'buz' end 

它还会给程序员带来相当愚蠢的任务,在分配局部变量之前找出他所处的上下文的每个setter方法,以确保他不会无意中使用setter。

 class C attr_writer :something end class B < C attr_writer :foo end class A < B attr_writer :bar end A.new.instance_eval something = 'something' #you just (almost certainly with no intention) assigned a value to an attribute end 

另外,你的问题是:

即使没有在相关表达式之前分配具有相同名称的局部变量,也不能在没有显式接收器的情况下使用setter方法:

如果是相反的方法,则无法在相关表达式之前分配具有相同名称的局部变量,因为赋值将使用setter(如本答案第一段所述)

关于变量的实现/访问,属性方法使用:Getter和Setter使用实例变量。 所以,例如attr_accessor实际上定义了这样的东西:

  def foo @foo end def foo=(data) @foo = data end 

因此,该属性被声明为实例变量而不是局部变量,为什么程序员能够像局部变量一样分配它? 这会给人留下错误的印象,即您可以通过分配局部变量来分配对象的实例变量。 如果ruby会这样做,那几乎肯定会导致严重的内存管理问题。 简而言之: foo = 'bar'@foo = 'bar'不一样,而且正因为attr方法使用@foo = 'bar' ,你不能通过使用foo = 'bar'来调用它们。

我认为@sawa最终澄清了“反私人”的含义。

sawa的评论:

私有意味着它不能有明确的接收者。 否定的是它可能有一个明确的接收器,这不是我提到的。 我提到的情况是一个方法必须有一个明确的接收器,这是对私人的。 我觉得你很困惑。

我很困惑,显然与所有其他评论者一起,因为“反私人”和“反对私人”不是标准术语,其含义也不是很明显。

我认为原始问题的含义是:“ 由于setter需要一个明确的接收者, private禁止明确的接收者,我怎么能称之为private setter? ”换句话说,“反私人”意味着“ private不相容 ”,或者“ private无法使用 ”。

JörgWMittag雄辩地解释了正常private规则的例外情况 。 基本上,即使它们是私有的,也可以在self上调用setter,因为没有其他方法可以调用它们(除非你使用繁琐的send )。

因此,setter对显式接收器的要求与private的setter完全兼容,只是因为规则的例外。

Beat Richartz的答案已经非常完整,但我想强调一点关于你提出的行为。

在您的问题中,您有以下示例代码:

 class A; attr_writer :foo end A.new.instance_eval do foo = :foo # <= No local variable named `foo` has been assigned before this point p @foo end 

您建议赋值调用setter方法。 并且如果尚未分配局部变量foo则希望发生这种情况。

但是在那之前你会使用什么语法来分配本地?

如果无接收器赋值foo = :foo意味着调用setter(当它存在时),你需要另一种语法结构来表示“ 分配这个局部变量,忽略是否有一个setter ”。

老实说,如果你有一个,我想听听你的提议(我不是讽刺)。 听取有关语言设计的其他观点会很有趣。

我不是说你的方式必然会比现在的ruby方式“更糟糕”。 但在某些时候,语言设计师必须决定模糊情境的默认行为,Matz决定无接收器分配指定本地。