setter方法的“反私人”属性

时间:2013-01-30 12:07:18

标签: ruby setter accessor

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

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方法的这种“反私人”属性如何合理?

3 个答案:

答案 0 :(得分:5)

如果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

此外,您的问题是:

  如果没有明确的接收器,即使是a,也不能使用

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'来调用它们

答案 1 :(得分:1)

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

萨瓦的评论:

  

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

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

我认为原始问题的含义是:“由于setter需要显式接收器,private禁止显式接收器,如何调用private setter? “换句话说,”反私有“的意思是”private “不兼容,或”无法使用private “。

JörgWMittag雄辩地解释了exception to the normal private rules。基本上,即使它们是私有的,也可以在self上调用setter,因为没有其他方法可以调用它们(除非你使用繁琐的send)。

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

答案 2 :(得分:-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 ”。

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

我不是说你的方式肯定比现在的红宝石方式“更糟糕”。但在某些时候,语言设计师必须为不明确的情况决定默认行为,Matz决定无接收分配指定本地。