2010-11-01

Ruby Cheat Sheet#1 反射



irb(main):001:0> a = Object.new
=> #<Object:0x7ff7a6ff6388>
irb(main):002:0> a.object_id #获取对象ID
=> 70350817702340
irb(main):003:0> a.class #获取对象类型
=> Object
irb(main):004:0> Integer.superclass #获取父类
=> Numeric
irb(main):006:0> Numeric.superclass #...
=> Object
irb(main):007:0> Object.superclass #Object父类为 nil
=> nil
irb(main):011:0> Integer.ancestors #获取类的父类及 include 的类
=> [Integer, Precision, Numeric, Comparable, Object, Kernel]
irb(main):013:0> Integer.class #类的类型是 Class
=> Class
irb(main):019:0> 1.methods #查找对象的方法
=> ["%", ...]
irb(main):020:0> 1.public_methods #查找对象的公开方法
irb(main):022:0> 1.protected_methods #查找对象的保护方法
irb(main):023:0> 1.private_methods #查找对象的私有方法

irb(main):029:0> class << a
irb(main):030:1> def foo; end
irb(main):031:1> end
=> nil
irb(main):032:0> a.singleton_methods #查找对象的单例方法
=> ["foo"]

irb(main):033:0> a.methods.grep /methods/ #快速查询方法
=> ["public_methods", "methods", "singleton_methods", "protected_methods", "private_methods"]

irb(main):034:0> Integer.methods #类也是对象,也有 :methods
=> ["private_class_method", ...]
irb(main):036:0> Integer.instance_methods #获取实例方法
irb(main):037:0> Integer.public_instance_methods #...
irb(main):038:0> Integer.protected_instance_methods #...
irb(main):039:0> Integer.private_instance_methods #...

irb(main):041:0> 1.method :times #获取方法对象
=> #<Method: Fixnum(Integer)#times>
irb(main):042:0> 1.method(:times).call #执行方法对象
=> #<Enumerable::Enumerator:0x7ff7a703fb78>
irb(main):044:0> 1.send :times #执行方法对象
=> #<Enumerable::Enumerator:0x7ff7a7019090>
irb(main):045:0> 1.__send__ :times #执行方法对象
=> #<Enumerable::Enumerator:0x7ff7a6ffd1b0>

irb(main):047:0> m = 1.method :times
=> #<Method: Fixnum(Integer)#times>
irb(main):048:0> m.name #方法名称
=> "times"
irb(main):051:0> m.owner #方法所在的类
=> Integer
irb(main):054:0> m.to_proc #转成 Proc 对象
=> #<Proc:0x00007ff7a6f955d8@(irb):54>
irb(main):055:0> m.unbind #解除绑定
=> #<UnboundMethod: Fixnum(Integer)#times>
irb(main):056:0> m.arity #最少参数个数
=> 0
irb(main):057:0> m.receiver #绑定的对象
=> 1

