该文档并非详尽Ruby的一切特性, 而是希望能抓住Ruby本身的特性和迷人之处.
1 Ruby基本结构
String Array Hash Numeric Symbol Object
1.1 Symbol
如:dsg
, symbol用于很多地方, 其很重要一点为: symbol在内存中仅存储一份.
:dsg.object_id === :dsg.object_id #=> 返回true
而字符串不是.
"dsg".object_id == "dsg".object_id #=> 返回false
2 变量和常量
2.1 变量
2.1.1 普通变量(local variable)
ruby的变量非常简单
如果上下文没有给一个陌生的'变量'赋值, 那么该'变量'不是'变量', 而是方法
class User attr_accessor :name def set_name origin_name = name # name为方法, origin_name为变量 self.name = "reseted #{name}" # name为方法, 重新赋值 end end
2.1.2 实例变量(instance variable)
存储在对象中的变量, 如下面的 @score
class User def initialize @score = 0 end end
2.1.3 类实例变量(class instance variable)
ruby中一切都是对象, 类也是对象, 存储在类中的实例变量为类实例变量
class People @alive = true end
上述的 @alive 为People类的实例变量
类实例变量存储在该类中, 是不被子类共享的.
如
class Man < People end Man.instance_variable_get(:@alive) #=> 输出是nil, 而不是@alive
2.1.4 类变量(class variable)
类变量存在整个继承链中, 被所有继承的子类共享
class People @@alive = true end class Man < People end Man.class_variable_get(:@@alive) #=> true Man.class_variable_set(:@@alive, false) People.class_variable_get(:@@alive) #=> false
Rails中关于类变量的应用: mattr_accessor
2.1.5 全局变量(global variable)
全局共享
$DSG = "dsgv587"
2.2 常量
- 常量在内存中只存在一份
- 常量有查找算法
- 如果查找不到该常量, 会走到Module#const_missing方法
- Rails通过复写const_missing方法, 使得常量的加载可以自动require该常量对应的文件
- 类名, module名都是常量
3 方法查找
3.1 方法定义
在ruby中, 方法只能定义一次, 不支持类似于java中overloading机制.
如
class User def get_name end def get_name(type) end end
在User类中同时定义了两个同名方法 get_name, 在ruby中, 后定义的方法生效.
3.2 方法查找
3.2.1 ancestors
所有的方法查找都从当前的self对应的类的ancestor中去查找
如下面的例子所示:
class People def name puts "People name" end end module MixinUser def name puts "MixinUser" end end class User < People include MixinUser def name puts "User name" super end end
User.new.name #=> User name MixinUser
该部分Ruby metaprogramming讲解地非常好. 请查看该书的第二章
方法查找方式
获取所有的祖先链
ruby User.ancestors #=> [User, MixinUser, People, Object, Kernel, BasicObject]
从祖先链依次遍历, 看其中是否有name方法, 如果是super, 则从祖先链的上一级去找
3.3 影响祖先链的因素
方法存在类里面
- prepend
- sigleton method
- self
- include
- super
最终如果找不到方法, 则去Object, Kernel, BasicObject找, 如果还找不到, 则进入method_missing方法
3.4 作用域和作用域门
参见Ruby metaprogramming的第四章: Blocks-Blocks Are closures-Scope
三个作用域门(Scope Gates)
- Class definitions
- Module definitions
- Methods
即 class
, module
和def
关键字
在metaprogramming中的例子如下:
v1 = 1 class MyClass v2 = 2 local_variables #=> [:v2] def my_method v3 = 3 local_variables #=> [:v3] end local_variables #=> [:v2] end local_variables #=> [:v1]
可以其他方式打开作用域门, 即: define_method 代替 def, Class.new 代替 class, Module.new 代替 module
4 后记
个人理解中, Ruby是设计得非常好的, Ruby中遵循了最小惊讶原则: principle of least surprise, 理解了上面提到的Ruby的数据模型, 变量常量定义, 方法查找, 作用域之后, 基本上Ruby不会再给你其他的惊喜或者特殊的地方.
非常感谢Paolo Perrotta, 您的metaprogramming
给我们打开了Ruby的另一扇门, 让我们能理解到Ruby的精髓和奇妙之处, 也支撑着我们以后学习其他语言如Go, Elixir, Javascript等, 都会思考相同的问题:
- 语言的数据模型是什么?
- 变量和方法是如何定义和寻找?
- 变量的作用域是什么?
- 这些语言提供的特性Ruby有吗?
对比着学习一门语言, 可以让我们事半功倍, 让精通第二门, 第三门语言的时间越来越短, 也能真正地感受到编程之美.
另外一本我们非常喜欢的书为Ruby Under a Microscope, 从C源码分析了Ruby的类, 方法是如何实现的, 尤其是AST, GC部分的分析, 非常地深入浅出. 很值得大家一看.
5 TODO
- GC
- Thread
- Why ruby is slow compared with NodeJS or Java or C?