ruby:类实例变量vs实例变量

ruby: class instance variables vs instance variables

我的想法是为来自java背景的人创建一个社区wiki,因为阅读了大量的解释,我无法理解任何东西,直到我真正尝试了一些东西,拼图的碎片开始找到他们的位置。但我首先要确保我做的对。从这样的背景来看,我很困惑地发现,@variable可能意味着两个截然不同的东西。下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Test
  @ins ="gah"
  def self.ins
    puts @ins
  end

  def initialize()
    @ins ="wtf?"
  end
  def ins2
    puts @ins
  end
end

据我所知,第一个@ins是表示类Test的对象的实例变量。第二个@ins是类Test的对象中的一个实例变量。

现在事情开始对我有意义了。这里有几个例子:

1
2
[14] pry(main)> test.ins2
wtf?

我们正在调用对象的方法,它返回对象的实例变量。

1
2
[15] pry(main)> test.ins
NoMethodError: undefined method `ins' for #<Test:0x000000017d9348 @ins="wtf?">

我们试图通过一个对象调用一个类方法,这个方法属于类,所以我们得到了NoMethodError

1
2
[16] pry(main)> Test.ins
gah

我们正在调用一个类方法,以便它正确地看到类对象的实例变量。

1
2
[17] pry(main)> Test.ins2
NoMethodError: undefined method `ins2' for Test:Class

我们正在通过不正确的类调用一个对象方法,因此抛出NoMethodError

以上所有操作都是用Ruby2.0执行的。我在问什么?

  • 我说得对吗?
  • 我是否正确使用了Ruby术语?
  • 在一个设计合理的应用程序中,类实例变量的实际用法有意义吗?或者这些仅仅是更好的@@类变量?


it was very confusing for me to find out that @variable may mean 2 very different things.

不,不是。类和其他任何对象一样都是对象。它们可以像其他任何对象一样拥有实例变量。它们可以像其他任何对象一样拥有实例方法。事实上,与Java不同,它有三种不同的"方法"(实例方法、静态方法和构造函数),在Ruby中,恰好有一种方法:实例方法。

把类作为对象的好处就在于@variable总是意味着完全相同的事情。

没有类实例变量这样的东西:它只是一个普通的实例变量,和其他变量一样。对象恰好是Class的一个实例,但这不会改变实例变量的性质。类String的对象的一个实例变量不是字符串实例变量,它只是一个实例变量。同样,类Class的对象的一个实例变量只是一个实例变量。

没有类方法这样的东西:它只是一个对象的普通单例方法,而这个对象恰好是Class的一个实例。(准确地说,也没有singleton方法:它只是对象的singleton类的一个普通实例方法。)

注意:红人可能会在随意的谈话中使用"课堂方法"。但这并不意味着类方法确实存在,它只是意味着"类对象的单例类的实例方法"是一个满口的东西。重要的是:因为类是对象,所以它们的工作方式与所有其他对象完全相同。它们可以有实例方法(在类Class中定义或继承自ModuleObjectKernelBasicObject,它们可以有"单例方法"(实际上是它们各自单例类的实例方法),它们可以有实例变量。

它们也可以有类变量(@@variables………)这些都很奇怪。忽略它们:


  • 首先,要理解实例变量,需要知道这一点——类是对象。

    所有类都是从Object继承的Class的实例。这就是类是对象的原因。

  • 然后,在self中定义每个实例变量(标识为@的ID,如@ins的ID)。

    self是一个类时,它们是类的实例变量(类实例变量)。当self是一个对象时,它们是对象的实例变量(实例变量)。

  • 在不同的代码范围中,self表示不同的东西。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Test
      # class scope, uncomment following line to see the value of self
      # p self
      @ins ="gah"
      def self.ins
        # class scope
        # p self
        puts @ins
      end

      def initialize()
        # object scope
        # p self
        @ins ="wtf?"
      end
      def ins2
        # object scope
        # p self
        puts @ins
      end
    end

  • 我觉得一切都很好。

    类变量将通过继承传递,而类上的实例变量将不传递。(src:ruby类实例变量vs.class变量)

    就设计而言,我倾向于完全避免类变量(我宁愿使用单例变量),但如果必须选择一个变量,我可能会选择类变量而不是类实例变量,以避免混淆。