【问题标题】:instance and class variables in rails controllerRails 控制器中的实例和类变量
【发布时间】:2014-02-14 04:20:04
【问题描述】:

我是 Rails 和 Ruby 的新手。我正在研究类和实例变量的概念。我理解其中的区别,但是当我在 rails 中使用控制器进行尝试时,我感到很困惑。我所做的是在类方法之外声明了一个类和实例变量:

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 返回一个 nil 值。 @@world 的值是“Hello World”。那么这里发生了什么?它们不是在同一个类中定义的吗?

【问题讨论】:

标签: ruby-on-rails ruby


【解决方案1】:

类也是 Ruby 中的对象,因此它们可以拥有自己的实例变量,称为 类实例变量

  • @@world 是一个类变量
  • @insworld 是一个类实例变量
  • #index 是一个实例方法

当您尝试在#index 中访问@insworld 时,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

【讨论】:

    【解决方案2】:

    当您声明 @instworld 时,您在 BooksController 类中(即 self 将返回 BooksController。在 ruby​​ 中奇怪的是类也是对象(类 Class 的实例)因此您实际上声明实例变量@instworld 用于类Classm 的这个特定实例,而不是BooksController 的实例。

    你可以通过声明类方法很容易地检查它:

    class A
      # self here returns class A
      @variable = 'class instance variable'
      @@variable = 'class variable'
    
      def initalize
        # self here returns the instance
        @variable = 'instance variable'
      end
    
      def self.test_me
        # self here returns class A
        @variable
      end
    
      def test_me
        # self returns the instance
        @variable
      end
    
      #class variable is accessible by both class and instance 
      def test_me2
        @@variable
      end
    
      def self.test_me2
        @@variable
      end
    end
    
    A.test_me       #=> 'class instance variable'
    A.new.test_me   #=> 'instance variable'
    A.test_me2      #=> 'class variable'
    A.new.test_me2  #=> 'class variable'
    

    【讨论】:

      【解决方案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 的原因:该变量在该范围内不存在。

      要获取实例级变量,请在方法/操作中设置它们。

      【讨论】:

        【解决方案4】:

        Instance 变量的作用域是从action 到view,它们在任何动作发生时启动,在动作结束时销毁。

        【讨论】:

        • 那么你如何拥有一个真正的类实例变量,一个在所有动作中持续存在的变量? @艾哈迈德侯赛因
        【解决方案5】:

        在类中而不是在构造函数或任何实例方法中声明@insworld 会将@insworld 的作用域设置为类本身的实例。

        BooksController.instance_variable_get(:'@insworld')
        

        如果您需要在索引方法中访问变量,请考虑在方法中定义它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多