irb(main):058:0> m = Integer.instance_method :times #获取未绑定的对象
=> #<UnboundMethod: Integer#times>
irb(main):060:0> m.bind(1) #绑定
=> #<Method: Fixnum(Integer)#times>
irb(main):061:0> m.owner #方法所在的类
=> Integer
irb(main):062:0> m.arity #最少参数个数
=> 0
irb(main):063:0> m.bind(Object.new) #绑定时会做类型检查
TypeError: bind argument must be an instance of Integer
from (irb):63:in `bind'
from (irb):63
from :0
irb(main):075:0> Integer.method_defined? :times #查询类的实例方法是否被定义
=> true
irb(main):076:0> Integer.public_method_defined? :times
=> true
irb(main):077:0> Integer.protected_method_defined? :times
=> false
irb(main):078:0> Integer.private_method_defined? :times
=> false

irb(main):089:0> 1.respond_to? :times #检查对象是否有方法
=> true
irb(main):092:0> 1.respond_to? :raise
=> false
irb(main):093:0> 1.respond_to? :raise, true #同时检查私有方法
=> true
irb(main):106:0> [1.class, 1.class.superclass]
=> [Fixnum, Integer]
irb(main):098:0> 1.is_a? Fixnum #检查1是否是 Fixnum 或其子类的对象
=> true
irb(main):099:0> 1.is_a? Integer #检查1是否是 Integer 或其子类的对象
=> true
irb(main):103:0> 1.instance_of? Fixnum #检查1是否是 Fixnum 的对象
=> true
irb(main):104:0> 1.instance_of? Integer #检查1是否是 Integer 的对象
=> false
irb(main):108:0> Fixnum.instance_methods - Integer.instance_methods #查看 Fixnum 类新添加的实例方法
=> ["%", "<<", "&", ">>", "to_sym", "*", "+", "-", "/", "|", "size", "~", "^", "**", "to_f", "id2name", "[]"]

补1: 刚才忘了变量部分了

irb(main):001:0> class A
irb(main):002:1> @@b = 1
irb(main):003:1> @c = 2
irb(main):004:1> def initialize
irb(main):005:2> @d = 3
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):008:0> A.class_variables
=> ["@@b"]
irb(main):010:0> A.class_variable_defined? "@@b"
=> true
irb(main):011:0> A.instance_variables
=> ["@c"]
irb(main):012:0> A.instance_variable_defined? "@c"
=> true
irb(main):014:0> A.instance_variable_set "@c", 15
=> 15
irb(main):015:0> A.instance_variable_get "@c"
=> 15
irb(main):016:0> a = A.new
=> #<A:0x7f55a5717c88 @d=3>
irb(main):018:0> a.instance_variables
=> ["@d"]
irb(main):019:0> a.instance_variable_defined? "@d"
=> true
irb(main):020:0> a.instance_variable_set "@d", 16
=> 16
irb(main):021:0> a.instance_variable_get "@d"
=> 16

[随笔] 只会一种语言带来的风险, 我的观点

今天 shanghai on rails 三周年聚会时提到一个问题,一个程序员能否只会一种语言,只会一种语言会带来什么样的技术风险?

我的观点是只会一种语言确实会带来风险,风险主要来自于程序员会变得偏执以及语言本身会跟不上需求的演化。前一点比较主观,所以主要说说语言本身跟不上需求演化的问题。

在 C 和 Fortran 时代, 编程的一个主要指导思想是如何充分利用 CPU 和内存,所以我们会推崇 blas, lapack, atlas 之类的数学库, 会去研究如何微调编译器选项, 会说程序就是算法+数据结构,会去提醒朋友使用 minmax 算法因为他只需比较 ~1.5N 次而不是 2N 次。

逐渐地,需求变更了, 我们觉得面向对象的设计很重要, 他能让我们能处理一些更复杂的业务,为此我们愿意牺牲一点性能, 所以 C++ 出现了。C++ 尽管声称性能不妥协,但在虚函数,异常,RTTI 上毕竟对性能做了一些妥协,而且由于 C++ 工程上难度的提高, 导致在实际实施中会损失了更多的运行效率。这时期我们会推崇 MFC, QT, WX 这类的 UI 库, 以及 ACE 之类的网络库。为了降低 C++ 工程上的风险,我们会去读 Effective C++, Exceptional C++ 这类书,会去尽量找有较长工作经验的工程师。

需求再次变更了,我们无法容忍 C++ 的低鲁棒性. 变量未初始化, 提前释放,缓冲区溢出, 复杂的多线程实践, 没有底层安全机制, 这些问题导致了一个又一个的项目失败。所以 Java 出现了, Java 抛弃了性能不妥协,引入了 GC, 引入了更方便的同步机制, 更堵住了一些让 C++ 程序崩溃的漏洞。这时期我们会推崇 J2EE,几乎霸占了整个企业应用市场。我们会教导我们的同事要使用 TDD, 接口要和实现分离, 要使用检查异常。

接着需求就出现分支了, 一支说 Web 开发很重要, 我们需要开发更有效率, 语言需要更灵活, 所以 Ruby, Python 这类的语言开始流行,诞生了 Rails, Django 这类优秀的 Web 框架。特别是 Ruby, 在引入 MixIn, Block, DSL, BDD, Bundler 后,极大程度地提高了开发效率。

Java 也做了一个很大规模的演化: Java 5, 再加上 SSH 框架, 引入 Annotation, 大规模使用非检查异常, 引入 Aspect, 引入 cglib, ORM, 尽管仍然叫 Java, 但是跟我们之前的 Java 已经有了很大的不同, 设计目标不再是安全,鲁棒,而是高效开发,甚至产生了 Spring Roo, Play framework 之类相当背离 Java 原始开发风格的框架。尽管很成功, 但是作为一种静态语言,他背了太多的包袱,开发效率上始终比不上动态语言。同时由于当初为了讨好 C++, 保留了原始类型和数组, 导致反射的使用异常痛苦,普通开发者很少使用反射来简化自己的设计。所以 Web 开发方面,尽管有 Structs 2, Spring 3 之类优秀的 MVC 框架,还是有更多的程序员选择逃离 Java。

另一支则说高并发很重要, 所以 Scala, Erlang, Concurrent Python 之类语言出现了.....(太晚了,不写了)。

所以只会一种语言的风险在哪儿?在于需求的变化很快, 语言的演化很慢(比如C++ 1x), 很痛苦(比如 Java 7), 失败率也很高(比如 Perl 6)。只会一门语言就意味着你把自己局限在了这种语言所擅长的问题圈子,你无法解决这个圈子之外的问题。

至于偏执, 这是我个人观察后得出的结论,你可以看看你周围的程序员,是否有这个问题

thanks.

PS. 为了避免不必要的纠纷,先说一句, lisp rocks.