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

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

但是为什么有些方法在别人没有的地方有感叹号( ! )呢?

这是什么意思?

一般来说,方法结束于! 表明该方法将修改它所调用的对象 。 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类都遵循这个约定。 它还可以帮助您跟踪代码中正在修改的内容。

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

正如其他人所说的那样,在标准方法中,它经常被用来指示一个方法导致一个对象自我变异,但并不总是如此。 请注意,许多标准的方法改变他们的接收器,并没有感叹号( popshiftclear ),有些感叹号的方法不会改变他们的接收器( exit! )。 例如见这篇文章 。

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

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

这个命名约定从Scheme中解除。

1.3.5命名约定

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

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

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

“危险的”或者修改接收者的方法可以用尾部的“!”来命名。

来自themomorohoax.com:

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

1)一个活跃的记录方法会产生一个错误,如果该方法没有做它说的话。

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

3)一个方法做一些额外的事情,比如发布到某个地方,或者采取一些行动。

重点是:只有在真正考虑是否有必要的时候才能使用,以免其他开发者烦恼不得不检查你为什么使用爆炸。

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

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

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

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

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

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

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

Rails和ActiveRecord继续这个趋势,因为它使用一些更令人惊讶的效果,比如.create! 这在失败时会引起错误。

简单的解释:

 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。 我建议你不要使用downcase! 除非完全有必要。

被称为“破坏性方法”他们往往会改变你所指的对象的原始副本。

 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] 

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

只用! 如果你不打算需要存储在你调用该方法的变量的原始值。

我更喜欢做一些事情:

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

要么

 foo = "word" puts foo.capitalize 

代替

 foo = "word" foo.capitalize! puts foo 

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

 ! 

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

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

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

另一个有用的提醒,如果你来自bash世界sed -i有这种类似的效果,使永久保存的变化。