Ruby 有一个回退机制。考虑这个例子:
class SomeClass
def my_method
"my method"
end
def other_method_with_local_variable
my_method = "lala"
puts my_method
end
def other_method
my_method
end
end
现在让我们在控制台中测试这些方法:
1.9.3p448 :016 > SomeClass.new.other_method # outputs instance method value, because there were none local variables inside the method and it falled back to instance scope
=> "my method"
1.9.3p448 :017 > SomeClass.new.other_method_with_local_variable # outputs "lala" because it's the value of lcoal variable
lala
不理解这个概念的人经常过度使用self
,这让经验丰富的 Ruby 开发人员眼睛流血 :D
UPD
您似乎将实例方法与实例变量混淆了。如果您来自其他 OOP 语言,则与实例 var 最接近的类比将是私有属性/属性。当然,在 Ruby 中,无论如何都可以通过一些变通方法来实现它。例子:
class Person
def initialize(name)
@name = name
end
end
p = Person.new("John")
# => #<Person:0x007fbe910cc680 @name="John">
p.name #produces error, because object doesn't have such method, only a private property
#NoMethodError: undefined method `name' for #<Person:0x007fbe910cc680 @name="John">
p.instance_variables # we can always get list of instance variables
# => [:@name]
p.instance_variable_get(:@name) # access them
# => "John"
p.instance_variable_set(:@name, "Ben") # and set them
# => "Ben"
p
# <Person:0x007fbe910cc680 @name="Ben">
以这种方式弄乱对象内部被认为是一个非常糟糕的习惯,我们应该使用类的公共接口。在许多语言中,人们通常开始为此类属性定义访问器/设置器。set_name
在类中看到诸如,之类的方法是很常见的get_name
。Ruby 语法允许并且约定建议这样做:
class Person
def initialize(name)
@name = name
end
def name
@name
end
def name=(new_name)
@name = new_name
end
end
1.9.3p448 :015 > p = Person.new("John")
# => #<Person:0x007f8b8b20ad28 @name="John">
1.9.3p448 :016 > p.name
# => "John"
1.9.3p448 :017 > p.name = "Ben"
# => "Ben"
1.9.3p448 :018 > p
# => #<Person:0x007f8b8b20ad28 @name="Ben">
在 Your 对象中定义它们是很常见的,因此 Ruby 提供了快捷方式。我们可以像这样重构我们的类:
class Person
attr_accessor :name
def initialize(name)
@name = name
end
end
1.9.3p448 :009 > p = Person.new("John")
# => #<Person:0x007f8091233a48 @name="John">
1.9.3p448 :010 > p.name
# => "John"
1.9.3p448 :011 > p.name = "Ben"
# => "Ben"
1.9.3p448 :012 > p
# => #<Person:0x007f8091233a48 @name="Ben">
我们实际上可以验证它attr_accessor
是否完全相同:
1.9.3p448 :013 > Person.instance_methods.grep(/^name=?/)
# => [:name, :name=]
现在回到 ActiveRecord。它以相同的方式为您的列定义方法,因此对于name
列,它将定义方法name
和name=
. 不同之处在于 AR 对象要复杂得多,并且那些调用读/写属性所做的事情不仅仅是设置实例变量@name
。
如果您已经理解了变量/方法的范围概念,那么您应该清楚何时使用self
以及这些方法调用的实际作用。
小总结:
- 实例变量不是方法,它们可以称为对象的私有属性
- 我们定义访问器方法来访问实例var,通常使用attr_accessor、attr_reader(只读属性)方法
- 当访问一些变量时,Ruby 在本地范围内搜索变量,如果没有找到,Ruby 会认为它是实例方法并调用它
self
self
写入 accessor() 时需要明确说明self.name =
,否则 Ruby 将其视为局部变量的创建。如果您在本地范围内有一个同名的变量,您还需要self
在阅读时使用,但这是一种非常糟糕的做法,我怀疑您会遇到这种情况。