`
swachian
  • 浏览: 73522 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

笔记2

阅读更多

1. Classes and Modules

classes and objects are both the highest-level constructs(构造) in Ruby and the essential underpinnings(支柱 支撑) of the entire language

成语言的基础,使用语言的最高一级单位。

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。

 

  • In Ruby, classes are very open and object state is rather close
  • 在class内而在instance method外时,self指向当前class(即当前定在定义的class是当前的object).

          在instance method内饰,self指向该class的一个实例。

  • 4种定义class method的形式,两种是利用self替换class的名字
  • private method不能指定reciever,只能在instance method(包括子类)中被调用,只有让self默默接收。

          而protected则能在class或者subclass范围内指定某个reciever

  • private_class_method :new 可把一个class_method私有化
  • send 和instance_eval不受private的影响

 

 

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模式,主要完成了两件事情:

  • private化诸如new之类的方法
  • 创建一个class_method instance,所有的该类的实例都通过instance方法来创建

G. Constants

 

1. 定义在某个module或者class之内的constant,在内部使用时可以什么都不加,在其他地方使用时给出::并带有对应module或class的名称。

2.不定义在任何module或者class之内的变量,可直接使用,前面不用加任何东西。实际上该const属于Object.


4. Containers and Block

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.

 

6. More on Methods


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.

 

 

 

9. Modules

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中的方法变成了实例方法。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics