在Ruby中,有些方法带有问号(?),会问include?询问是否包含有问题的对象,然后返回true/false。
但是为什么有些方法有感叹号(!)而其他方法没有呢?
这是什么意思?
在Ruby中,有些方法带有问号(?),会问include?询问是否包含有问题的对象,然后返回true/false。
但是为什么有些方法有感叹号(!)而其他方法没有呢?
这是什么意思?
当前回答
被称为“破坏性方法”,它们倾向于改变你所引用的对象的原始副本。
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中,!改变对象并返回它。否则它将返回nil。
因此,如果你正在对一个数组进行某种操作,并调用方法.compact!没有东西要压缩,它会返回nil。
例子:
arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]
Run again arr.compact!
=> nil
如果你需要在一行中使用数组arr,最好再次显式返回它,否则你将得到nil值。
例子:
arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array
感叹号意味着很多事情,有时你除了“这很危险,小心”外,你无法从它身上看出很多东西。
正如其他人所说,在标准方法中,它通常用于指示导致对象自身变异的方法,但并不总是如此。请注意,许多标准方法更改了它们的接收器,并且没有感叹号(pop、shift、clear),并且一些带有感叹号的方法不更改它们的接收器(exit!)。例如,请参阅这篇文章。
其他库可能以不同的方式使用它。在Rails中,感叹号通常意味着该方法将在失败时抛出异常,而不是无声地失败。
这是一种命名惯例,但许多人以微妙的不同方式使用它。在你自己的代码中,一个好的经验法则是当一个方法做了一些“危险”的事情时使用它,特别是当存在两个同名的方法,其中一个比另一个更“危险”时。“危险”几乎可以指任何事情。
通常,以!结尾的方法指示该方法将修改调用它的对象。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类都遵循它。它还可以帮助您跟踪代码中修改的内容。
底线:!方法只改变被调用对象的值,而没有!返回一个被操纵的值,而不重写调用该方法的对象。
只用!如果您不打算将原始值存储在调用方法的变量中。
我喜欢这样做:
foo = "word"
bar = foo.capitalize
puts bar
OR
foo = "word"
puts foo.capitalize
而不是
foo = "word"
foo.capitalize!
puts foo
以防万一我想再次访问原始值。
它是最准确的说,方法与Bang!是更危险或更令人惊讶的版本。有很多方法在没有Bang的情况下会发生突变,比如.destroy,通常情况下,方法只有Bang,而核心库中存在更安全的替代方法。
例如,在Array中,我们有.compact和.compact!,这两个方法都会改变数组,但是.compact!如果数组中没有nil则返回nil而不是self,这比只返回self更令人惊讶。
我发现唯一的非突变方法是Kernel的.exit!这比.exit更令人惊讶,因为你无法在进程关闭时捕获SystemExit。
Rails和ActiveRecord延续了这一趋势,因为它使用bang来实现更多“令人惊讶”的效果,如.create!这会在失败时产生错误。