为了回答你的“如果它们是变量”和“作用域”问题,更简单的回答是访问符号与实例变量无关,即使这听起来有些异端邪说。它们不指向实例变量。访问器只定义getter和setter方法。在Object#instance_variables下,Pickaxe(*)指出:请注意,仅定义访问器并不会创建相应的实例变量。
在Ruby中,变量在赋值之前不存在。以下代码演示了这一点。
class MyClass
attr_accessor :name
attr_reader :book
end
obj = MyClass.new
print '1) obj.instance_variables : '; p obj.instance_variables
print '2) obj.name : '; p obj.name
obj.name = 'xyz'
print '3) obj.instance_variables : '; p obj.instance_variables
print '4) obj.name : '; p obj.name
print '5) obj.book : '; p obj.book
class MyClass
def initialize(p_book)
@book = p_book
end
end
obj = MyClass.new('The Pickaxe')
print '6) [new] obj.book : '; p obj.book
class MyClass
method_name = 'title'
attr_accessor method_name
end
obj.title = 'Programming Ruby'
print '7) obj.instance_variables : '; p obj.instance_variables
print '8) obj.title : '; p obj.title
输出:
$ ruby -w t.rb
1) obj.instance_variables : []
2) obj.name : nil
3) obj.instance_variables : ["@name"]
4) obj.name : "xyz"
5) obj.book : nil
6) [new] obj.book : "The Pickaxe"
7) obj.instance_variables : ["@title", "@book"]
8) obj.title : "Programming Ruby"
1) 空数组:访问器未定义实例变量
2) 请求实例变量@name的答案为nil:它不存在
3) 分配一个值已创建实例变量。
请注意,name =
是使用带参数的setter作为普通方法的语法糖:obj.name=('xyz')
4) getter方法name
回答@name的值
5) getter方法book
回答nil,因为实例变量@book不存在。定义访问器attr_reader :book
未定义相应的实例变量
6) getter方法book
回答在initialize
中分配的值,由第21行的new
调用。实例变量@book已由@book = p_book
创建
第26行)我一直认为访问器只接受符号。我发现变量是可能的,但兴趣有限。
7) setter方法title=
已创建@title。这也表明实例变量属于单个对象。我们经常认为它们属于类的所有实例,就像其他语言一样。在这种情况下,@name仅属于第6行创建的对象。
8) getter方法title
回答@title的值
class MyClass
def title
@book + ' (cheating !)'
end
end
print '9) obj.title : '; p obj.title
输出:
t.rb:34: warning: method redefined; discarding old title
9) obj.title : "The Pickaxe (cheating !)"
9) 当然,访问器符号和相应的实例变量之间存在紧密的关联,因为在后台,Ruby创建了引用同名实例变量的方法。您可以定义自己的getter并欺骗它。
请注意,除了类变量(@@var,有些人认为它们像全局变量一样丑陋)外,类还可以具有实例变量。我称它们为类实例变量:)。
class MyClass
:Ruby分配一个新的类Class的实例,定义一个常量MyClass,并将新实例分配给该常量。因此,MyClass是一个普通对象(Class的实例),因此可以具有实例变量。
if RUBY_VERSION[0..2] == '1.8'
class Object
def singleton_class
class << self
self
end
end
end
end
class MyClass
singleton_class.instance_eval do
attr_accessor :counter
end
@counter = 0
def initialize(p_book)
@book = p_book
self.class.counter += 1
end
end
print '10) MyClass.singleton_methods : '; p MyClass.singleton_methods
print '11) MyClass.instance_variables : '; p MyClass.instance_variables
obj = MyClass.new('Ruby')
print '12) [new] obj.book ', MyClass.counter, ': '; p obj.book
obj = MyClass.new('Metaprogramming')
print '13) [new] obj.book ', MyClass.counter, ': '; p obj.book
输出:
t.rb:55: warning: method redefined; discarding old initialize
10) MyClass.singleton_methods : ["counter", "counter="]
11) MyClass.instance_variables : ["@counter"]
12) [new] obj.book 1: "Ruby"
13) [new] obj.book 2: "Metaprogramming"
关于单例模式,可以在这里了解更多:什么是def `self.function`名称?
(*) http://pragprog.com/book/ruby3/programming-ruby-1-9