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

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

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

这是什么意思?

179979 次浏览

通常,以!结尾的方法表明该方法将修改调用它的对象。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类都遵循它。它还可以帮助您跟踪代码中修改的内容。

! 通常意味着方法作用于对象而不是返回结果。摘自Ruby编程这本书:

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

这个命名约定来自计划

1.3.5命名约定

根据约定,过程的名称 总是返回一个布尔值 通常以“?”结尾。这样的程序

根据约定,过程的名称 存储值到先前 已分配的位置(见3.4节) 通常以“!”结尾。这样的程序 叫做变异程序。通过 方法返回的值

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

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

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

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

从themomorohoax.com:

刘海有以下几种用法,依我个人喜好而定。

如果一个活动记录方法没有这样做,则会引发一个错误

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

一个方法做一些“额外的”事情,比如张贴到某个地方 一些行动。< / p >
关键是:只有当你真正想过是否要用砰的一声 这是必要的,可以省去其他开发人员不得不这样做的烦恼

.

.

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

1)表示调用对象后没有必要保存对象 方法。< / p >

2)当你调用这个方法时,db会被改变。

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

简单的解释:

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。downcase!将不会返回一个新的字符串对象,而是在适当的位置替换字符串,完全将foo改为小写。 我建议你不要使用downcase!,除非完全必要

它是最准确的说,方法与Bang!更多的是危险的令人惊讶的版本。有许多方法在没有Bang的情况下会发生突变,比如.destroy,通常情况下,方法只有Bang,而核心库中存在更安全的替代方案。

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

我发现的唯一非突变方法是Kernel.exit!,它比.exit更令人惊讶,因为当进程关闭时你无法捕获SystemExit

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

底线:!方法只是改变它们所调用的对象的值,而没有!的方法则返回一个经过操作的值,而不需要重写所调用方法的对象。

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

我喜欢这样做:

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

foo = "word"
puts foo.capitalize

而不是

foo = "word"
foo.capitalize!
puts foo

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

!

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

例如,如果你使用Ruby的方法进行全局替换# eyz0,你所做的替换是永久的。

你可以想象的另一种方式是,打开一个文本文件,进行查找和替换,然后保存。!在代码中做同样的事情。

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

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

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]

我的回答解释了在Ruby on Rails (RoR)模型验证的上下文中带有感叹号/shebangs的Ruby方法的重要性。

本质上,无论何时开发人员定义模型验证(这里介绍的),他们的最终目标是拒绝数据库记录更改&如果提交了无效数据来更新相关记录,则引发/抛出相关异常。

RoR ActiveRecord宝石定义各种模型操作方法(Ruby on Rails指南)。。在这些方法中,valid?方法是唯一一个无需数据库操作/修改就能触发验证的方法。其余的方法尝试更改数据库。

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

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