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

时间:2009-03-04 20:02:28

标签: ruby methods naming-conventions immutability

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

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

这是什么意思?

10 个答案:

答案 0 :(得分:570)

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

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

这将输出:

a string

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

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类都遵循它。它还可以帮助您跟踪代码中修改的内容。

答案 1 :(得分:130)

感叹号意味着许多事情,除了“这很危险,要小心”之外,有时你不能说出很多东西。

正如其他人所说,在标准方法中,它通常用于表示一种方法,该方法会导致对象发生变异,但并非总是如此。请注意,许多标准方法更改其接收器并且没有感叹号(popshiftclear),并且某些带感叹号的方法不会更改其接收器({ {1}})。例如,请参阅this article

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

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

答案 2 :(得分:70)

此命名约定取自Scheme

  

1.3.5命名约定

     

按照惯例,程序的名称   总是返回一个布尔值   通常以“?”结尾。这样的程序   被称为谓词。

     

按照惯例,程序的名称   将值存储到之前的值   分配的位置(见3.4节)   通常以“!”结尾。这样的程序   被称为变异程序。通过   约定,由a返回的值   突变程序未指定。

答案 3 :(得分:23)

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

  

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

答案 4 :(得分:16)

来自themomorohoax.com:

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

  

1)如果方法没有,则活动记录方法会引发错误   它的意思是什么。

     

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

     

3)一种方法可以做一些“额外”的事情,比如某些地方的帖子,或者确实如此   一些动作。

重点是:当你真正考虑是否时,只能使用一声巨响 为了拯救其他开发者不得不烦恼,这是必要的 检查你使用爆炸的原因。

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

  

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

     

2)当你调用方法时,数据库将被更改。

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

答案 5 :(得分:16)

最准确的说法是用Bang!是dangeroussurprising版本的.destroy.exit!版本。有许多方法可以在没有Bang的情况下进行变异,例如.create!,并且通常方法只有在核心库中存在更安全的替代方法的爆炸。

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

我发现爆炸的唯一非变异方法是Kernel {{3}},这比.exit更令人惊讶,因为你无法抓住SystemExit过程正在结束。

Rails和ActiveRecord延续了这一趋势,因为它使用了更多“令人惊讶”的效果,如{{3}},这会在失败时引发错误。

答案 6 :(得分: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!,则foo会永久更改为小写。 downcase!不会返回新的字符串对象,而是替换字符串,将foo完全更改为小写。 我建议你不要使用downcase!,除非这是完全必要的。

答案 7 :(得分:1)

!

我喜欢把这看作是一种爆炸​​性的变化,它会破坏之前的一切。 Bang或感叹号表示您在代码中进行了永久保存的更改。

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

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

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

答案 8 :(得分:1)

被称为“破坏性方法”他们倾向于更改您所指对象的原始副本。

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]

答案 9 :(得分:0)

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

如果您不打算在您调用方法的变量上存储原始值,则仅使用!

我喜欢做类似的事情:

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

OR

foo = "word"
puts foo.capitalize

而不是

foo = "word"
foo.capitalize!
puts foo

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