《反私》setter 方法的属性 [英] "Anti-private" property of setter method
问题描述
Getter 方法可以在没有显式接收器的情况下使用,除非存在同名的局部变量:
Getter methods can be used without an explicit receiver unless there is a local variable with the same name:
class A; attr_reader :foo end
A.new.instance_eval do
@foo = :foo
p foo
end
# => :foo
当存在同名的局部变量时,这将不成立,因为在有歧义时,解释为局部变量比作为方法调用具有优先权.
This will not hold when there is a local variable with the same name, due to the principle that interpretation as a local variable has priority than as a method call whenever there is an ambiguity.
class A; attr_reader :foo end
A.new.instance_eval do
foo = :bar
@foo = :foo
p foo
end
# => :bar
然而,setter 方法不能在没有显式接收器的情况下使用,即使在所讨论的表达式之前没有分配同名的局部变量:
However, setter methods cannot be used without an explicit receiver even when a local variable with the same name is not assigned prior to the expression in question:
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 方法的这种反私有"属性如何证明?
How is this "anti-private" property of setter method justified?
推荐答案
如果 ruby 将你最后一条语句中的赋值解释为对 self
的赋值,你将无法设置局部变量.
If ruby interpreted your assignment in your last statement as an assignment to self
, you would have no way left to set a local variable.
解释器处理的方式没有歧义:没有 self
的赋值总是局部变量,对 self 的赋值总是试图在对象上使用 writer.
The way it is leaves no ambiguity for the interpreter to deal with: assignments without self
are always local variables, assignments to self are always trying to use a writer on the object.
解释器必须查找上下文编写器方法并通过编写器分配它(如果有),这几乎肯定会对性能产生负面影响
The interpreter would have to look up the contexts writer methods and assign it via the writer if there is one, which almost certainly would have a negative impact on performance
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,这是一项相当愚蠢的任务.
It would also leave the programmer with the rather stupid task to find out every setter method of the context he's in before assigning local variables to make absolutely sure he does not unintentionally use a 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 methods cannot be used without an explicit receiver even when a local variable with the same name is not assigned prior to the expression in question:
如果反过来,则不能在所讨论的表达式之前分配具有相同名称的局部变量,因为分配将使用 setter(如本答案的第一段所述)
If it were the other way around, you could not assign a local variable with the same name prior to the expression in question, because the assignment would use the setter (as stated in the first paragraph of this answer)
关于属性方法使用的实现/对变量的访问:Getter 和 Setter 使用实例变量.所以,例如 attr_accessor
实际上定义了这样的东西:
Concerning the implementation / the access to variables the attribute methods use: Getter and Setters work with instance variables. So, for example attr_accessor
actually defines something like this:
def foo
@foo
end
def foo=(data)
@foo = data
end
那么,属性被声明为实例变量而不是局部变量,为什么程序员可以像局部变量一样分配它?这会留下错误的印象,即您可以通过分配局部变量来分配对象的实例变量.如果 ruby 这样做,几乎肯定会导致严重的内存管理问题.简而言之:foo = 'bar'
和 @foo = 'bar'
不一样,正是因为 attr
方法使用@foo = 'bar'
,你不能通过使用 foo = 'bar'
来调用它们.
So, the attribute is declared as a instance variable and not as a local variable, why should the programmer be able to assign it like a local variable? This would leave the wrong impression that you could assign instance variables of an object via assigning local variables. If ruby would do this, it would almost certainly lead to a serious memory management problem. To make it short: foo = 'bar'
and @foo = 'bar'
are not the same, and exactly because the attr
methods use @foo = 'bar'
, you can not call them via using foo = 'bar'
.
这篇关于《反私》setter 方法的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!