谈谈Ruby中的类变量
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中的类变量的更多相关文章
- 理解Ruby中的作用域
作用域对于Ruby以及其它编程语言都是一个需要理解的至关重要的基础知识.在我刚开始学习ruby的时候遇到很多诸如变量未定义.变量没有正确赋值之类的问题,归根结底是因为自己对于ruby作用域的了解不够, ...
- ruby中symbol
Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字. 创建一个 Symb ...
- Ruby学习: 类变量和类方法
一.类变量 在ruby中,可以为类定义类变量,类变量的值为类的所有实例(对象)所共享. 有点类似其它语言(如java)中的静态变量,但与java中的静态变量的区别是, 类变量是私有的,无法在类的外部访 ...
- 谈谈JAVA中的安全发布
谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...
- ruby中的链式访问和方法嵌套
先看一道题,这道题是codewars上的一道题,我很早就看到了,但是不会写.等到又看到这道题的时候,我刚看完元编程那本书,觉得是可以搞定它的时候了.废话不多说,先看这道题,题目最开始是为JavaScr ...
- [翻译]理解Ruby中的blocks,Procs和lambda
原文出处:Understanding Ruby Blocks, Procs and Lambdas blocks,Procs和lambda(在编程领域被称为闭包)是Ruby中很强大的特性,也是最容易引 ...
- [No000010]Ruby 中一些百分号(%)的用法小结
#Ruby 中一些百分号(%)的用法小结 #这篇文章主要介绍了Ruby 中一些百分号(%)的用法小结,需要的朋友可以参考下 what_frank_said = "Hello!"#% ...
- Ruby中 使用Builder Xml Markup 操作XML
=begin Ruby中 使用Xml Markup 轻松的对XML文档操作, 项目地址:http://builder.rubyforge.org/ 使用之前我们需要安装Builder xml mark ...
- Ruby中Block, Proc, 和Lambda
Block Blocks就是存放一些可以被执行的代码的块,通常用do...end 或者 {}表示 例如: [1, 2, 3].each do |num| puts num end [1, 2, 3]. ...
随机推荐
- Combination Sum
Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique c ...
- 移动端 touch 事件的originalEvent
对于移动端的触摸事件,我们通过touchstart.touchmove.touchend实现,PC端一般使用mousedown.mousemove.mouseup实现. 我们获取事件坐标,原生js获取 ...
- iOS_Swift初识之使用三种回调方式自定义Button
最近在学习Swift ,发现青玉伏案大神早期用OC写的一篇博客--IOS开发之自定义Button(集成三种回调模式) 很适合用来熟悉Swift的回调方式,于是我就用Swift翻版了一下,具体实现原理 ...
- Android应用内存泄漏的定位、分析与解决策略
什么是内存泄漏 对于不同的语言平台来说,进行标记回收内存的算法是不一样的,像 Android(Java)则采用 GC-Root 的标记回收算法.下面这张图就展示了 Android 内存的回收管理策略( ...
- ubuntu12.04+Elasticsearch2.3.3伪分布式配置,集群状态分片调整
目录 [TOC] 1.什么是Elashticsearch 1.1 Elashticsearch介绍 Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎.能够快速搜索数 ...
- C#连接操作mysql实例
第三方组件:Mysql.Data.dll说明:去官方网站下载Mysql.Data.dll,然后在项目中添加该组件的引用,在代码页里输入using Mysql.Data.MysqlClient,我们就可 ...
- # C/C++的笔试题目
p,li { white-space: pre-wrap } # C/C++的笔试题目 + include<> 和include"" 的区别 + sizeof操作符与字 ...
- api接口验证shal()
就安全来说,所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输,明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床.所谓man-in-the-midd ...
- Ubuntu 16.04中安装Chromium浏览器
引用:http://www.linuxidc.com/Linux/2016-05/131097.htm 通过ppa,安装最新版本的Chromium浏览器 sudo add-apt-repository ...
- Linux的Service/Daemon你真的懂了吗?
一 service与一般的程序的区别 service(也称为daemon)表示后台运行的程序,一般随系统的启动自动地启动且在用户logoff后仍然能够继续运行.该daemon进程一般在启动后需要与父进 ...