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

Why are exclamation marks used in Ruby methods?

提问人:Lennie 提问时间:3/5/2009 最后编辑:dreftymacLennie 更新时间:10/3/2023 访问量:190188

问:

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

但是,为什么有些方法有感叹号(),而另一些方法没有呢?!

这是什么意思?

Ruby 方法 命名约 不可变性

评论

26赞 prusswan 7/3/2012
同义词:砰,感叹号
17赞 David J. 7/31/2012
接受的答案应更改为 stackoverflow.com/a/612653/109618。参见 wobblini.net/bang.txtruby-forum.com/topic/176830#773946 -- “爆炸标志的意思是”爆炸版本比非爆炸版本更危险;小心处理“” -Matz
3赞 Damien 9/4/2014
如果所有爆炸方法都是危险的,那么爆炸方法将是一个很好的设计选择。可悲的是,它们不是,因此在记住什么是可变的和什么是不可变的方面成为一项令人沮丧的练习。

答:

740赞 Todd Gamblin 3/5/2009 #1

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

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo

这将输出:

a string

在标准库中,有很多地方你会看到成对的类似名称的方法,一个有 the,一个没有。没有的方法称为“安全方法”,它们返回原始方法的副本,并对副本进行更改,被调用方保持不变。下面是相同的示例,没有:!!

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

这将输出:

A STRING
a string

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

评论

3赞 Andrew Grimm 3/5/2009
还有退出与退出等情况!并且(在 Rails 中)保存与保存!
33赞 Sarah Mei 3/5/2009
要非常小心 - 许多较小的库不遵循这个约定。如果发生奇怪的事情,经常替换 obj.whatever!使用 obj=obj.whatever!修复它。非常令人沮丧。
123赞 ecoologic 10/4/2011
bang 也用于在方法 without 不引发异常时引发异常的方法,例如: 和savesave!ActiveRecord
5赞 BookOfGreg 2/16/2014
@AbhilashAK save! 如果无法保存,则会引发错误。这与返回 true/false 的常规保存相反。
42赞 BookOfGreg 2/16/2014
@tgamblin Ruby 中有很多方法可以在没有刘海的情况下进行变异。甚至有一些罕见的方法不会一蹴而就,而是会做一些令人惊讶的事情,比如引发错误或跳过错误。刘海被用来表示这是该方法的更不寻常的版本,我认为这应该反映在您的答案中,因为它被标记为正确。
28赞 Pesto 3/5/2009 #2

!通常意味着该方法作用于对象,而不是返回结果。摘自 Programming Ruby 一书:

“危险”或修改接收器的方法可能用尾随的“!”命名。

92赞 Steven Huwig 3/5/2009 #3

此命名约定已从 Scheme 中解除。

1.3.5 命名约定

按照惯例,程序的名称 始终返回布尔值 通常以 ''?'' 结尾。此类程序 称为谓语。

按照惯例,程序的名称 将值存储到以前的 分配的位置(参见第 3.4 节) 通常以 ''!'' 结尾。此类程序 称为突变程序。由 convention,则返回的值 突变程序未指定。

评论

4赞 DavidSilveira 12/9/2016
+1 到这个答案,因为有一个文档可以对 !用法。非常好的答案史蒂文
180赞 Brian Carper 3/5/2009 #4

感叹号意味着很多事情,有时除了“这很危险,要小心”之外,你无法从中看出很多东西。

正如其他人所说,在标准方法中,它通常用于指示导致对象自身变异的方法,但并非总是如此。请注意,许多标准方法会更改其接收器并且没有感叹号 (, , ),并且某些带有感叹号的方法不会更改其接收器 ()。例如,请参阅此文章popshiftclearexit!

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

这是一种命名约定,但许多人以微妙不同的方式使用它。在你自己的代码中,一个好的经验法则是,每当一个方法正在做一些“危险”的事情时,就使用它,特别是当存在两个同名的方法,其中一个比另一个更“危险”时。不过,“危险”几乎可以意味着任何事情。

20赞 Edward Castano 9/9/2011 #5

来自 themomorohoax.com

Bang 可以按以下方式使用,按我个人喜好的顺序使用。

  1. 如果活动记录方法不执行此操作,则该方法将引发错误 它说什么,它会。

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

  3. 方法执行一些“额外”操作,例如发布到某个位置,或者执行 一些行动。

关键是:只有在你真正考虑过是否 这是必要的,以节省其他开发人员不得不的烦恼 检查你为什么要使用爆炸。

爆炸为其他开发人员提供了两个线索。

  1. 调用 方法。

  2. 调用该方法时,数据库将被更改。

6赞 Mirage 9/14/2013 #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.

但是,如果您曾经在上面的解释中调用过某个方法,则会永久更改为小写。 不会返回新的字符串对象,而是将字符串替换到原位,完全更改为小写。 我建议你不要使用,除非完全必要。downcase!foodowncase!foodowncase!

