Rubyメソッドで感嘆符が使用されるのはなぜですか?


540

Rubyの一部のメソッドには、問題のオブジェクトが含まれているかどうか?を尋ねる疑問符()がありinclude?ます。これにより、true / falseが返されます。

しかし、なぜ一部のメソッドには感嘆符(!)があるのに、他のメソッドにはないのですか?

どういう意味ですか?


21
同義語:感嘆符、感嘆符
prusswan 2012

17
受け入れられた回答は、stackoverflow.com / a / 612653/109618に変更する必要があります。wobblini.net/bang.txtおよびruby-forum.com/topic/176830#773946を参照してください-「強打の記号は、強打のバージョンが強打のバージョンよりも危険であることを意味します。取り扱いに注意してください」 "-Matz
David J.

2
bangメソッドは、すべての bangメソッドが危険である場合にのみ、優れた設計の選択肢になります。悲しいことに、それらはそうではないので、何が変更可能で何が変更可能でないかを記憶することはイライラする練習になります。
Damien Roche

回答:


617

一般に、末尾!がのメソッドは、メソッドが呼び出されたオブジェクト変更することを示します。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クラスの多くはこれに準拠しています。また、コードで何が変更されているかを追跡するのにも役立ちます。


2
出口と出口のようなケースもあります!そして(レールで)保存と保存!
アンドリューグリム

24
細心の注意を払ってください-多くの小さなライブラリはこの規則に従っていません。奇妙なことが起こっている場合、しばしばobj.whateverを置き換えます!obj = obj.whatever!それを修正します。とてもイライラします。
サラメイ

101
強打は、例外を発生させる方法に使用する場合の方法なしていない、例えば:savesave!ActiveRecord
ecoologic

3
@AbhilashAK 節約!保存できない場合はエラーが発生します。これは、true / falseを返す通常の保存とは対照的です。
BookOfGreg 2014

31
@tgamblin Rubyには、前髪なしで変化するメソッドがたくさんあります。まれに、強打で変更されないが、エラーを発生させたり、エラーをスキップしたりする驚くべき方法もあります。前髪は、これがメソッドのより珍しいバージョンであると言うために使用され、正しいとマークされているので、これはあなたの答えに反映されるべきだと思います。
BookOfGreg 2014

143

感嘆符は多くのことを意味し、「これは危険ですので、注意してください」以外は多くのことを区別できない場合があります。

他の人が言ったように、標準的なメソッドでは、オブジェクトがそれ自体を変異させるメソッドを示すためによく使用されますが、常にそうではありません。多くの標準的な方法は、自分の受信機を変更し、(感嘆符を持っていないことを注意popshiftclear)、および感嘆符といくつかの方法が(自分の受信機を変更しないでくださいexit!)。たとえば、この記事を参照してください。

他のライブラリはそれを異なって使用するかもしれません。Railsでは感嘆符は多くの場合、メソッドがエラーなしで失敗するのではなく、失敗時に例外をスローすることを意味します。

これは命名規則ですが、多くの人が微妙に異なる方法で使用しています。独自のコードでは、特に同じ名前の2つのメソッドが存在し、そのうちの1つが他のメソッドよりも「危険」な場合に、メソッドが「危険」なことをしているときはいつでもそれを使用することをお勧めします。「危険」はほとんど何でも意味します。


75

この命名規則は、Schemeから削除されました。

1.3.5命名規則

慣例により、常にブール値を返すプロシージャの名前は通常「?」で終わります。このような手続きは述語と呼ばれます。

慣例により、以前に割り当てられた場所(セクション3.4を参照)に値を格納するプロシージャの名前は、通常「!」で終わります。このような手順は突然変異手順と呼ばれます。慣例により、ミューテーションプロシージャによって返される値は指定されていません。


2
!の合理的な説明を提供するドキュメントがあるので、この答えに+1してください。使用法。本当に良い答えスティーブン
DavidSilveira

@DavidSilveira、ありがとう!
Steven Huwig 2017年

24

!通常、メソッドは結果を返す代わりにオブジェクトに作用することを意味します。本からRubyのプログラミング

「危険」なメソッド、またはレシーバーを変更するメソッドには、末尾に「!」が付いている場合があります。


18

バングのあるメソッドと言うのが最も正確です!より危険なバージョンまたは意外なバージョンです。など、Bangを使用せずに変異するメソッドは多数ありますが.destroy、一般的には、コアlibに安全な代替手段が存在する場合にのみbangを使用します。

例えば、アレイ上の我々は持っている.compact.compact!、両方の方法は、配列を変化させますが、.compact!単なる自己を返すよりも驚くべきことである配列、にはゼロのが存在しない場合はリターンは、自己の代わりにnilを。

私はバタンと見つけた唯一の非変異方法があるKernel.exit!を超える驚くべきことである.exitあなたがキャッチすることはできませんので、SystemExitプロセスが終了している間。

RailsとActiveRecordはこの傾向を続けており、bangを使用して.create!、障害発生時にエラーが発生するなど、より「驚くべき」効果をもたらします。


16

themomorohoax.comから:

bangは、個人的な好みの順に、以下の方法で使用できます。

1)アクティブレコードメソッドは、メソッドが意図したとおりに実行しない場合、エラーを発生させます。

2)アクティブなレコードメソッドがレコードを保存するか、メソッドがオブジェクトを保存する(例:ストリップ!)

3)メソッドは、どこかへの投稿のような「特別な」何かを行うか、または何らかのアクションを行います。

重要なのは、他の開発者がなぜbangを使用しているのかを確認しなければならないという煩わしさをなくすために、本当に必要かどうかを考えたときにのみbangを使用することです。

強打は他の開発者に2つの手がかりを提供します。

1)メソッドを呼び出した後にオブジェクトを保存する必要がないこと。

2)メソッドを呼び出すと、dbが変更されます。

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods


6

簡単な説明:

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!どうしても必要な場合以外は使用しないことをお勧めします。


1
!

私はこれを、それ以前に起こったことをすべて破壊する爆発的な変化と考えるのが好きです。感嘆符または感嘆符は、コードに変更を永続的に保存することを意味します。

たとえばRubyのメソッドをグローバル置換に使用する場合gsub!、行う置換は永続的です。

想像できるもう1つの方法は、テキストファイルを開いて検索と置換を行ってから保存することです。!コードでも同じです。

bashの世界から来た場合のもう1つの便利な注意sed -i点は、永続的に保存された変更を行うという同様の効果があります。


1

「破壊的メソッド」と呼ばれる彼らはあなたが参照しているオブジェクトの元のコピーを変更する傾向があります。

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]

0

結論:!メソッドは呼び出されたオブジェクトの値を変更するだけですが、メソッドのない!メソッドは、メソッドが呼び出されたオブジェクトを上書きせずに操作された値を返します。

!メソッドを呼び出した変数に格納されている元の値を必要としない場合にのみ使用してください。

私は次のようなことをすることを好みます:

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

または

foo = "word"
puts foo.capitalize

の代わりに

foo = "word"
foo.capitalize!
puts foo

元の値に再度アクセスしたい場合に備えて。


1
あなたの答えはまったく役に立たなかったからです。「結論:!メソッドは、呼び出されたオブジェクトの値を変更するだけです」というのは、真実ではありません。
ダーウィン、

それは@Darwin ないオブジェクトの値を変更します。!変更されたコピーを返すのではなく、オブジェクトを変更します。
Charles

これは何をしていると思いますか?User.create!
ダーウィン

@ダーウィンはどんな文脈で?ActiveRecord?
Charles

はい、ActiveRecord。
ダーウィン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.