在 Ruby中,一些方法有?
一个问号(include?
但是为什么有些方法有感叹号(!
)而其他方法没有呢?
这是什么意思?
在 Ruby中,一些方法有?
一个问号(include?
但是为什么有些方法有感叹号(!
)而其他方法没有呢?
这是什么意思?
通常,以 结尾!
的方法表示该方法将修改它所调用的对象。Ruby 将这些称为“危险方法”,因为它们会更改其他人可能引用的状态。下面是一个简单的字符串示例:
foo = "A STRING" # a string called foo
foo.downcase! # modifies foo itself
puts foo # prints modified foo
这将输出:
a string
在标准库中,您会在很多地方看到成对的名称相似的方法,一个有 the !
,一个没有。没有的那些称为“安全方法”,它们返回原始副本的副本,并将更改应用于副本,而被调用者保持不变。这是没有 的相同示例!
:
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 类都遵循它。它还可以帮助您跟踪代码中的修改内容。
感叹号意味着很多东西,有时除了“这很危险,小心”之外,你无法从中看出很多东西。
正如其他人所说,在标准方法中,它通常用于表示导致对象自身发生变异的方法,但并非总是如此。请注意,许多标准方法会更改其接收器并且没有感叹号(pop
, shift
, clear
),而某些带有感叹号的方法不会更改其接收器(exit!
)。例如,请参阅这篇文章。
其他库可能会以不同的方式使用它。在 Rails 中,感叹号通常意味着该方法将在失败时抛出异常,而不是静默失败。
这是一个命名约定,但许多人以微妙不同的方式使用它。在您自己的代码中,一个好的经验法则是在方法执行“危险”操作时使用它,尤其是当存在两个同名方法并且其中一个比另一个更“危险”时。“危险”几乎可以意味着任何东西。
这个命名约定是从Scheme中提取的。
1.3.5 命名约定
按照惯例,总是返回布尔值的过程的名称通常以“?”结尾。这样的过程称为谓词。
按照惯例,将值存储到先前分配的位置(参见第 3.4 节)的过程的名称通常以“!”结尾。这样的过程称为突变过程。按照惯例,突变过程返回的值是未指定的。
!通常意味着该方法作用于对象而不是返回结果。来自《Programming Ruby 》一书:
“危险”或修改接收器的方法可能以结尾的“!”命名。
最准确的说法是用Bang 的方法!是更危险或更令人惊讶的版本。有许多方法在没有 Bang 的情况下发生变异,例如.destroy
,通常方法只有在核心库中存在更安全的替代方案时才有 bang。
例如,在 Array 上,我们有.compact
and .compact!
,这两个方法都会改变数组,但.compact!
如果数组中没有 nil,则返回 nil 而不是 self,这比仅返回 self 更令人惊讶。
我发现的唯一非变异方法是Kernel
's .exit!
,这比在进程关闭时.exit
无法捕获更令人惊讶。SystemExit
Rails 和 ActiveRecord 延续了这一趋势,因为它使用 bang 来获得更多“令人惊讶”的效果,比如.create!
在失败时会引发错误。
来自 themorohoax.com:
根据我的个人喜好,可以通过以下方式使用爆炸。
1) 如果方法没有按照它说的那样做,那么活动记录方法会引发错误。
2)活动记录方法保存记录或方法保存对象(例如strip!)
3) 一个方法做一些“额外的”事情,比如发帖到某个地方,或者做一些动作。
关键是:只有在你真正考虑过是否有必要时才使用 bang,以免其他开发人员不得不检查你为什么使用 bang。
爆炸为其他开发人员提供了两个线索。
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!
,除非它是完全必要的。
!
我喜欢将其视为一种爆炸性的变化,它摧毁了之前的一切。Bang 或感叹号表示您正在对代码进行永久保存的更改。
例如,如果您使用 Ruby 的全局替换方法,gsub!
那么您所做的替换是永久性的。
您可以想象的另一种方式是打开一个文本文件并进行查找和替换,然后保存。!
在你的代码中做同样的事情。
如果您来自 bash 世界,另一个有用的提醒是sed -i
具有永久保存更改的类似效果。
底线:!
方法只是更改它们被调用的对象的值,而没有!
返回操作值的方法不会覆盖调用该方法的对象。
仅!
当您不打算将原始值存储在您调用该方法的变量中时才使用。
我更喜欢做类似的事情:
foo = "word"
bar = foo.capitalize
puts bar
或者
foo = "word"
puts foo.capitalize
代替
foo = "word"
foo.capitalize!
puts foo
以防万一我想再次访问原始值。
称为“破坏性方法”它们倾向于更改您所指对象的原始副本。
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]