Ruby中的类变量,很多文章都是不太建议使用的,主要原因在于他的一些特性容易导致犯一些错误,尤其在广泛使用元编程的时候。

初步接触类变量可能觉得他跟C++的类静态成员和Java中的静态变量没什么区别,但在实际使用中一不留神就会掉到类变量的陷阱中去

陷阱1,类变量跟类实例变量不同,类实例变量关联的是self,但类变量关联的是当前类作用域

class C
end class D
end class C
@@var = "C"
def D.getvar
@@var
end
end class D
@@var = "D"
def C.getvar
@@var
end
end C.getvar
#=> "D"
D.getvar
#=> "C"

在这个例子里面我在类C里面定义D的方法,在D里面定义C的方法,结果C的方法返回了D的类变量,而D的方法返回了C的类变量,这就是由于类变量跟当前环境的self无关,只跟所在环境的类作用域有关,如果不包含在class关键字中,则视为在Object中。

是不是感觉有点怪怪的啊,不过更怪的还在后面。

陷阱2,超类如果增加一个子类已有的同名类变量,会将子类的类变量污染

我们知道类的继承带有引用性质,在一个引用树上,子类可以重写超类的方法和变量而不对超类产生影响,但对于类变量这个事情不成立

类变量在整个继承树中只有一个实体,首先超类中如果有类变量,子类完全继承,而子类中的类变量原则上是不影响超类的,但一旦超类中加入了相同的类变量就会自动把子类的类变量重写!!

class C
@@var1 = "C_var1"
def getvar
@@var1
end
def setvar
@@var2 = "C_var2"
end
end
class D < C
@@var2 = "D_var2"
def getvar
@@var2
end
end
c = C.new
d = D.new
p c.getvar
#"C_var1"
p d.getvar
#"D_var2"
c.setvar
p c.getvar
#"C_var1"
p d.getvar
#"C_var2"

可以看到,子类和超类有各自的同名实例函数,但是却共享一个相同的类变量名。

陷阱3,跟陷阱2类似,Object中如果定义一个类变量,会将所有类中的同名类变量污染

同样的,如果两个不同的子类中有两个相同的类变量,这本来是不干扰的,但是一旦他们共同的超类定义了该类变量,这三个类变量就会强制统一!!

而我们知道类共同的超类是Object,那么一旦你在Object中定义了一个类变量,就会导致所有的类的同名类变量都受到污染!!

class C
@@var = "C_var"
def getvar
@@var
end
end
class D
@@var = "D_var"
def getvar
@@var
end
end
c = C.new
d = D.new
p c.getvar
# "C_var"
p d.getvar
# "D_var"
class Object
@@var = "Object_var"
end
# @@var = "main_var"
# 使用这句有同样的效果,不过会得到一个警告
p c.getvar
# "Object_var"
p d.getvar
# "Object_var"

类变量在一个继承树中只能有一个,不允许重写,但在不同的继承树中却允许重名,这个奇葩的东西还是少碰点的好

因此慎用类变量,尤其是不要用猴子补丁来定义类变量,我甚至觉得这个奇怪的东西应该从Ruby中拿掉。

