微信号:rigongyizu365

介绍:一线码农不端不装的「日拱一卒」,关注技术、书籍、创业、GTD、以及一切个人成长周边的话题,每周一到五更新.

集合的使用技巧(一) | Ruby

2016-09-09 23:52 lazybios

在改变作为参数的集合之前复制它们

多数对象(除Fixnum)都是通过引用而不是通过实际值来传递的。当将这种类型的对象插入容器时,集合类实际存储着该对象的引用而不是对象本身。并且当对象以方法参数的形式传递时,该法则依然成立,调用方法会接收到该对象的引用而非副本。

class Turner
  def initialize(presets)
    @presets = presets
    clean
  end

  private
  def clean
    @presets.delete_if {|f| f[-1].to_i.even?}
  end
end

presets = %w(90.1 106.2 88.5)

turner = Turner.new(presets)

presets
#=> ['90.1', '88.5']

上面的代码执行后,虽然clean执行成功,但作用域外的presets的值也被改变了。显然这不是我们想要的结果。所以,为了杜绝这样的情况出现,我们需要在方法执行破坏性操作之前先复制一份出来。

Ruby自带的对象复制方法有dupclone,多数情况下我们会使用dup方法,二者区别如下:

  • clone会拷贝单例方法,dup不会

  • clone可以对fronzen对象进行拷贝,并且返回冻结装状态的对象,但dup不会

所以上面代码中的initialize方法可以修改成,如下:

  def initialize(presets)
    @presets = presets.dup
    clean
  end

使用Kernel#Array将nil与标量对象转换成数组

因为Ruby里经常用鸭子类型,所以原则上只要某个对象可以对某个指定调用方法和参数做出响应就可以直接按照期望的那个对象来对待。基于此假设你有一个方法,期望参数是一个数组集合,但事实上直到你传输参数那一瞬间,你才能确定到它是不是数组,这样会给程序代理很多不确定性,它有可能是数组以外的任何值。

class Pizza
  def initialize(toppings)
    toppings.each do |topping|
      add_and_price_topping(topping)
    end
  end
  ...
end

有两个方法可以减少这种不确定性。一种是通过将参数类型显示的修改为*toppings,来表明传输initialize方法中的是数组,另一个是在方法体中通过Kernel#Array方法来人为显示把toppings转换成数组: Array(toppings).each do |topping|

-待续-

参考引用


 
日拱一卒 更多文章 Objective-C中的块(block)语法初步 MPMoviePlayerController视频播放器初步 UIViewController(视图控制器)的生命周期 关于SQL中的Join Vim中的搜索与替换
猜您喜欢 PHP7今天要正式发布了 FPGA:下一代机器人感知处理器 正规的足疗店(HTTPS服务)需要注意的几个细节 五年高考,三年模拟 | 来做道语文阅读理解 才云 CEO 张鑫将应邀出席CCUC2016并演讲《生产环境中使用Docker的运维实践》