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方法的这种“反私人”属性如何合理?
答案 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决定无接收分配指定本地。