在Ruby中,某些方法带有一个问号(?
),它会问一个问题,例如include?
询问是否包含所讨论的对象,然后返回true / false。
但是,为什么有些方法带有感叹号(!
),而其他方法则没有呢?
这是什么意思?
在Ruby中,某些方法带有一个问号(?
),它会问一个问题,例如include?
询问是否包含所讨论的对象,然后返回true / false。
但是,为什么有些方法带有感叹号(!
),而其他方法则没有呢?
这是什么意思?
Answers:
通常,以结尾!
的方法表示该方法将修改其调用的对象。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类。它还可以帮助您跟踪代码中正在修改的内容。
save
and save!
inActiveRecord
感叹号意味着很多事情,有时候除了“这很危险,要小心”之外,您不能从中看出很多。
正如其他人所说,在标准方法中,它通常用于表示导致对象自身发生变异的方法,但并非总是如此。请注意,许多标准方法改变自己的接收器,并没有一个感叹号(pop
,shift
,clear
),以及一些方法与惊叹号不改变自己的接收器(exit!
)。例如,请参阅本文。
其他库可能会不同地使用它。在Rails中,感叹号通常意味着该方法将在失败时引发异常,而不是无声地失败。
这是一个命名约定,但是许多人以不同的方式使用它。在您自己的代码中,一个好的经验法则是在某个方法执行“危险”操作时使用它,特别是当存在两个具有相同名称的方法并且其中一个方法比另一个方法更“危险”时。“危险”几乎可以指任何东西。
此命名约定从Scheme中取消。
1.3.5命名约定
按照约定,总是返回布尔值的过程的名称通常以``?''结尾。这样的过程称为谓词。
按照约定,将值存储到先前分配的位置中的过程的名称(请参见第3.4节)通常以``!''结尾。这样的过程称为突变过程。按照惯例,未指定突变过程返回的值。
最准确地说是用Bang方法!是更危险或更令人惊讶的版本。有许多不带Bang突变的方法,例如.destroy
,一般情况下,只有在核心库中存在更安全替代方法的bang才存在。
例如,在Array上,我们有.compact
and .compact!
方法,这两种方法都会使数组发生变化,但是.compact!
如果数组中没有nil ,则返回nil而不是self,这比仅返回self更为令人惊讶。
我发现的唯一非突变方法是Kernel
,.exit!
这比.exit
因为SystemExit
进程关闭时无法捕获而引起的惊讶更令人惊讶。
Rails和ActiveRecord延续了这一趋势,因为它使用bang来产生更多的“令人惊讶”的效果,如.create!
在失败时引发错误。
从themomorohoax.com:
根据我的个人喜好,可以按以下方式使用爆炸声。
1)如果活动记录方法未按预期执行操作,则会引发错误。
2)活动记录方法保存记录或方法保存对象(例如,条带!)
3)方法会做一些“额外”的事情,例如张贴到某个地方或执行某些操作。
关键是:只有在真正考虑过是否有必要时才使用爆炸,以免其他开发人员不必检查为什么要使用爆炸。
爆炸为其他开发人员提供了两个提示。
1)调用方法后不必保存对象。
2)当您调用该方法时,数据库将被更改。
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!
不会返回新的字符串对象,而是将字符串替换为原位,从而将foo
变为小写。我建议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
以防万一我想再次访问原始值。
!
更改对象,而不是返回修改后的副本。
User.create!