Effective Ruby 要点回顾汇总(持续更新中)

1.理解Ruby中的True

  • 除了falsenil外所有值都表示真值。
  • 和很多语言不同,Ruby中的0值是真值。
  • 如果你需要区分falsenil,可以使用nil?方法或==操作符并将false作为左操作对象。

2.所有对象的值都可能为nil

  • 根据Ruby的类型系统运作方式,任何对象都可以为nil
  • 如果方法接受者是nilnil?方法返回真值,反之为假。
  • 在适合的时候使用转换方法,如to_sto_i,可以将nil对象强制转换为你期待的类型。
  • Array#compact方法返回去除所有nil元素的接受者的副本。

3.避免使用Ruby中古怪的Perl风格语法

  • 推荐使用String#match替代String#=~。前者将匹配信息以MatchData对象返回,而非几个特殊的全局变量。
  • 使用更长、更能表意的全局变量的别名,而非其短的、古怪的名字(比如,用$LOAD_PATH替代$:)。大多数长的名字需要在加载库English之后才能使用。
  • 避免使用隐式读写全局变量$_的方法(比如,Kernel#printRegexp#~等)。

4.留神,常量是可变的

  • 总是将常量冻结,从而防止其被改变。
  • 如果常量引用了一个集合对象比如数组或散列,那么冻结这个集合及其所有元素。
  • 要防止常量被重新赋值,可以冻结定义它的那个模块。

5.留意运行时警告

  • 使用命令行选项-w来运行Ruby解释器以启动编译时和运行时的警告。设置环境变量RUBYOPT-w也可以达到相同目的。
  • 如果必须禁用运行时的警告,可以临时将全局变量$VERBOSE设置为nil

6.了解Ruby如何构建继承体系

  • 要寻找一个方法,Ruby只需要向上搜索类体系。如果没有找到这个方法,就从起点开始搜索method_missing方法。
  • 包含模块时Ruby会悄悄地创建单例类,并将其插入在继承体系中包含它的类的上方。
  • 单例方法(类方法和针对对象的方法)储存在单例类中,它也会被插入继承体系中。

7.了解super的不同行为

  • 当你想重载继承体系中的一个方法时,关键字super可以帮你调用它。
  • 不加括号地无参调用super等价于将宿主方法的所有参数传递给要调用的方法。
  • 如果希望使用super并且不向重载方法传递任何参数,必须使用空括号,即super()
  • super调用失败时,自定义的method_missing方法将丢弃一些有用的信息。在第30条中有method_missing的替代解决方案。

8.初始化子类时调用super

  • 当创建子类对象时,Ruby不会自动调用超类中的initialize方法。作为替代,常规的方法查询规则也适用于initialize方法,只有第一个匹配的副本会被调用。
  • 当为显式使用继承的类定义initialize方法时,使用super来初始化其父类。在定义initialize_copy方法时,应使用相同的规则。

9.提防Ruby最棘手的解析

  • setter方法在调用时需要显式的接收者。没有接收者时,会被Ruby解析为变量赋值。
  • 在实例方法中调用setter方法时,使用self作为接收者。
  • 在调用非setter方法时,不需要显式指定接收者。换句话说,不要使用不必要的self,那会弄乱你的代码。

10.推荐使用Struct而非Hash存储结构化数据

  • 在处理结构化数据时,如果创建一个新类不那么合适时,推荐使用Struct而非Hash
  • Struct::new的返回值赋给常量,并像类一样使用它。

11.通过在模块中嵌入代码来创建命名空间

  • 通过在模块中嵌入代码来创建命名空间。
  • 让你的命名空间结构和目录结构相同。
  • 如果使用时可能出现歧义,可使用“::”来限定顶级常量(比如,::Array)。

12.理解等价的不同方法

  • 绝不要重载equal?方法。该方法的预期行为是,严格比较两个对象,仅当它们同时指向内存中同一对象时其值为真(即,当它们具有相同的object_id时)。
  • Hash类在冲突检测时使用eql?方法来比较键对象。默认实现可能和你想象不同。遵循第13条的建议之后再使用别名eql?来替代==书写更合理的hash方法。
  • 使用==操作符来测试两个对象是否表示相同的值。有些类比如表示数字的类会有一个粗糙的等号操作符进行类型转换。
  • case表达式使用===操作符来测试每个when语句的值。左操作数是when的参数,右操作数是case的参数。

13.通过“<=>”操作符实现比较和比较模块

  • 通过定义<=>操作符和引入Comparable模块实现对象的排序。
  • 如果左操作数不能与右操作数进行比较,<=>操作符应该返回nil
  • 如果要实现类的<=>运算符,应该考虑将将eql?方法设置为==操作符的别名,特别是当你希望该类的所有实例可以被用来作为哈希键的时候,就应该重载哈希方法。

14.通过protected方法共享私有状态