0

除非有同名的局部变量,否则可以在没有显式接收器的情况下使用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  # <= No local variable named `foo` has been assigned before this point
  p @foo
end
# => nil

setter 方法的这种“反私有”属性如何证明是合理的?

4

3 回答 3

5

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

它的方式让解释器处理起来没有歧义:没有self的赋值总是局部变量,对 self 的赋值总是试图在对象上使用编写器。


如果反过来

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

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方法 use @foo = 'bar',您不能通过 using 调用它们foo = 'bar'

于 2013-01-30T12:15:26.800 回答
1

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

萨瓦评论:

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

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

我认为原始问题的意思是:“既然setter需要一个显式的接收器,并且private禁止显式的接收器,我怎么能调用一个privatesetter呢? ”换句话说,“anti-private”的意思是“不兼容private”,或者“无法使用private” ”。

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

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

于 2013-11-01T21:09:54.283 回答
-1

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 决定无接收者分配分配本地。

于 2013-11-01T18:25:39.807 回答