为什么Ruby方法中使用感叹号?

Len*_*nie 520 ruby methods naming-conventions immutability

在Ruby中,有些方法有一个问号(?),它会询问一个问题include?,询问是否包含有问题的对象,然后返回true/false.

但为什么有些方法会有感叹号(!)而其他方法却没有?

这是什么意思?

Tod*_*lin 593

通常,以end结尾!的方法表示该方法将修改它所调用的对象.Ruby将这些称为" 危险方法 ",因为它们会改变其他人可能引用的状态.这是一个简单的字符串示例:

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo
Run Code Online (Sandbox Code Playgroud)

这将输出:

a string
Run Code Online (Sandbox Code Playgroud)

在标准库中,有很多地方你会看到成对的同名方法,一个有一个!,一个没有.没有的那些被称为"安全方法",并且它们返回原始的副本,其中应用于副本的更改,被调用者不变.这是没有的相同示例!:

foo = "A STRING"    # a string called foo
bar = foo.downcase  # doesn't modify foo; returns a modified string
puts foo            # prints unchanged foo
puts bar            # prints newly created bar
Run Code Online (Sandbox Code Playgroud)

这输出:

A STRING
a string
Run Code Online (Sandbox Code Playgroud)

请记住,这只是一个约定,但很多Ruby类都遵循它.它还可以帮助您跟踪代码中修改的内容.

  • bang还用于在没有的情况下引发异常的方法,例如:`save`和`save!`在`ActiveRecord`中 (93认同)
  • @tgamblin Ruby中有很多方法可以在没有爆炸的情况下进行变异.甚至有一些罕见的方法不会随着爆炸变异,但做一些令人惊讶的事情,如引发错误或跳过错误.Bangs习惯说这是该方法更不寻常的版本,我认为这应该反映在你的答案中,因为它被标记为正确. (27认同)
  • 要非常小心 - 许多小型图书馆不遵循这一惯例.如果发生了奇怪的事情,通常会取代obj.whatever!与obj = obj.whatever!解决它.很沮丧. (22认同)
  • 我同意@BookOfGreg,请参阅https://www.ruby-forum.com/topic/176830#773946 (6认同)
  • @AbhilashAK [save!](http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save-21)如果无法保存则会引发错误.这与常规保存返回true/false相反. (3认同)
  • 还有退出与退出等情况!和(在轨道中)保存与保存! (2认同)
  • 哈!我喜欢它.多么疯狂的语言. (2认同)

Bri*_*per 135

感叹号意味着许多事情,除了"这是危险的,要小心"之外,有时你不能从中得到很多.

正如其他人所说,在标准方法中,它通常用于表示一种方法,该方法会导致对象自身变异,但并非总是如此.请注意,许多标准方法改变自己的接收器,并没有一个感叹号(pop,shift,clear),以及一些方法与惊叹号不改变自己的接收器(exit!).例如,请参阅此文章.

其他库可能使用不同的方式.在Rails中,感叹号通常意味着该方法将在失败时抛出异常而不是静默失败.

这是一个命名惯例,但许多人以微妙的方式使用它.在你自己的代码中,一个好的经验法则就是在方法执行"危险"操作时使用它,特别是当存在两个具有相同名称的方法且其中一个比另一个更"危险"时."危险"几乎可以表示任何意义.


Ste*_*wig 71

这个命名约定取自Scheme.

1.3.5命名约定

按照惯例,总是返回布尔值的过程名称通常以"?"结尾.这样的过程称为谓词.

按照惯例,将值存储到先前分配的位置(参见3.4节)的过程名称通常以"!"结尾.这种程序称为变异程序.按照惯例,突变过程返回的值未指定.

  • +1这个答案,因为有一个文件,给出了合理的解释!用法.真的很好回答史蒂文 (2认同)

Pes*_*sto 24

!通常意味着该方法作用于对象而不是返回结果.从Ruby编程:

"危险"或修改接收器的方法可能以尾随"!"命名.


Boo*_*reg 18

最准确的说方法是用Bang!是更危险或更令人惊讶的版本.有许多方法在没有Bang的情况下进行变异,.destroy并且通常方法只有在核心库中存在更安全的替代方案的方法.

例如,在阵列我们有.compact.compact!,这两种方法变异的数组,但.compact!返回nil自我,而不是如果没有零的数组中,这不仅仅是回归自我更令人惊讶.

我发现的唯一一种非变异方法是爆炸性Kernel.exit!,这比在过程结束时.exit你无法捕获更令人惊讶SystemExit.

Rails和ActiveRecord延续了这一趋势,因为它使用了更多"令人惊讶"的效果,例如.create!在失败时引发错误.


Edw*_*año 16

来自themomorohoax.com:

根据我的个人喜好,可以按照以下方式使用爆炸.

1)如果方法没有按照预期的方式执行,则活动记录方法会引发错误.

2)活动记录方法保存记录或方法保存对象(例如条带!)

3)一种方法可以做一些"额外"的事情,比如发布到某个地方,或做一些动作.

重点是:当你真正考虑是否有必要时,只使用一声巨响,以免其他开发人员烦恼,不得不检查你使用爆炸的原因.

爆炸为其他开发者提供了两个线索.

1)调用方法后没有必要保存对象.

2)当你调用方法时,db将被更改.

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods


Mir*_*age 6

简单说明:

foo = "BEST DAY EVER" #assign a string to variable foo.

=> foo.downcase #call method downcase, this is without any exclamation.

"best day ever"  #returns the result in downcase, but no change in value of foo.

=> foo #call the variable foo now.

"BEST DAY EVER" #variable is unchanged.

=> foo.downcase! #call destructive version.

=> foo #call the variable foo now.

"best day ever" #variable has been mutated in place.
Run Code Online (Sandbox Code Playgroud)

但是如果您downcase!在上面的解释中调用了一个方法,foo则会永久更改为downcase.downcase!不会返回一个新的字符串对象,而是替换该字符串,完全将其更改foo为downcase.我建议你不要使用,downcase!除非它是完全必要的.


小智 5

!
Run Code Online (Sandbox Code Playgroud)

我喜欢将其视为一种爆炸性的变化,它摧毁了之前的一切。爆炸或感叹号意味着您正在对代码进行永久保存的更改。

例如,如果您使用 Ruby 的方法进行全局替换,gsub!则您所做的替换是永久性的。

您可以想象的另一种方式是打开一个文本文件并进行查找和替换,然后保存。!在您的代码中执行相同的操作。

如果您来自 bash 世界,另一个有用的提醒是sed -i具有类似的永久保存更改的效果。