web-dev-qa-db-ja.com

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

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

しかし、なぜいくつかのメソッドが感嘆符(!)を他のものが持っていないのはなぜですか?

どういう意味ですか?

498
Lennie

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

573
Todd Gamblin

感嘆符は多くのことを意味します、そして時にはあなたは「これは危険です、注意してください」以外にそれから多くを話すことができません。

他の人が言っているように、標準的なメソッドでは、オブジェクトを自分自身に変化させるメソッドを示すためによく使われますが、いつもそうとは限りません。多くの標準メソッドは受信者を変更し、感嘆符(popshiftclear)を持たず、また感嘆符を持つメソッドの中には受信者(exit!)を変更しないものがあります。例えば この記事 を見てください。

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

これは命名規則ですが、多くの人が微妙に異なる方法でそれを使用します。あなた自身のコードでは、特に同じ名前を持つ2つのメソッドが存在し、そのうちの1つが他よりも「危険」であるときに、メソッドが「危険」をしているときはいつでもそれを使用するのがよい経験則です。 「危険」とは、ほぼすべてのことを意味します。

130
Brian Carper

この命名規則は Scheme から解除されています。

1.3.5命名規則

慣例により、常に真偽値を返す手続きの名前は通常 ``? ''で終わります。このような手続きは述語と呼ばれます。

慣例により、以前に割り当てられた位置に値を格納する手続きの名前(セクション3.4を参照)は通常 ``! ''で終わります。このような手順は突然変異手順と呼ばれます。慣例により、突然変異手続きによって返される値は指定されていません。

70
Steven Huwig

!通常、メソッドは結果を返すのではなく、オブジェクトに対して機能します。本から--- Programming Ruby

「危険」なメソッド、またはレシーバを変更するメソッドは、末尾に「!」を付けて命名することができます。

23
Pesto

それはバングでその方法を言うのが最も正確です!もっと 危険な あるいは 驚くべき バージョンです。 .destroy のように、Bangを使わずに変異するメソッドはたくさんありますが、一般的には、より安全な代替手段がコアライブラリに存在するところにbangがあります。

たとえば、Arrayでは.compact.compact!があります。どちらのメソッドも配列を変更しますが、配列にnilがない場合は.compact!はselfではなくnilを返します。これは、selfを返すよりも驚くべきことです。

私がbangを使って見つけた唯一の不変の方法はKernel.exit! です。これはプロセスが終了している間はSystemExitをキャッチできないため、.exitよりも驚くべきことです。

RailsとActiveRecordは、この傾向を続けています。 .create! のようなより「驚くべき」効果にはbangを使用しているため、失敗するとエラーが発生します。

16
BookOfGreg

Themomorohoax.comから:

私の個人的な好みの順に、ビッグバンは以下の方法で使うことができます。

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

16
Edward Castaño

簡単な説明

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!を使用しないことをお勧めします。

6
Mirage

「破壊的な方法」と呼ばれるそれらはあなたが参照しているオブジェクトのオリジナルのコピーを変更する傾向があります。

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の方法を使う場合gsub!あなたが行う置換は永久的です。

あなたがそれを想像することができるもう一つの方法は、テキストファイルを開いて検索と置換をしてから保存することです。 !はあなたのコードで同じことをします。

あなたがbashの世界から来た場合のもう1つの便利なリマインダーはsed -iが永久的に保存された変更をするという同様の効果を持つことです。

1
Charlie Wood

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

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

私は以下のようなことをするのが好きです。

foo = "Word"
bar = foo.capitalize
puts bar

OR

foo = "Word"
puts foo.capitalize

の代わりに

foo = "Word"
foo.capitalize!
puts foo

念のためにもう一度元の値にアクセスしたいと思います。

0
Charles