论坛首页 编程语言技术论坛

慎用类变量 - 实例变量靠谱量又足

浏览 13964 次
该帖已经被评为良好帖
作者 正文
   发表时间:2007-11-24  
报告首长,实际项目中就是用了class_inheritable_array
我嫌排BUG麻烦才改成class_inheritable_accessor,但他们的本质都是一样的,最终都是用到write_inheritable_attribute和read_inheritable_attribute,所以他们都有同生共死的BUG牵绊。
0 请登录后投票
   发表时间:2007-11-24  
哦,上面的回贴正是解决这个问题,陷阱陷阱~
不过 array/hash的value对象里如果再引用其它东西,最终还是到了一个地方。根结在于,它们最初的来源就不是两个,而dup的程度从来没达到过deepcopy。现在就是幸灾乐祸的说,早晚要出事,呵呵~
0 请登录后投票
   发表时间:2007-11-24  
嗯嗯!
代码都在那个百来行的inheritable_attribute.rb里。
拷贝的时机在Class被继承的回调里,一个类的inherited方法当有子类定义时自动调用:
class Class
    # Prevent this constant from being created multiple times
    EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)

    def inherited_with_inheritable_attributes(child)
      inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
      
      if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
        new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
      else
        new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
          memo.update(key => (value.dup rescue value))
        end
      end
      
      child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
    end

    alias inherited_without_inheritable_attributes inherited
    alias inherited inherited_with_inheritable_attributes

end
0 请登录后投票
   发表时间:2007-11-24  
但那个补丁已经整合到RAILS1.2.3中了,这么说还是有BUG?果然每个补丁后面都隐藏着更大的BUG,今天终于华丽的孵化了。

那RUBY有没dup!! 这种支持深层的遍历方法啊
0 请登录后投票
   发表时间:2007-11-24  
由potian老大的图看出,类的继承链上,在类本身的层次上,不会共享实例变量,也没有查找机制。如果想完全控制,还是自己手工定义类上面的accessor方法吧,想放到哪放到哪,想从哪取从哪取。不然,深度拷贝的效果也不合心意呢?关键在于,我们怎么定义继承下来的属性应该是什么样的
0 请登录后投票
   发表时间:2007-11-24  
但我目前需要实现的:
1.类与实例可共用变量
2.父类可以初始化变量值
3.子类继承父类的初始值,但子类改变变量值时,不影响父类的值

怎么看怎么像是class_inheritable_accessor的存在理由啊。
木有理由再造这么一个轮啊,修修或许还行,只是小弟功力尚浅,请前辈扶下小弟(不是那里,汗)。
0 请登录后投票
   发表时间:2007-11-25  
inherited是core extension,不敢对它贸然下手,但若要只影响到A所牵连的部分,还是可以quick hack一下:


class Base
  class_inheritable_accessor :var
  class << self
      def set_var(new_var)
        self.var ||= [{:a=>"aa"}, {:b=>"bb"}]
        self.var.each do |v|
          v[:a] = new_var
        end
      end
  end
end

class A < Base
 class << self
   
   def inherited_with_inheritable_attributes_deep_copy(child)
      inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
      child.instance_variable_set('@inheritable_attributes', Marshal.load(Marshal.dump(inheritable_attributes)))
    end
    alias_method_chain :inherited, :inheritable_attributes_deep_copy
 end

 class_inheritable_accessor :var

 set_var "a"
end

class B < Base
end

class C < A
end

A.var
#=> [{:a=>"a"}, {:b=>"bb", :a=>"a"}]
B.set_var('b')
A.var
C.set_var('c')
# *notice*
A.var
#=> [{:a=>"a"}, {:b=>"bb", :a=>"a"}]


用到The ruby way(11.1.9. Copying an Object)提到的Marshal(也只支持简单的Hash),估计它不会指条黑路给我吧。
但这里只能解决我写的简单演示代码,而实际项目代码复杂得多,所作的HACK并没有解决到问题,还需要继续探索。
0 请登录后投票
   发表时间:2007-11-25  
既要继承,又要相互独立,牵扯到复杂的场景,对象的引用关系不是单一一种方案能解决的吧,我还是觉得需要开发人员自己去判断。 比如上面用Marshal,那么从父类继承过来的Array/Hash整个也被克隆了,如果在子类上修改某个从父类继承过来的属性时,根据“继承”的推测,理所当然认为改了父类的,出错了。
引用

3.子类继承父类的初始值,但子类改变变量值时,不影响父类的值

用copy on write的模式实现setter/getter就行,可是能彻底解决理解上的歧义和功能上的需求吗?我觉得还是不会。
我的结论是,知道这个陷阱和解决办法是最务实的,大一统的方案我还没想明白,总结一下是
一、理解上的歧义
何时它是继承的、何时它又是独立的
二、功能需求
1.类与实例可共用变量,也可独立
2.类和实例都方便对内对外access这个"属性"

经过上面的讨论,我理解更清楚了,谢谢~
go on...
0 请登录后投票
   发表时间:2007-12-13  
看了好久,终于知道你们在说什么了...
1.copy bug
2.类变量(或类的实例变量)共享实现
我猜对了么?
其实我有很多关于Ruby方面的问题,想和你们交个朋友
0 请登录后投票
   发表时间:2008-08-28  
class A   
  @x = 1             #<<---- 按我说, 这里应该发出一个警告才对, “你是不是想用 @@x 少写了一个@”
  @@z = 1            #<<---- 这个是啥, 挺常用的
  def initialize   
    @y = 2   
  end  
end


liusong1111说:
引用
但怎么说子类父类引用同一个东东称之为class variable太诡异了。


底层数据结构 @x和 @@z 应该一样, @@z 的行为应该比较容易理解,

@x的这种用法我根本不知道用在哪好, 似乎有少写一个 @ 的嫌疑,只会把自己弄乱, 毕竟 对 前缀@ 的处理只是在Ruby语言层次的。


可以看一下
http://rhg.rubyforge.org/ 里面的 的 第四章 和 第六章

挺有用的。


0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics