我有一个基本控制器
class Base
@@var = 'base'
def self.result
@@var
end
def self.result=(var)
@@var = var
end
def do_sth
// do something here
end
end
和2个子类
class A < Base
Base.result = 'a'
end
class B < Base
Base.result = 'b'
end
当访问url_a转到class A
,然后我访问url_b转到class B
,两者都运行正常。
但当我切换回url_a时,Base.result
仍会返回b
,为什么?
修改
我已将@@var
更改为@var
,我得到的结果相同。
答案 0 :(得分:1)
这是@lurker在问题评论中提到的内容的扩展。无论您使用类变量还是类级实例变量都没关系,您将看到相同的行为。
然而,当您使用两种类型的变量时,幕后发生的情况会有所不同。
案例1:类变量(即@@var
)
在类声明期间设置类变量的值,即读取Ruby源代码并且只发生一次。
这里要记住两件事:
url_a
class A
时,即已解析其来源class B
尚未加载。当您点击url_b
时,它会被加载。Base.result =
方法调用。所以步骤的顺序是:
url_a
时,class A
已解析,Base.result = a
将@@var
设为a
url_b
的调用中,class b
被解析,Base.result = b
将@@var
设置为b
,对于所有后续调用,它仍然如此。以下代码段可能有助于理解第二点:
irb(main):033:0> class ParseTest
irb(main):034:1> @@time_now = Time.now
irb(main):035:1> def speak_time
irb(main):036:2> puts @@time_now.to_s
irb(main):037:2> end
irb(main):038:1> end
=> nil
irb(main):039:0> pt = ParseTest.new
=> #<ParseTest:0x007f80758514c8>
irb(main):040:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):041:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):042:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):043:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):044:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):045:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):046:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):047:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):048:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):049:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):050:0> pt.speak_time
2014-09-18 23:15:15 +0530
=> nil
irb(main):051:0> class ParseTest2 < ParseTest
irb(main):052:1> @@time_now = Time.now
irb(main):053:1> end
=> "2014-09-18T23:16:41.911+05:30"
irb(main):054:0> pt.speak_time
2014-09-18 23:16:41 +0530
=> nil
irb(main):055:0>
正如您所看到的,在解析ParseTest
类定义一次后,@@time_now
的值在随后的任何puts
中都没有变化。时间的价值就是解析源代码的时间。
但是,当我定义ParseTest2
子类并解析其代码时,同一个类变量被赋予了新的time值。当我使用基类的相同旧对象打印它时,会反映这个新值。
这也是您的代码中发生的事情。
案例2:类级实例变量(即任何实例函数外的类定义中的@var
)
现在,如果不是类变量而是在类定义中使用实例变量(即在任何函数之外),那就非常不同了。这种情况可能看起来有点令人困惑,因此如果第一次看起来让您感到困惑,请阅读并重新阅读以下代码段。
irb(main):089:0> class Base
irb(main):090:1> @time_now = Time.now
irb(main):091:1>
irb(main):092:1* def self.time_now=(time)
irb(main):093:2> @time_now = time
irb(main):094:2> end
irb(main):095:1>
irb(main):096:1* def self.time_now
irb(main):097:2> puts @time_now.to_s
irb(main):098:2> end
irb(main):099:1> end
=> nil
irb(main):100:0> class A < Base
irb(main):101:1> Base.time_now = Time.now
irb(main):102:1> end
=> "2014-09-18T23:33:26.514+05:30"
irb(main):103:0> Base.time_now
2014-09-18 23:33:26 +0530
=> nil
irb(main):104:0> A.time_now
=> nil
irb(main):105:0> A.time_now = Time.now
=> "2014-09-18T23:34:27.093+05:30"
irb(main):106:0> A.time_now
2014-09-18 23:34:27 +0530
=> nil
irb(main):107:0> Base.time_now
2014-09-18 23:33:26 +0530
=> nil
irb(main):108:0>
类级别实例变量对class
是私有的。它在继承期间不会被传递/共享。因此,继承层次结构中的每个类都有自己的一组实例变量。但是,方法确实被传递,并且这些方法作用于调用它们的类的实例变量。因此,根据您调用time_now=
setter方法的类,将设置相应的实例变量。
在您的情况下,您始终引用Base
类的实例变量。因此,相同的一组步骤发生在前一个案例中所描述的
url_a
时,class A
已解析,Base.result = a
将@var
设为Base
至a
url_b
的调用中,class b
被解析,Base.result = b
将@var
Base
设置为b
,它仍然是所有后续电话。