为什么在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类都遵循这个约定。 它还可以帮助您跟踪代码中正在修改的内容。
感叹号意味着很多东西,除了“这是危险的,要小心”之外,有时你不能从中说出很多。
正如其他人所说的那样,在标准方法中,它经常被用来指示一个方法导致一个对象自我变异,但并不总是如此。 请注意,许多标准的方法改变他们的接收器,并没有感叹号( pop
, shift
, clear
),有些感叹号的方法不会改变他们的接收器( 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
有这种类似的效果,使永久保存的变化。