【问题标题】:Why do some Ruby methods need a bang and others don't to be a destructive method?为什么一些 Ruby 方法需要爆炸,而另一些不需要破坏性方法?
【发布时间】:2014-10-07 05:37:28
【问题描述】:

例如,array.pop 不需要 bang 来永久更改数组。为什么会这样?开发这些特定的 Ruby 方法背后的原因是什么?

【问题讨论】:

  • 一般情况下是 ruby​​ 还是 Rails 或 Rails 的某些子集,如 ActiveRecord?
  • 这个约定通常在 Ruby 社区中使用。

标签: ruby methods


【解决方案1】:

Bang 方法最常用于区分同一方法的危险版本和安全版本。以下是一些可能需要区分 bang/no-bang 组合的示例:

  • mutator 方法 - 一个版本更改对象,另一个版本返回副本并保持原始对象不变
  • 遇到错误时,一个版本会抛出异常,而另一个版本只会将错误消息写入日志或不执行任何操作

但是,如果只有一个版本是有意义的,则惯例是不使用。例如,poping 一个数组而不实际更改它是没有意义的。在这种情况下,它最终会是一个不同的操作:Array#last。许多方法会更改它们被调用的对象,例如 setter。我们也不需要一气呵成地写这些,因为很明显它们会改变对象。

最后,有一些例外情况,一些开发人员可能会使用 bang 方法而没有实现无 bang 对应项。在这些情况下,bang 只是用作使方法调用在视觉上突出的一种方式。例如:

  • 该方法会做一些危险或破坏性的事情
  • 该方法做了一些意想不到的事情
  • 该方法对性能有显着影响

【讨论】:

  • 此外,一些框架扩展了使用 ! 的约定,以表示“做一些你可能没想到的事情”——因此,旨在通过有条件地引发异常或无参数持久性变体来控制流程的方法(例如model_object.activate!)。但是,这些有时是单个开发团队对约定的想法,而不是 Ruby 范围内的。
  • 这部分不正确。虽然您所说的pop 是准确的,但! 后缀并不意味着某些东西是突变体,而是意味着它很危险。请参阅我的回答和我的ActiveRecord::Base#save! 示例。
  • @NeilSlater 非常有用的评论。此外,我看到 bang 方法被用来表示该方法可能会对性能产生重大影响。
  • 感谢您的建议,我已尝试改进我的答案。
【解决方案2】:

bang 用于区分同一方法的危险版本和不太危险的版本。 pop方法只有一个,所以没什么好区分的。

注意:方法的名称与它的作用完全无关。一个方法是否具有破坏性取决于它执行的代码,而不是它的名称。

【讨论】:

    【解决方案3】:

    bang 在 Ruby 中的意思是“小心”。这意味着您应该谨慎使用该方法,仅此而已。我再也找不到参考资料了,但权威人士明确表示 bang ≠ 破坏性方法。 Bang 只是一个与谨慎相关的语义元素。程序员可以权衡一切并决定何时使用 bang。

    例如,在我的模拟 gem 中,我使用#step 方法来获取步长。

    simulation.step #=> 0.42
    

    step! 方法来实际执行模拟步骤。

    simulation.step! #=> takes the simulation to the next time step
    

    但是对于#reset的方法,我觉得“reset”这个词已经够啰嗦了,没必要用bang来警告用户模拟状态会被破坏:

    simulation.reset #=> resets the simulation back to the initial state
    

    P.S.:现在我记得,曾几何时,Matz 半开玩笑地说,他后悔将带有 bang 的方法引入 Ruby,因为 bang 在语义上是如此模棱两可。

    【讨论】:

      【解决方案4】:

      ! 的后缀意味着一个方法是另一个方法的危险版本。例如,save!save 的危险版本。危险可能意味着在适当的位置进行编辑、执行更严格的错误等。在危险的方法上不需要使用! 后缀,但不需要更安全的对应方法。此外,这只是一个命名约定,因此 Ruby 不会限制方法是否以 ! 结尾时可以做什么和不可以做什么。

      有一个普遍的误解,即每个编辑就地内容的方法都应该以! 结尾。这不是真的,! 仅在已经存在的方法的更危险版本时才需要,这并不一定意味着危险方法编辑到位。例如,在 Rails 中,ActiveRecord::Base#save! 是执行验证的ActiveRecord::Base#save 的一个版本。

      【讨论】:

      • Ruby 是否定义了Array#pop!
      • 这就是重点。不,Ruby 没有 Array#pop! 方法。
      • 不,因为Array#pop 已经很危险,因为它可以就地编辑,不需要危险版本。
      • @NicolasMcCurdy 你的第二句话暗示pop! 方法确实存在......我会使用除了pop right there之外的一个例子
      • 糟糕,我没听清。我现在已经更新了我的答案。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 2023-03-29
      相关资源
      最近更新 更多