class Hello
@hello = "hello"
    def display
        puts @hello
    end
end

h = Hello.new
h.display

我在上面创建了这个类。它不打印任何东西。我认为在类声明期间设置了实例变量@hello。但是当我调用display方法时输出为'nil'。这样做的正确方法是什么?

有帮助吗?

解决方案

首次学习Ruby时,ruby中的实例变量可能有点令人困惑,特别是如果你习惯于另一种像Java这样的OO语言。

您不能简单地声明实例变量。

除了带有@符号前缀的符号之外,了解ruby中实例变量的最重要的事情之一就是它们在第一次被分配到时就会变得生动。

class Hello
  def create_some_state
    @hello = "hello"
  end
end

h = Hello.new
p h.instance_variables 

h.create_some_state
p h.instance_variables

# Output
[]
["@hello"]

您可以使用 Object#instance_variables 方法列出对象的所有实例变量。

你通常“宣布”并初始化initialize方法中的所有实例变量。另一种清楚地记录应该公开可用的实例变量的方法是使用模块方法 attr_accessor (读/写), attr_writer (写)和 attr_reader (阅读)。这些方法将为列出的实例变量合成不同的访问器方法。

class Hello
  attr_accessor :hello
end

h = Hello.new
p h.instance_variables 

h.hello = "hello"
p h.instance_variables

# Output
[]
["@hello"]

实例变量仍未创建,直到它被分配给使用合成的 Hello#hello = 方法。

另一个重要问题,如kch所描述的,是你在声明一个类时需要注意活动的不同上下文。声明类时,最外层作用域中的默认接收器(self)将是表示类本身的对象。因此,当您在类级别分配 @hello 时,您的代码将首先创建一个类实例变量。

内部方法 self 将是调用该方法的对象,因此您尝试使用名称 @hello 打印实例变量的值。对象,它不存在(请注意,它非常合法地读取非现有的实例变量)。

其他提示

您需要添加 initialize 方法:

class Hello
    def initialize
        @hello = "hello"
    end
    def display
        puts @hello
    end
end

h = Hello.new
h.display

代码中的第一个 @hello 称为类实例变量。

它是类对象的实例变量,常量 Hello 指向该变量。 (它是类 Class 的实例。)

从技术上讲,当你在 class 范围内时, self 被设置为当前类的对象, @variables 属于您当前的 self 。男孩我很蠢地解释这些事情。

你可以通过观看这一系列的5美元 - 来自实用程序员的每个截屏视频

(或者你可以在这里要求澄清,我会尝试更新。)

书中有一个清晰的描述“红宝石编程语言”,阅读它会非常有帮助。我把它贴在这里(来自第7.1.16章):

  

在类定义中但在...之外使用的实例变量   实例方法定义是类实例变量

class Point
    # Initialize our class instance variables in the class definition itself
    @n = 0              # How many points have been created
    @totalX = 0         # The sum of all X coordinates
    @totalY = 0         # The sum of all Y coordinates

    def initialize(x,y) # Initialize method 
      @x,@y = x, y      # Sets initial values for instance variables
    end

    def self.new(x,y)   # Class method to create new Point objects
      # Use the class instance variables in this class method to collect data
      @n += 1           # Keep track of how many Points have been created
      @totalX += x      # Add these coordinates to the totals
      @totalY += y

      super             # Invoke the real definition of new to create a Point
                    # More about super later in the chapter
    end

    # A class method to report the data we collected
    def self.report
        # Here we use the class instance variables in a class method
        puts "Number of points created: #@n"
        puts "Average X coordinate: #{@totalX.to_f/@n}"
        puts "Average Y coordinate: #{@totalY.to_f/@n}"
    end
end

...

  

因为类实例变量只是类的实例变量   对象,我们可以使用attr,attr_reader和attr_accessor来创建   它们的存取方法。

class << self
  attr_accessor :n, :totalX, :totalY
end

定义了这些访问器后,我们可以将原始数据称为Point.n,Point.totalX和Point.totalY。

我忘记了有一个“类实例变量”。 Ruby中的概念。在任何情况下,OP的问题似乎都令人费解,并且在迄今为止的任何答案中都没有真正解决,除了kch的答案中的暗示:它是范围问题。 (在编辑时添加:实际上,sris的答案确实在最后解决了这一点,但无论如何我都会让这个答案成立,因为我认为示例代码可能对理解问题很有帮助。)

在Ruby类中,以 @ 开头的变量名称可以引用两个变量之一:要么是实例变量,要么是一个类实例变量,具体取决于它所引用的类的位置。这是一个相当微妙的问题。

一个例子将澄清这一点。这是一个小的Ruby测试类(所有代码都在irb中测试):

class T

  @@class_variable = "BBQ"
  @class_instance_variable_1 = "WTF"
  @class_instance_variable_2 = "LOL"

  def self.class_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def initialize
    @instance_variable = "omg"
    # The following line does not assign a value to the class instance variable,
    # but actually declares an instance variable withthe same name!
    @class_instance_variable_1 = "wtf"
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def instance_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

end

我根据我的想法对变量进行了命名,但结果并非总是如此:

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

irb> t = T.new
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">

irb> t.instance_method
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> nil

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

@@ class_variable @instance_variable 总是按照您的预期行事:前者是在类级别定义的,无论是在类方法中引用还是在实例方法中,它保存在顶部分配给它的值。后者仅在类 T 的对象中获取值,因此在类方法中,它引用一个未知变量,其值为 nil

富有想象力地命名为 class_method 的类方法按预期输出 @@ class_variable 和两个 @class_instance_variable 的值,即as在课程顶部初始化。但是,在实例方法 initialize instance_method 中,访问同名的变量 ,即实例变量,而非类实例变量

您可以看到 initialize 方法中的赋值不会影响类实例变量 @ class_instance_variable_1 ,因为稍后调用 class_method 输出其旧值,&quot; WTF&quot; 。相反,方法 initialize 声明了一个新的实例变量,一个命名(误导) @ class_instance_variable_1 。分配给它的值&quot; wtf&quot; ,由方法 initialize instance_method 输出。

示例代码中的变量 @ class_instance_variable_2 等同于原始问题中的变量 @hello :它被声明并初始化为类实例变量,但是当一个实例时method指的是该名称的变量,它实际上看到具有相同名称的实例变量 - 一个从未声明过的变量,因此其值为nil。

我还建议查看以“@@”为前缀的类变量。 - 这里有一些示例代码,向您展示类和实例变量是如何不同的:

class Vars
  @@classvar="foo"
  def test
    @instancevar="bar"
  end
  def Vars.show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"
  end
  def instance_show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"

  end
end

# only shows classvar since we don't have an instance created
Vars::show
# create a class instance
vars = Vars.new
# instancevar still doesn't show b/c it hasn't been initialized
vars.instance_show
# initialize instancevar
vars.test
# now instancevar shows up as we expect
vars.instance_show
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top