7.1 模块
我们常常把许多零散的小物件放在一个盒子里,或者放在一个抽屉里,这些小物件可能是铅笔,墨水,字典等学习用品,也有可能是不相关的几件物品。在程序中,相关的、不相关的代码的组合,叫作模块。一般情况下,我们总是把功能相关的代码放在一个模块里。
把功能相关的程序代码放在一个模块里,体现了模块的第一个作用:可以被其它程序代码重复使用。
看程序 E7.1-1.rb :
- #E7.1-1.rb
- puts Math.sqrt(2) # => 1.4142135623731
- puts Math::PI # => 3.14159265358979
Ruby标准包里的 Math 模块提供了许多方法,比如:求平方根 sqrt ,使用的时候要这么写:模块名.方法名(参数)。你可以 Math.sqrt(37.2/3) ,Math.sqrt( a*5+b ) ; Math 模块还提供了两个常量,圆周率π 和自然对数底 e,使用的时候要这么写:模块名::常量名。
数学中常用的函数,Math模块都提供了。每个使用Math模块的程序员无须再重复编写这些常用的函数与常数。
定义模块用module...end 。模块与类非常相似,但是:
A) 模块不可以有实例对象;
B) 模块不可以有子类。
7.2 命名空间
如果你觉得Ruby标准包里的Math模块提供的sqrt方法不好,不能够设置迭代区间和精度,你重写了一个sqrt方法。你的同事在他的程序里需要调用你的sqrt方法,也要调用标准Math模块提供的sqrt方法,怎么办呢?
模块的第二个作用:提供了一个命名空间(namespace),防止命名冲突。
看程序 E7.2-1.rb :调用一个模块方法,与定义模块方法一样,要在方法名前加上模块名和一个点号“.”。模块方法提供了一个途径,在模块的外部访问模块内部方法,无须 include 模块。定义模块常量不需要如此。
- #E7.2-1.rb
- module Me
- def sqrt(num, rx=1, e=1e-10)
- num*=1.0
- (num - rx*rx).abs
- end
- end
- include Math
- puts sqrt(293) # => 17.1172427686237
- #puts sqrt(293, 5, 0.01)
- include Me
- puts sqrt(293) # => 17.1172427686237
- puts sqrt(293, 5, 0.01) # => 17.1172429172153
如你所见,只要include模块名,就能使用不同模块的sqrt方法,Math模块的sqrt方法不能有三个参数,Me模块的sqrt方法可以是一个参数,或者二个参数,或者三个参数。Me模块被include 在Math模块后面,Math模块的sqrt方法就被Me模块的sqrt方法覆盖了。
现在出现一个问题,你喜欢像Math模块那样调用sqrt方法,
puts Math.sqrt(2)
而不喜欢像Me模块那样调用sqrt方法,
include Me
puts sqrt(2)
还记得类方法吗?我们可以定义一个模块方法,在方法名前加上模块名和一个点号“.”。
看程序 E7.2-2.rb :
- #E7.2-2.rb
- module Me
- def sqrt(num, rx=1, e=1e-10)
- num*=1.0
- (num - rx*rx).abs
- end
- end
- module Me2
- def Me2.sqrt(*num)
- "This is text sqrt. "
- end
- PI=3.14
- end
- puts Math.sqrt(1.23) # => 1.10905365064094
- puts Math::PI # => 3.14159265358979
- puts Me2.sqrt(55, 66, 77, 88, 99) # => This is text sqrt.
- puts Me2::PI # => 3.14
- include Me
- puts sqrt(456, 7, 0.01) # => 21.3541565188558
调用一个模块方法,与定义模块方法一样,要在方法名前加上模块名和一个点号“.”。模块方法提供了一个途径,在模块的外部访问模块内部方法,无须 include 模块。定义模块常量不需要如此。
完整阅读,请看我写的 Ruby语言中文教程all in one