为什么`可复制?`定义它的方式?

时间:2018-03-16 13:06:29

标签: ruby-on-rails ruby

我在Rails源代码中遇到过这个问题:

class Object
  def duplicable?
    true
  end
end

class NilClass
  begin
    nil.dup
  rescue TypeError    
    def duplicable?
      false
    end
  end
end

使用此代码,即使从对象中删除dup,该对象也会使用duplicable?响应true

我认为它可以重写为更简单的代码,如:

class Object
  def duplicable?
    repond_to?(:dup)
  end
end

使用duplicable? ... begin定义rescue的优点是什么?

2 个答案:

答案 0 :(得分:7)

  

使用duplicable? ... begin定义rescue的优点是什么?

在尝试nil.dup时,2.4之前的Ruby引发了一个TypeError:

$ rbenv local 2.3.0

$ ruby --version
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]

$ ruby -e 'p nil.dup'
-e:1:in `dup': can't dup NilClass (TypeError)
    from -e:1:in `<main>'

从Ruby 2.4开始,nil.dup只返回自己:

$ rbenv local 2.4.0

$ ruby --version
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]

$ ruby -e 'p nil.dup'
nil

将方法定义放在rescue中可确保仅为引发TypeError的Ruby版本定义该方法。

  

我认为它可以改写为更简单的代码,如:[...]

只需检查接收方是否响应dup不起作用,因为nil - Object - 确实回复dup ,即使在2.3。 TypeErrorObject#dup来自VALUE rb_obj_dup(VALUE obj) { VALUE dup; if (rb_special_const_p(obj)) { rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj)); } // ... }

round

答案 1 :(得分:2)

nil 回复 dup明确抛出TypeError(反过来,与NoMethodError无关。)[更正] :在2.4之前回复dup,积分转到@Stefan。]

NilClass.instance_method(:dup)
#⇒ #<UnboundMethod: NilClass(Kernel)#dup>

目标是使用duplicable? 回复false,除非 NilClass#dup被城市中的另一个猴子修补程序覆盖。 [更正:将“另一个猴子修补器”改为“Matz”:)]