【问题标题】:"Anti-private" property of setter methodsetter 方法的“反私有”属性
【发布时间】:2013-01-30 12:07:17
【问题描述】:

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 方法的这种“反私有”属性如何证明?

【问题讨论】:

  • 这是怎么回事?我不明白。设置器不是私有方法。
  • @m_x 他们不是。我在写反私人。不是私人的。
  • 为什么二传手是私有的? setter 的重点是将字段公开给公共接口。或者我不明白你所说的“反私人”是什么意思
  • @sawa private 在 ruby​​ 中定义了曝光,所以 m_x 在这个问题上给你打电话是绝对正确的。可能不清楚您所说的反私有是什么意思,即使我理解您的意思是当变量在其(用您的话是私有的)范围内定义时,对象不会隐式使用设置器,但没有必要对此粗鲁.
  • 是的,我知道私有在 ruby​​ 中的含义。您的问题最好改写为“为什么二传手在 ruby​​ 中需要一个明确的接收者?”。我认为@BeatRichards 解释得很好。作为旁注,AFAIK“反隐私”是你的发明,在官方文档中找不到,所以请不要再看不起那些诚实地试图理解你的问题并帮助你的人。

标签: ruby setter accessor


【解决方案1】:

如果 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 方法使用 @foo = 'bar',所以您不能通过使用 foo = 'bar' 来调用它们。

【讨论】:

  • 它实际上不是将其解释为对self的赋值,而是作为局部变量。
  • 这与你所说的相反。另一方面,如果确实是你所说的,那么你只是在重复这个问题。
  • @sawa 我澄清了我的回答,希望对您有所帮助。
  • @sawa 也许你错过了答案第一句话中的“如果”?
  • 我无法完全解析您的第三段,但您的第三和第四段似乎从设计的角度回答了我的问题。这是我问题的一半答案,但我期待另一半:从实施的角度来看。
【解决方案2】:

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

sawa 的评论:

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

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

我认为原问题的意思是:“既然setter需要一个显式的receiver,而private禁止显式receiver,我怎么能调用privatesetter呢?”换句话说, “anti-private”是指“private不兼容”,或“private不兼容”。

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

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

【讨论】:

  • @sawa,我不知道你是否是反对者,但你介意确认或否认我是否准确理解你的问题吗?我仍然想深入了解您的问题。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-27
    • 2018-07-16
    相关资源
    最近更新 更多