【问题标题】:An object can `respond_to` a message but raise an error when called?一个对象可以“respond_to”一条消息,但在调用时会引发错误?
【发布时间】:2016-04-07 01:05:55
【问题描述】:

我试过了:

1.respond_to? "clone"    # => true
1.clone                  # => TypeError: can't clone Fixnum

似乎一个对象可以报告它接受了一条消息,但直接引发了一个异常。

我正在尝试写一个deep_copy。是否有内置的或者某些代码 sn-ps 已经可以做到这一点?如果我需要决定某个东西是否可以克隆,我是否需要以任何方式调用它,然后从异常中rescue 知道它不是?

如果一个对象会引发异常,那么(1)报告false是否有意义,或者是由于Object提出的接口要求,以及(2)我可以告诉任何对象向respond_to "foo"报告虚假?

【问题讨论】:

  • A Fixnum 响应clone,因此1.respond_to?(:clone) 返回true 是有意义的。考虑一下:如果您编写了一个带有方法def foo; raise "Error!" end 的类,您是否希望该类的实例为respond_to(:foo) 返回true?我会。它是否引发错误并不重要。如果它引发了一个没有意义的 NoMethodError,但这里不是这种情况。
  • 换句话说,奇怪的不是respond_to?的行为,而是Kernel#clone的定义只是为了返回一个错误。
  • 如果您添加以下问题可能会很有趣:“为什么定义 clone 只是为了返回错误?它在什么用例中有帮助?”
  • @sawa return ≠ raise
  • Fixnum 的任何方法都不会改变对象 - 可能不需要支持 clone,因为它永远不需要。

标签: ruby clone deep-copy


【解决方案1】:

respond_to? == true 表示NoMethodError 不会加注。

但可能会引发其他错误。

如果要进行深度克隆,请使用

Marshal.load(Marshal.dump(obj_to_copy))

【讨论】:

  • Marshal 模块非常有用,但请注意:dump 在其参数是immutable 对象时不会引发异常。例如Marshal.load(Marshal.dump(33)) #=> 33,但33 不是自身的“深拷贝”。
  • 元帅能否像programmers.stackexchange.com/questions/306392/… 中那样处理这种情况,也就是说,如果对象拥有其他一些对象,而不是仅仅指向它们(如在图的节点对象中)
  • 您可以自己回答。试试看!
【解决方案2】:

考虑:

Fixnum.instance_method(:clone).owner
  #=> Kernel
Fixnum.ancestors
  #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Fixnum.included_modules
  #=> [Comparable, Kernel]

Fixnum 的实例响应 Fixnum 的所有实例方法,包括它从其祖先继承的方法。为了确保在 Fixnum 实例上调用每个方法(clone 是一个)时不会引发异常,语言需要不同的设计。

【讨论】:

    【解决方案3】:

    根据 Jordan 的相关评论创建社区 wiki 答案

    Fixnum 响应clone,因此1.respond_to?(:clone) 返回true 是有意义的。

    考虑一下,如果你用方法写了一个类

    def foo
       raise "Error!" 
    end
    

    您是否希望该类的实例为respond_to(:foo)? 返回true。答案是“是”。

    它是否引发错误并不重要。如果它引发了NoMethodError,那就没有意义了,但这里不是这样。

    【讨论】:

    • 在良好的 OOP 实践中是否真的如此,您不会更改对象可以响应的内容?事实上,有没有办法做到这一点?我觉得是因为一旦接口设置好了,我们就不想修改了,否则会违反类继承、接口继承、多态性
    猜你喜欢
    • 2012-12-04
    • 1970-01-01
    • 2019-02-26
    • 2020-07-21
    • 2014-02-24
    • 1970-01-01
    • 2020-01-04
    • 1970-01-01
    • 2022-06-11
    相关资源
    最近更新 更多