Ruby Quick Start (3) -- Module, Mix-in

2016-10-22 10:04:27来源:作者:Yilin's blog人点击

《Ruby语言入门教程v1.0》笔记(3)

第六章 模块、命名空间、Mix-in 1. Ruby中的模块

在程序中,相关的、不相关的代码的组合,叫作模块。一般情况下,我们总是把功能相关的代码放在一个模块里。

把功能相关的程序代码放在一个模块里, 体现了模块的第一个作用: 可以被其它程序代码重复使用。

数学中常用的函数, Ruby 中的 Math模块都提供了。 每个使用 Math模块的程序员无须再重复编写这些常用的函数与常数。

puts Math.sqrt(2)# 1.4142135623731puts Math::PI# 3.14159265358979

定义模块用 module...end。

模块与类非常相似,但是:

模块不可以有实例对象; 模块不可以有子类。 2. Ruby中的命名空间

如果你觉得 Ruby 标准包里的 Math模块提供的 sqrt方法不好,不能够设置迭代区间和精度,你重写了一个 sqrt方法。你的同事在他的程序里需要调用你的 sqrt方法,也要调用标准 Math 模块提供的 sqrt方法,怎么办呢?

模块的第二个作用:提供了一个命名空间(namespace) ,防止命名冲突。

moduleMedefsqrt(num, rx =1, e =1e -10) num *= 1.0 (num - rx * rx).abs < e ? rx :sqrt(num, (num / rx + rx) /2, e)endendincludeMathputs sqrt(293)# 17.1172427686237# puts sqrt(293, 5, 0.01) 错误,Math模块中的sqrt不存在这种调用方法includeMeputs sqrt(293)# 17.1172427686237puts sqrt(293,5,0.01)# 17.1172429172153

也可不用include,而通过模块名来访问模块方法:

moduleMedefsqrt(num, rx =1, e =1e -10) num *= 1.0 (num - rx * rx).abs < e ? rx :sqrt(num, (num / rx + rx) /2, e)endendmoduleMe2defMe2.sqrt(*num)# 这里参数的星号表示可以接受数组参数"This is text sqrt. "endPI=3.14endputs Math.sqrt(1.23)# 1.10905365064094puts Math::PI# 3.14159265358979puts Me2.sqrt(55,66,77,88,99)# This is text sqrt.puts Me2::PI# 3.14includeMeputs sqrt(456,7,0.01)# 21.3541565188558 3. Ruby中的糅和(Mix-in) 与多重继承

Ruby 本身是单继承,不是通过接口实现多重继承。但是通过 Mix-in模块,可以实现多重继承的优点。

模块的第三个作用: 实现了类似多重继承的功能。

我们有一个 Student类,有着 Person类的属性和方法,还会做数学题——求平方根。已经有了 Me模块,只要 Mix-in在 Student类里就可以了。

moduleMedefsqrt(num, rx =1, e =1e -10) num *= 1.0 (num - rx*rx).abs <e ? rx :sqrt(num, (num/rx + rx)/2, e)endendclassPersondeftalk puts "I'm talking."endendclassStudent<PersonincludeMeendaStudent = Student.newaStudent.talk # I'm talking.puts aStudent.sqrt(20.7,3.3)# 4.54972526643248

通过“ < 父类名” ,一个子类可以得到父类的属性和方法;

通过“ include 模块名” ,一个子类可以得到某个模块的常量和方法;

类不能被 include。

与 include方法相对应的,还有一个 extend方法。如果并不是 Student类的每个对象都会求平方根,只有某一个学生会,如何办到呢?

moduleMedefsqrt(num, rx=1, e=1e-10) num*=1.0 (num - rx*rx).abs <e ? rx :sqrt(num, (num/rx + rx)/2, e)endendclassStudentendaStudent = Student.newaStudent.extend(Me)# 为Student类的一个实例aStudent包含Me模块puts aStudent.sqrt(93.1,25)# 9.64883412646315

include方法为一个类的所有对象包含某个模块; extend方法为一个类的某个对象包含某个模块。

4. require 和 load

上面的程序中先写了 Me模块,然后 include Me模块,实现了 Mix-in功能,但是,这样没能做到 代码复用。

我们将 Me模块和 Person类分别写在不同的文件( Me.rb和 Person.rb)中,这时候 Student类如何使用 Me模块和 Person类呢?这里要用到 require方法。

require"Me"require"Person"classStudent<PersonincludeMeendaStudent = Student.newaStudent.talk # I'm talking.puts aStudent.sqrt(77,2)# 8.77496438739435

require, load用于包含文件; include, extend则用于包含模块。

require加载文件一次, load加载文件多次。

require加载文件时可以不加后缀名, load加载文件时必须加后缀名。

require一般情况下用于加载库文件,而 load用于加载配置文件。

利用 load多次加载文件的特性,可以用来实现程序的无缝升级和系统的热部署。程序功能改变了,你只需要重新 load一次,其它代码与它再次交互的时候,这个程序实际上已经不是原来的程序了。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台