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

但是为什么某些方法却带有感叹号标记(!)在其他地方没有?

是什么意思?

评论

同义词:爆炸,感叹号

接受的答案应更改为stackoverflow.com/a/612653/109618。参见wobblini.net/bang.txt和ruby-forum.com/topic/176830#773946-“爆炸符号表示”爆炸版本比非爆炸版本危险得多;小心处理“”“ -Matz

如果仅爆炸方法很危险,那么爆炸方法将是一个不错的设计选择。遗憾的是,它们不是,因此在记住什么是可变的和不可变的内容时,这成为令人沮丧的练习。

#1 楼

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

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


这将输出:

a string


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

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

评论


请非常小心-许多较小的库不遵循此约定。如果发生奇怪的事情,请经常替换obj.whatever!与obj = obj.whatever!解决它。非常沮丧。

–莎拉·梅(Sarah Mei)
09年3月4日在22:41

bang也用于在没有的方法不存在时引发异常的方法,例如:save and save!在ActiveRecord中

–生态
2011年10月4日15:22

@AbhilashAK保存!如果无法保存,则会引发错误。这与常规保存返回true / false的情况相反。

– BookOfGreg
2014年2月16日15:22

@tgamblin Ruby中有很多方法可以变异而不会发生刘海。甚至还有一些罕见的方法,它们不会发生爆炸,而是会发生一些令人惊讶的事情,例如引发错误或跳过错误。经常使用Bangs表示这是该方法的更特殊的版本,我认为这应该反映在您的答案中,因为它被标记为正确。

– BookOfGreg
14年2月16日在15:24

哈!我喜欢它。多么卑鄙的疯狂语言。

–黑暗无耻
2014年9月17日下午13:49

#2 楼

感叹号意味着很多事情,有时候除了“这很危险,要小心”之外,您不能从中看出很多。

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

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

这是一个命名约定,但是许多人以不同的方式使用它。在您自己的代码中,一个好的经验法则是在方法执行“危险”操作时使用它,尤其是当存在两个具有相同名称的方法并且其中一个方法比另一个方法更“危险”时。 “危险”几乎可以指任何东西。

#3 楼





1.3.5命名约定

按照惯例,始终返回布尔值的过程名称

通常以``?''结尾。这样的过程
被称为谓词。

按照惯例,将值存储在先前分配的位置中的过程的名称
(请参见第3.4节)
通常以``!''结尾。这样的程序称为变异程序。按照
约定,未指定
突变过程返回的值。


评论


+1对这个答案,因为有一个文档为给出了合理的解释!用法。真的很好答案史蒂文

–DavidSilveira
16 Dec 9'在15:54

谢谢@DavidSilveira!

–史蒂芬·休格(Steven Huwig)
17年1月6日在20:41

#4 楼

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


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


#5 楼

最准确地说是用Bang方法!是更危险或更令人惊讶的版本。有很多没有Bang突变的方法,例如.destroy,一般情况下,只有在核心库中存在更安全替代方法的bang。例如,在Array上,我们有.compact.compact!,这两种方法对数组进行突变,但是如果数组中没有nil,则.compact!返回nil而不是self,这比仅仅返回self更令人惊讶。

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

Rails和ActiveRecord继续保持这种趋势,因为它使用bang来产生更多的“令人惊讶”的效果,例如.create!,引发故障错误。

#6 楼

来自themomorohoax.com:

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


1)主动记录方法会引发错误如果该方法不执行
它说的那样。

2)主动记录方法将保存记录,或者方法将保存一个对象(例如strip!)

/>
3)方法可以做一些“额外”的事情,例如张贴到某个地方,或者做一些动作。


重点是:仅在真正考虑过是否有必要时才使用bang,以免其他开发人员不得不烦恼
您正在使用爆炸。

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


1)无需在调用方法。

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


http://www.themomorohoax.com/ 2009/02/11 /何时使用爆炸感叹号-rails方法后

#7 楼

简单的解释:

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!

#8 楼

!


我喜欢将其视为具有爆炸性的变化,它摧毁了一切。爆炸或感叹号表示您正在对代码进行永久保存。

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

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

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

#9 楼

被称为“破坏性方法”的方法往往会更改您所引用的对象的原始副本。

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]


#10 楼

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

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

我喜欢做类似的事情:

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




foo = "word"
puts foo.capitalize


代替

foo = "word"
foo.capitalize!
puts foo


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

评论


因为您的回答对任何方式都没有帮助。 “底线:!方法只是更改它们被调用的对象的值”只是不正确的。

–达尔文
16年8月8日在12:28

@Darwin它确实会更改对象的值。 !更改对象,而不是返回修改后的副本。

–查尔斯
16年8月8日在19:02

那么您认为这是什么呢? User.create!

–达尔文
16年8月9日在7:52



@Darwin在什么情况下? ActiveRecord?

–查尔斯
16年8月9日在23:29

是的,ActiveRecord。

–达尔文
16-8-10的7:34