读《松本行弘的程序世界》

2015-07-29  本文已影响41人  orcl_zhang

断断续续花了很久才把这本书读完,内容比较杂,也不是特别深入,应该是从日常的文章汇总而成,有些内容还是值得一读。而且可以看出作者并没有仔细的整理这些内容,关于对象和块的章节重复和累赘部分很多,关于 Schewarzian Transform 也讲了很多次。

1 我为什么开发 Ruby

2 面向对象

用语 内容
单一继承 只有一个父类,单纯但存在几个问题
多重继承 多个父类,但引入了单一继承没有的新问题
静态语言(Java) 区分规格继承和实现继承
动态语言 只有实现继承
规格多重继承的问题 Java 的接口可以解决
实现多重继承的问题 Mix-in 可以解决
Mix-in 所有支持多重继承的语言都可以考虑使用
Ruby 的 Mix-in 强制使用模块,来解决多重继承的问题

3 程序块

def each(&block)
  i = 0
  while i < self.size
    block.call(self[i])
    i+=1
  end
end
def each()
  i=0
  while i < self.size
    yield self[i]
    i+=1
  end
end

块作为参数的优点:

  1. 明确表示了块处理;
  2. 块和对象一样被统一处理了;
  3. 检查参数是否为 nil 就可以判断是否传递了块参数。

yield 的优点:

  1. 没有用到闭包,执行速度稍快;
  2. 错误信息比较用一理解。

3.2.5 Enumerable 的局限(赞)

Enumerable 的两个主要缺点:

  1. 循环都依赖 each 方法,而且不能并行执行;
  2. 从多个对象取出元素进行处理比较难写。

用 Ruby 来定义 zip 方法的话,到目前为止,因为没有提供外部迭代器,所以只能在内部把参数变换成数组来对应。把参数作成数组,有以下两个问题:

  1. 大量的数据变换成数组会造成资源的浪费;
  2. 不能处理无限循环的 Enumerable。

代码部分:

module Enumerable
  def zip(*args)
    n = 0
    args = args.map{|a| a.to_a }
    self.each do |x|
      yield [x, *args.map{|a| a[n] }]
      n += 1
    end
  end
end

可以修改为:

module Enumerable
  def zip(*args)
    args = args.map{|a| a.enum_for(:each) }
    self.each do |x|
      yield [x, *args.map{|a|
        a.next rescue nil
      }]
     end
   end
end
  1. 不要变换成数组,而是用 enum_for 方法变换成以 each 为基础的 Enumerator。如果是 Ruby 1.8.7 ,这部分可以通过调用块的 each 方法来实现,但是如果这个类没有 each 方法,可能不返回 Enumerator。所以用 enum_for 方法才是安全的。
  2. 如果参数用数组可能会消耗很大内存。

4 设计模式

5 Ajax (建议粗读,内容有点老,而且也比较浅)

6 Ruby on Rails

6.2.3 猴子补丁技巧

** undef **
undef 有把方法定义取消的功能。用 undef 不仅可以取消本类中的方法,也可以取消父类中的方法。
** remove_method **
remove_method 仅取消本类中的方法。
alias
用 undef 或 remove_method 删除了以前方法后,别名的方法依然可以使用。别以 alias 只是起别名,而是重新定义了一个方法。

7 文字编码(不感兴趣可以跳过)

文字编码的难度还是很大的。

正则表达式(赞)(要比Ruby镐头书和元编程介绍的详细)

锚点 匹配位置
^ 行首
$ 行尾(若含换行,则是其前面的字符)
\A 字符串头
\Z 字符串尾(若含换行,匹配前一字符)
\z 字符串尾
\b 词头或词尾([] 外)
(?=) 用模式指定位置
(?!) 用否定模式制定位置

*贪婪与懒惰 **
这是一个经常讨论的问题,记得加 .

分组
使用向后引用的时候,因为要在内部保存数据,效率会受影响。如果仅仅为了分组,而不需要使用向后引用,可以使用没有向后饮用的模式括号(?:)。
锚点

锚点 匹配位置
^ 行首
$ 行尾(若含换行,则是其前面的字符)
\A 字符串头
\Z 字符串尾(若含换行,匹配前一字符)
\z 字符串尾
\b 词头或词尾([] 外)
(?=) 用模式指定位置
(?!) 用否定模式制定位置
选项 含义
i 不区分大小写
m 复数行匹配
o 只展开一次
x 无视正则表达式的空格,注释有效

选项

选项 含义
i 不区分大小写
m 复数行匹配
o 只展开一次
x 无视正则表达式的空格,注释有效

注释

/\d{4}-? #year
  \d{1,2}-? #month
  \d{1,2} #day
/x

8.1.7 特殊变量

$& 最后匹配字符串

8.1.9 split 的本质

str = "<ul><li>a</li>b</ul>"
str.split(/(<.*?>)/)
# ["", "<ul>", "", "<li>", "a", "</li>", "b", "</ul>"]

8.1.10 字符串扫描

"afdasfasdfads".scan(/fa./){|s| p s }

下面代码执行同样的动作。它不生成无用的数组,效率稍高一点。(谁能告诉我为什么?)

"afdasfasdfads".scan(/fa./).each{|s| p s }

8.1.11 置换

置换字符串

a = 'abbbcd'
a.gsub(/a(b+)/, "#{$1}") #wrong
a.gsub(/a(b+)/, "\1") #wrong
a.gsub(/a(b+)/, "\\1") #right
a.gsub(/a(b+)/, '\1') #right
a.gsub(/a(b+)/, '\\1') #right
a.gsub(/a(b+)/){ $1 } #right

居然'\1'和'\1'都可以!

上一篇 下一篇

猜你喜欢

热点阅读