谈谈Ruby中的类变量的更多相关文章

  1. 理解Ruby中的作用域

    作用域对于Ruby以及其它编程语言都是一个需要理解的至关重要的基础知识.在我刚开始学习ruby的时候遇到很多诸如变量未定义.变量没有正确赋值之类的问题,归根结底是因为自己对于ruby作用域的了解不够, ...

  2. ruby中symbol

    Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字. 创建一个 Symb ...

  3. Ruby学习: 类变量和类方法

    一.类变量 在ruby中,可以为类定义类变量,类变量的值为类的所有实例(对象)所共享. 有点类似其它语言(如java)中的静态变量,但与java中的静态变量的区别是, 类变量是私有的,无法在类的外部访 ...

  4. 谈谈JAVA中的安全发布

    谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...

  5. ruby中的链式访问和方法嵌套

    先看一道题,这道题是codewars上的一道题,我很早就看到了,但是不会写.等到又看到这道题的时候,我刚看完元编程那本书,觉得是可以搞定它的时候了.废话不多说,先看这道题,题目最开始是为JavaScr ...

  6. [翻译]理解Ruby中的blocks,Procs和lambda

    原文出处:Understanding Ruby Blocks, Procs and Lambdas blocks,Procs和lambda(在编程领域被称为闭包)是Ruby中很强大的特性,也是最容易引 ...

  7. [No000010]Ruby 中一些百分号(%)的用法小结

    #Ruby 中一些百分号(%)的用法小结 #这篇文章主要介绍了Ruby 中一些百分号(%)的用法小结,需要的朋友可以参考下 what_frank_said = "Hello!"#% ...

  8. Ruby中 使用Builder Xml Markup 操作XML

    =begin Ruby中 使用Xml Markup 轻松的对XML文档操作, 项目地址:http://builder.rubyforge.org/ 使用之前我们需要安装Builder xml mark ...

  9. Ruby中Block, Proc, 和Lambda

    Block Blocks就是存放一些可以被执行的代码的块,通常用do...end 或者 {}表示 例如: [1, 2, 3].each do |num| puts num end [1, 2, 3]. ...

随机推荐

  1. PHPExcel 导出时乱码

    今天遇到了个奇怪的问题..猜测应该是因为php文件的编码造成的,但是没有解决办法. 问题是,用PHPEXCEL导出文件的时候,相同的代码在一个文件中可以导出,在另一个文件中却不行.. 最后没有办法,只 ...

  2. JSBInding+Bridge.NET:把C#编译为Js

    编译步骤: 1. 用 VS 2015 打开 BridgeProj/BridgeProj.sln ,编译 2. 将生成 BridgeProj/Bridge/output/bridge.js,对应于 Br ...

  3. createjs 入门之EaselJs 绘制图片Bitmap

    var canvas=document.getElementById('demoCanvas'); canvas.width=window.innerWidth; canvas.height=wind ...

  4. Unity进阶技巧 - 动态创建UGUI

    前言 项目中有功能需要在代码中动态创建UGUI对象,但是在网上搜索了很久都没有找到类似的教程,最后终于在官方文档中找到了方法,趁着记忆犹新,写下动态创建UGUI的方法,供需要的朋友参考 你将学到什么? ...

  5. ProcessOn

    1.地址:http://www.processon.com/ 2.简介:在线创作流程图.BPMN.UML图.UI界面原型设计.iOS界面原型设计等. 3.优势:无需安装,简单易用.可以替代VISO,学 ...

  6. 转载:scala中:: , +:, :+, :::, ++的区别

    原文链接:https://segmentfault.com/a/1190000005083578 初学Scala的人都会被Seq的各种操作符所confuse.下面简单列举一下各个Seq操作符的区别. ...

  7. 阿里云centos yum源更换,两个文件是从阿里云服务器拷贝出来的,可安装openvpn

    第一步:备份你的原镜像文件,以免出错后可以恢复. mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.back ...

  8. CentOS 6、7下pptp vpn一键安装脚本

    之前有折腾过<CentOS 6.7下IPSEC/L2TP VPN一键安装脚本>,不稳定.不支持IOS,因此换成pptp,并已经添加到<lnmp一键安装包>.这个脚本可以单独使用 ...

  9. S5Time BCD码存储

    ,时基为1秒. 当使用S5TIME时,定义数值的范围为0~999,而且要指明使用的时基.时基指定了时间单位. S5TIME时基及相应的时间范围如下: 时基 BCD码 时间范围 10 ms 00 10 ...

  10. 用SysTick做的延时计时器

    CM3.CM4的内核中都有个24位的SysTick定时器.这两个MCU里边的SysTick大同小异.SysTick的介绍可以参考:(来自CSDN博客的参考)或者(来自百度文库的参考)或者参考<C ...