成语言的基础,使用语言的最高一级单位。
A. 基本定义方式
class Song def initialize(name, artist, duration) @name = name @artist = artist @duration = duration end end
initialize 是调用new时,分配uninitialized的对象内存后,会呼叫的一个函数,并传入new中的参数。
@ 开头的变量是实例变量,属于object
Class variable以"@@ " 开头。在使用前必须被初始化(通常在class的定义中使用一条赋值语句)。
访问Class variable可以是实例的method,也可以是class method。
new是class method,而initialize是instance method。
在instance method内饰,self指向该class的一个实例。
而protected则能在class或者subclass范围内指定某个reciever
B. Inheritance and Messages(继承和调用)
"< Song " 说明Song是superclass, 但子类一般更好或更特别。
ruby的多态类似java,method调用时,先从子类找可以接受消息的method。
直接访问祖先的成员变量是一个不好的行为。
用method chaining 实现decorator模式,比如super.
C. Objects and Attributes
成员变量的访问通过定义method实现,定义与成员变量名称相同的method获取值,而变量名结尾跟着= 实现 写入method。rails自动完成这些attributes的method的添加。
angels on a pinhead 是指说不清道不明的问题,可以思辩但实际用时无所谓。
initialize只有一种,如果有多种构造方式,可以通过实现各factory并最终转化到initialize所需要的格式。
ruby内建的Singleton module实现了Singleton模式,主要完成了两件事情:
G. Constants
1. 定义在某个module或者class之内的constant,在内部使用时可以什么都不加,在其他地方使用时给出::并带有对应module或class的名称。
2.不定义在任何module或者class之内的变量,可直接使用,前面不用加任何东西。实际上该const属于Object.
A. containers: objects that hold references to one or more other objects.
class SongList def [](index) @songs[index] end end
B. Block 的进一步说明
yield 中的参数
参数可以传多个,而且block中的参数和method中的参数是共享一个内存空间。
yield也可以返回值。
*args , meaning “collect the actual parameters passed to the method into an array named args.” 传给其他函数时,也是按照*args的形式传入。
可变长度的参数列表(bundled into a new array)
block_given? 可以判断调用该method时,有没有传入block,以此可以给method制定不同的行为。
如File.open,在判断有block输入时,会执行block并在结束后close文件,如无block输入则简单的打开文件并返回文件引用。该函数位于Kernel类中。
C. Proc实例(将block变成变量保存下来)
method中最后的一个以& 开开头的参数表明调用该函数时,ruby必须要查找block。block会变成Proc的一个实例,之后可以使用。
def initialize(label, &action) super(label) @action = action end
@action.call(self)
通过call传入的参数可以自己来掌握,并且即使该参数在上下文环境已经不存在时,能够继续使用。称做closure(it remembers the context in which it was defined, and it uses that context whenever it is called) .
block内可以在之前环境已经消失的情况下,继续使用原始环境中的信息,只要在block中有这个变量存在过。
lambda {|n| thing * n} 返回一个Proc 实例。thing可以在首次调用后一直保存。
1 通过& 传一个block
2 调用Proc.new
3 调用Kernel.lambda
前2个是raw procs ,后一个更像free-standing method body .前两个得到的返回受block内部的return 影响,lambda则得到独立的代码块。
next 跳出该block并返回,对raw procs来说,break 跳出调用该block的method,都有返回值。
Containers, blocks, and iterators are core concepts in Ruby.
A. 定义method
method name小写开头,不然ruby会解析成常量
? ! = 是method 名字仅允许的几个不平凡的结尾
分别表示query, modify self(dangerous), assigmn.
参数名字也是小写,default value 可通过定义method时用赋值号= 给与。
method的body中还能继续定义method。method内是Ruby expressions。
* 开头的参数,表示不定长参数
& 开头的参数,会获得一个block
B. call
4要素:reciever (object, self, class or module),method name ,参数 , block
如果返回多个参数,就会以array的形式返回。
在调用时,* 开头的参数,起到了expanding的作用(定义是bundled)
在调用时,& 开头的参数,ruby认为这是一个Proc实例,proc实例可通过lambda 方法获取。
calc = lambda {|n| n*number} (1..10).collect(&calc).join(", ")
C. 传入hash (收集参数)
ruby不支持keyword arguments 的特性,而是使用hash来达到同样的效果。
ruby会自动把以 key=>value对收集 成一个hash并且作为一个参数传递 给method,只要这些pair跟随在普通参数后面、在* 和block 参数前面 。
Well-written: contain many methods, each quite small.
grouping together methods, classes, and constants.
1. provide a namespace
2. mixin facilty .
A. Namespace
Modules定义了namespace,隔开了中间的methods和constants。
module Trig PI = 3.141592654 def Trig.sin(x) # .. end end
使用时,require 'trig' ,require后面跟随的是小写的文件名 。然后的调用方法与调用class method如出一辙。
method前面加. ,常量前加:: .
B. Mixin
在module 中定义实例method ,这些method不能被module的对象使用,因为module不能实例化对象。
但是,class可以include module,在这之后,所有的module中的实例method都会混入 class中。因此叫做
mixin。
include 后面跟随的是大写的module 名。require要在include前被使用 。多个class include的module指向同一个地址,所以如果在某个class中改变了module的一个行为,那么将影响全部相关的class ,这点在运行时也是如此。
mixin中的method和class的method协作 起来,将是很具有威力的。其实可以理解成module定义一个钩子,include module后class负责实现这个钩子,然后module中的method使用这个钩子来完成很多例行函数,在混合后,这些函数的意义就跟着class走了。如枚举模块,如比较大小模块
module中的实例变量名可能会与class中有冲突。一般来说module自己没有状态,或者保证名字不会冲突。
method重载时,先本class,其次mixin,再次是superclass 和superclass的mixin。最后一个include的module被优先搜索。
C. 自动更新
load 在每次method中都会被执行,require 只load一次某个给定的文件。
所以可以用load来动态刷新自己,这是动态语言的一大好处,不必重启服务、不必重新定义新的版本。
require 使得可以使用文件中的内容,include则使得module中的方法变成了实例方法。