【问题标题】:What is the purpose of "!" and "?" at the end of method names?“!”的目的是什么?和 ”?”在方法名称的末尾?
【发布时间】:2011-11-02 23:43:09
【问题描述】:

有时我会在 Ruby 中看到带有“?”的方法。和 ”!”在它们的末尾,例如:

name = "sample_string"
name.reverse
name.reverse!
name.is_binary_data?

我想知道他们的目的是什么?它们只是语法糖衣吗?

【问题讨论】:

标签: ruby methods syntax predicate syntactic-sugar


【解决方案1】:

问号表示该方法返回布尔值。已经在这里回答了:

What does the question mark operator mean in Ruby?

bang 表示该方法作用于对象本身。已经在这里回答了:

Why are exclamation marks used in Ruby methods?

【讨论】:

    【解决方案2】:

    为了可读性,它“只是糖衣”,但它们确实具有共同的含义:

    • ! 结尾的方法执行一些永久性或潜在危险的更改;例如:
      • Enumerable#sort 返回对象的排序版本,而 Enumerable#sort! 将其排序。
      • 在 Rails 中,ActiveRecord::Base#save 在保存失败时返回 false,而 ActiveRecord::Base#save! 会引发异常。
      • Kernel::exit 导致脚本退出,而Kernel::exit! 立即退出,绕过任何退出处理程序。
    • ? 结尾的方法返回一个布尔值,这使得代码流更加直观,就像一个句子——if number.zero? 读作“如果数字为零”,但if number.zero 看起来很奇怪。

    在您的示例中,name.reverse 的计算结果为反向字符串,但只有在 name.reverse! 行之后,name 变量才真正包含反向名称。 name.is_binary_data? 看起来像“name 是二进制数据吗?”。

    【讨论】:

    • 一个重要的注意事项是,如果您也有相应的非 bang 方法,那么您应该只有一个 bang 方法。爆炸用于区分“更令人惊讶”的方法版本和“不那么令人惊讶”的方法。如果您只有一种方法,则无需区分,也不应以爆炸式命名。例如,请参阅Array#clear。它清除数组。清除数组自然会改变它。这并不奇怪,这个名字已经很清楚了,因此:没有爆炸。见ruby-forum.com/topic/176830#773946
    • 根据Ruby Style Guide,添加@JörgWMittag 所说的内容:潜在危险方法的名称(即修改自身或参数的方法,退出!(不运行终结器,如退出) ) 等) 应以感叹号结尾如果存在该危险方法的安全版本
    • 请注意,情况并非总是如此。例如,Ruby Array#concat docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat。 MyActiveRecordModel.column_names.concat(...) 之类的东西会让你被严重烧伤。相反,您必须在执行 concat 之前克隆它。
    【解决方案3】:

    在 Ruby 中,? 表示该方法将返回一个布尔值,! 修改了它被调用的对象。在查看代码时,它们可以提高可读性。

    【讨论】:

      【解决方案4】:

      与 - 我想 - 大多数编程语言相比......

      Ruby,方法允许以问号或感叹号结尾。

      按照惯例,回答问题的方法(即 Array#empty? 如果接收者为空则返回 true)以问号结尾。

      按照惯例,可能是“危险”的方法(即修改 self 或参数、exit!等的方法)以感叹号结尾。

      来自:http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/有趣的方法名称部分

      【讨论】:

      • ?结尾的方法也称为谓词方法。
      【解决方案5】:

      请注意,情况并非总是如此。以 Ruby Array#concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat 为例。

      MyActiveRecordModel.column_names.concat([url]) 之类的东西可能会让你被严重烧伤。稍后与 MyActiveRecordModel 相关的调用将尝试为 MyActiveRecordModel 查找“url”列并抛出。

      相反,您必须在执行 concat 之前克隆它。幸运的是我的测试套件抓住了这个,但是.. 抬头!

      【讨论】:

        猜你喜欢
        • 2015-11-14
        • 2010-11-23
        • 1970-01-01
        • 2020-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-10
        • 2015-10-28
        相关资源
        最近更新 更多