我是铁杆和红宝石的新手。我正在研究类和实例变量的概念。我理解了差异但是当我在轨道中使用控制器尝试它时让我感到困惑。我所做的是在类方法之外声明了一个类和实例变量:
class BooksController < ApplicationController
# GET /books
# GET /books.json
@@world = "Hello World"
@insworld = "my hobby"
def index
@books = Book.all
binding.pry
respond_to do |format|
format.html # index.html.erb
format.json { render json: @books }
end
end
end
我的印象是@insworld具有“我的爱好”的价值,但是当我在index method
内部时,当我试图检查@insworld的值时,@ insworld返回了一个零值。 @@ world具有“Hello World”的价值。那么这里发生了什么?它们不是在同一个类中定义的吗?
答案 0 :(得分:46)
类也是Ruby中的对象,因此它们可以拥有自己的实例变量,这些变量称为类实例变量。
@@world
是类变量 @insworld
是类实例变量 #index
是一种实例方法当您尝试访问@insworld
中的#index
时,Ruby会在A
对象(意为A.new
)中搜索实例变量,因为#index
是一个实例方法。
但是您将@insworld
定义为类实例变量,这意味着它是在类对象本身中定义的(意思是A
)。
以下代码演示了:
class Hi
@@a = 1 # class variable
@b = 2 # class instance variable
def initialize
@c = 3 # instance variable
end
def test # instance method, works on objects of class Hi
puts @@a # => 1
puts @b # => nil, there is no instance variable @b
puts @c # => 3 # we defined this instance variable in the initializer
end
end
Hi.class_variables # => @@a
Hi.instance_variables # => @b
Hi.new.instance_variables # => @c
# Hi is an object of class Class
# Hi.new is an object of class Hi
请记住,如果不存在,所有实例变量都会返回nil
。
答案 1 :(得分:6)
当您声明@instworld
时,您在BooksController类中(即self
将返回BooksController
。在ruby中,奇怪的是类也是对象(类{{1}的实例因此,您实际上为类Class
的此特定实例声明了实例变量@instworld
,而不是Class
的实例。
您可以通过声明类方法来轻松检查它:
BooksController
答案 2 :(得分:3)
在方法之外声明实例变量时,可能无法获得所需的结果。它是一个实例变量,是的,但它属于类本身(它是类Class
的一个实例)。
class Foo
@myvar = "class-level"
def initialize
@myvar = 'instance-level'
end
end
f = Foo.new
f.class.instance_variable_get(:@myvar) # => "class-level"
f.instance_variable_get(:@myvar) # => "instance-level"
f.instance_variable_get(:@myvar2) # => nil
如果您尝试获取未初始化的ivar的值,它将评估为nil
。这就是你在实验中得到nil
的原因:该范围内的变量不存在。
要获取实例级变量,请在方法/操作中设置它们。
答案 3 :(得分:2)
实例变量的范围是从动作到视图,它们在任何动作发生时启动,并在动作结束时销毁。
答案 4 :(得分:1)
在类中声明@insworld而不在构造函数或任何实例方法中声明@insworld作用于类本身的实例。
BooksController.instance_variable_get(:'@insworld')
如果需要访问index方法中的变量,请考虑在方法中定义它。