新手问题 关于类变量的疑问

a886937 · 2018年12月01日 · 最后由 a886937 回复于 2018年12月04日 · 749 次阅读
class A
  @@path=''
  def path
    @@path
  end
end
class B < A
  @@path='b'
end
class C < A
  @@path='c'
end

obj= B.new
puts obj.path

按常理来说,应该输出

b

执行rails s 命令产生的结果是一致的。 但是用nginx里却输出的是

c

有大神能帮我解解惑吗,谢谢了。

共收到 11 条回复

这段代码你确定执行过吗?obj=new B 是什么鬼?

hellorails 回复

写的伪代码汗,搞成c#了,应该是B.new

这代码跑不通啊 B.new也跑不通

你想写 B 继承自 A 吧?

抱歉各位,爪机敲的问题百出。我修正过了,烦请各位帮帮我。

ecnelises 回复

对的

首先这段代码最后的结果就是 c,最简单的,开一个 irb 把代码都粘贴上去验证一下就行了。你上面提到的 Nginx 结果没有什么问题,至于 rails s 结果错误,肯定是因为别的原因(我猜想你的 B, C 都是自动加载类,然后实际上验证结果时 C 没有加载或者 B 在 C 之后加载的)。

至于结果为什么是 c,是因为 Ruby 的类变量会和所有子类以及他们的单例类共享的,即在上述的所有作用域中 @@path 的内存指向都是一样的。

class A
  @@path=''

  def path_object_id
    @@path.object_id
  end

  def self.path_object_id
    @@path.object_id
  end

  puts path_object_id # => 70139278257540
  puts self.new.path_object_id # => 70139278257540
end

class B < A
  puts @@path.object_id # => 70139278257540
  puts self.new.path_object_id # => 70139278257540
end

class C < A
  puts @@path.object_id # => 70139278257540
end
pinewong 回复

你好,非常感谢你的回答,我按照你的方法验证了一下。我确实是用的自动加载类,可以再请教一下你吗,如果我要达到打印 'b' 的效果的话,有什么办法可以实现吗,类结构不变。

yunshang Ruby 如何获取对象的内存地址? 中提及了此贴 12月02日 20:55
a886937 回复

像你这种情况是不想公用属性啊,那应该用实例变量而不是类变量。

但要记得实例变量区分类和他的单例类两个作用域,因此要把初始化的操作移到构造函数中,像上面在类中初始化会得不到你期望的效果

给你补上例子

class A
  def initialize
    @path=''
  end
  def path
    @path
  end
end
class B < A
  def initialize
    @path='b'
  end
end
class C < A
  def initialize
    @path='c'
  end
end

obj= B.new
puts obj.path
pinewong 回复

很感谢您的回帖,我已经明白了,谢谢您帮助

a886937 关闭了讨论 12月04日 16:24
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册