26赞 BookOfGreg 2/16/2014 #7

最准确地说,方法与砰!是更危险更令人惊讶的版本。有许多方法可以在没有 Bang 的情况下发生变异,例如 .destroy,一般来说,只有在核心库中存在更安全的替代方案时,方法才会发生 Bang。

例如,在 Array 上,我们有 和 ,这两种方法都会改变数组,但如果数组中没有 nil,则返回 nil 而不是 self,这比仅仅返回 self 更令人惊讶。.compact.compact!.compact!

我发现的唯一一个非突变方法是's .exit!,这比因为在进程关闭时无法捕捉更令人惊讶。Kernel.exitSystemExit

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

2赞 Charles 7/24/2015 #8

底线:方法只是更改它们被调用的对象的值,而没有的方法返回一个作的值,而不写出调用方法的对象。!!

仅当您不打算将原始值存储在调用该方法的变量中时才使用。!

我更喜欢做这样的事情:

foo = "word"
bar = foo.capitalize
puts bar

foo = "word"
puts foo.capitalize

而不是

foo = "word"
foo.capitalize!
puts foo

以防万一我想再次访问原始值。

评论

1赞 Darwin 8/8/2016
因为你的回答没有任何帮助。“底线:!方法只是更改它们被调用的对象的值“是不正确的。
0赞 Charles 8/9/2016
@Darwin它确实会更改对象的值。 改变对象,而不是返回修改后的副本。!
0赞 Darwin 8/9/2016
那么你认为这有什么作用呢?User.create!
1赞 Darwin 8/10/2016
这里有一个更好的论据来解释为什么你的答案是完全错误的。阅读 Matz 对 bang 的评论“!”。ruby-forum.com/topic/176830#773946。你还觉得你的“底线:!方法只是改变它们被调用的对象的值“在任何方面都是真的,所以曾经吗?
1赞 Charles 8/11/2016
@Darwin:完全正确?不,我现在明白了。“有什么办法吗?”是的。修改其参数或调用方法的对象显然是“危险的”——这是不言而喻的;任何改变其任何参数的方法都是危险的,因为您可能会丢失数据。我承认:我被教导要修改它的对象,我从来没有真正质疑过这一点。所以我为此感谢你。!!
5赞 Charlie Wood 4/3/2017 #9
!

我喜欢把这看作是一个爆炸性的变化,它摧毁了之前的一切。砰砰声或感叹号表示您正在对代码进行永久保存的更改。

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

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

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

1赞 Mittinti Ramana Murthy 5/23/2017 #10

称为“破坏性方法”,它们倾向于改变你所指对象的原始副本。

numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers   # returns [nil,nil,nil,nil,nil]
1赞 Curiousone 11/27/2022 #11

我的回答解释了在(RoR)模型验证的背景下,带有感叹号/shebangs的方法的重要性。RubyRuby on Rails

从本质上讲,每当开发人员定义模型验证(此处解释)时,他们的最终目标是拒绝数据库记录更改并引发/抛出相关异常,以防提交无效数据以更新相关记录。

RoR gem 定义了各种模型操作方法(Ruby on Rails 指南)。在这些方法中,该方法是唯一一个无需数据库操作/修改即可触发验证的方法。其余方法将尝试更改数据库。ActiveRecordvalid?

这些方法在运行时触发回调。列表中的一些方法具有带有 shebang 的姊妹方法。两者有什么区别?它与每当记录验证失败时返回的回调形式有关。

没有感叹号/shebang 的方法仅在记录验证失败时返回布尔值 false,而带有 shebang 的方法引发/抛出异常,然后可以在代码中适当地处理该异常。

0赞 napster235 2/6/2023 #12

只是提醒一下,因为我自己也经历过。

在 Ruby 中,改变对象并返回它。否则它将返回 .!nil

因此,例如,如果您正在对数组进行某种操作,并调用该方法并且没有 nothig 进行压缩,它将返回 ..compact!nil

例:

arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]

Run again arr.compact!
=> nil

如果您需要在下一行使用它,最好再次显式返回数组,否则您将获得该值。arrnil

例:

arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array
0赞 shivani gupta 10/3/2023 #13

0

方法名称末尾的感叹号 (“!”) 是一种命名约定。它们指示该方法可能更危险,执行破坏性操作,或者可以修改它所调用的对象。这是一种提醒开发人员注意方法的特殊行为的方法。感叹号在 Ruby 语言本身中没有特定的含义,但在社区中被广泛使用,以暗示对象的潜在副作用或修改。

示例:def sort!(数组) array.sort!结束

数字 = [3, 1, 2] 排序!(numbers) put numbers.inspect # 输出: [1, 2, 3]

那种!方法对数组进行就地排序并修改原始数字数组。感叹号表示此方法更改了它所操作的对象。