Ünlem işaretleri Ruby yöntemlerinde neden kullanılıyor?


540

Ruby'de bazı yöntemlerde, söz konusu nesnenin dahil edilip edilmediğini ?soran böyle bir soru soran bir soru işareti ( ) vardır include?, bu daha sonra true / false döndürür.

Ama neden bazı yöntemlerin !diğerlerinde olmayan ünlem işaretleri ( ) var?

Bunun anlamı ne?


21
eşanlamlı: patlama, ünlem işareti
prusswan

17
Kabul edilen cevap stackoverflow.com/a/612653/109618 olarak değiştirilmelidir . Bkz. Wobblini.net/bang.txt ve ruby-forum.com/topic/176830#773946 - "Patlama işareti" patlama versiyonunun patlama olmayan emsalinden daha tehlikeli olduğu anlamına gelir; özenle ele "" -Matz
David J.

2
Patlama yöntemi sadece ve tüm patlatma yöntemleri tehlikeli olsaydı harika bir tasarım seçeneği olurdu . Ne yazık ki değiller ve bu yüzden değişebilir ve değişmez olanı ezberlemek için sinir bozucu bir egzersiz haline gelir.
Damien Roche

Yanıtlar:


617

Genel olarak, sona eren yöntemler !, yöntemin çağrıldığı nesneyi değiştireceğini gösterir . Ruby bunları " tehlikeli yöntemler " olarak adlandırır çünkü başkalarının referans alabileceği durumu değiştirirler. İşte dizeler için basit bir örnek:

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo

Bu çıktı:

a string

Standart kütüphanelerde, biri !ve diğeri olmadan benzer şekilde adlandırılmış yöntemlerin çiftlerini göreceğiniz birçok yer vardır . Olmayanlar "güvenli yöntemler" olarak adlandırılır ve orijinalin bir kopyasını, kopya değiştirilmeden kopyaya uygulanan değişikliklerle döndürürler . İşte aynı örnek olmadan !:

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

Bu çıktılar:

A STRING
a string

Bunun sadece bir kongre olduğunu unutmayın, ancak birçok Ruby sınıfı bunu izler. Ayrıca, kodunuzda nelerin değiştiğini izlemenize de yardımcı olur.


2
Ayrıca çıkışa karşı çıkış gibi durumlar da var! ve (raylarda) kaydetme yerine kaydetme!
Andrew Grimm

24
Çok dikkatli olun - birçok küçük kütüphane bu sözleşmeye uymaz. Eğer garip şeyler oluyorsa, genellikle obj.whatever! obj = obj.whatever ile! düzeltir. Çok sinir bozucu.
Sarah Mei

101
patlama da bir istisna yöntemleri için kullanıldığında yöntem olmadan yapar değil, örneğin: saveve save!deActiveRecord
ecoologic

3
@AbhilashAK kaydet! kaydedemezse bir hata oluşturur. Bu, doğru / yanlış döndüren düzenli kurtarmaya karşıdır.
BookOfGreg

31
@tgamblin Ruby'de patlama olmadan mutasyon geçiren birçok yöntem vardır. Patlama olmadan mutasyona uğramayan, ancak hataları yükseltmek veya hataları atlamak gibi şaşırtıcı bir şey yapan nadir yöntemler bile vardır. Patlamalar, yöntemin daha sıradışı bir versiyonu olduğunu söylemek için kullanılır ve doğru olarak işaretlendiğinden bunun cevabınıza yansıtılması gerektiğini düşünüyorum.
BookOfGreg

143

Ünlem işareti çok şey ifade ediyor ve bazen "bu tehlikeli, dikkatli ol" dışında pek bir şey söyleyemezsiniz.

Diğerlerinin söylediği gibi, standart yöntemlerde genellikle bir nesnenin kendini değiştirmesine neden olan bir yöntemi belirtmek için kullanılır, ancak her zaman değil. Birçok standart yöntemler kendi alıcısını değiştirebilir ve ünlem (yok Not pop, shift, clear) ve ünlem işareti ile bazı yöntemler kendi alıcısını değişmez ( exit!). Örneğin bu makaleye bakın .

Diğer kütüphaneler bunu farklı kullanabilir. Rails'te bir ünlem işareti genellikle yöntemin sessizce başarısız olmaktan ziyade hataya bir istisna atacağı anlamına gelir.

Bu bir adlandırma kuralıdır, ancak birçok kişi bunu farklı şekillerde kullanır. Kendi kodunuzda iyi bir kural, bir yöntem "tehlikeli" bir şey yaptığında, özellikle aynı ada sahip iki yöntem olduğunda ve bunlardan biri diğerinden daha "tehlikeli" olduğunda kullanmaktır. "Tehlikeli" neredeyse her şey anlamına gelebilir.


75

Bu adlandırma kaldırıldığında Şema .

1.3.5 Adlandırma kuralları

Kural olarak, her zaman bir boole değeri döndüren prosedürlerin adları genellikle ``? '' İle biter. Bu prosedürlere yüklem denir.

Kural olarak, değerleri daha önce tahsis edilen konumlara (bkz. Bölüm 3.4) depolayan prosedürlerin adları genellikle ``! '' İle biter. Bu prosedürlere mutasyon prosedürleri denir. Geleneksel olarak, bir mutasyon prosedürü tarafından döndürülen değer belirtilmez.


2
+ 1 için bu cevaba makul bir açıklama veren bir belge var! kullanımı. Gerçekten iyi cevap Steven
DavidSilveira

Teşekkürler @DavidSilveira!
Steven Huwig

24

! tipik olarak yöntemin bir sonuç döndürmek yerine nesneye etki ettiği anlamına gelir. Ruby Programlama kitabından :

"Tehlikeli" olan veya alıcıyı değiştiren yöntemlerin sonuna "!" Adı verilebilir.


18

Bu yöntemleri bir Bang ile söylemek en doğru! daha tehlikeli ya da şaşırtıcı versiyonlardır. Bang olmadan mutasyona uğrayan birçok yöntem vardır .destroyve genel yöntemler sadece çekirdek lib'de daha güvenli bir alternatifin bulunduğu patlamalara sahiptir.

Örneğin, Array üzerinde sahip olduğumuz .compactve .compact!her iki yöntemler dizisi mutasyona fakat .compact!daha adil kendini döndüren daha şaşırtıcıdır dizide, hiçbir nil en varsa döner öz yerine nil.

Ben bir patlama ile buldum sadece sigara mutasyona yöntemdir Kernel'ın .exit!birden şaşırtıcıdır .exitsen yakalamak olamaz çünkü SystemExitsüreç kapanırken.

Rails ve ActiveRecord, bu eğilimi .create!başarısızlık gibi hataları yükselten gibi daha 'şaşırtıcı' efektler için patlama kullanması nedeniyle devam ediyor .


16

Themomorohoax.com'dan:

Bir patlama, kişisel tercihime göre aşağıdaki şekillerde kullanılabilir.

1) Yöntem söylediği şeyi yapmazsa, etkin kayıt yöntemi bir hata oluşturur.

2) Aktif bir kayıt yöntemi kaydı kaydeder veya bir yöntem bir nesneyi kaydeder (örn. Şerit!)

3) Bir yöntem, bir yere gönderiler gibi “ekstra” bir şey yapar veya bazı eylemler yapar.

Mesele şu ki: sadece gerçekten gerekli olup olmadığını düşündüğünüzde bir patlama kullanın, diğer geliştiricilere neden bir patlama kullandığınızı kontrol etme sıkıntısını kurtarmak için.

Patlama diğer geliştiricilere iki ipucu veriyor.

1) yöntemi çağırdıktan sonra nesneyi kaydetmenin gerekli olmadığı.

2) yöntemi çağırdığınızda, db değiştirilecektir.

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


6

Basit açıklama:

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.

Ancak downcase!yukarıdaki açıklamada bir yöntem fooçağırdıysanız, kalıcı olarak küçük harfe dönüşecektir. downcase!yeni bir dize nesnesi döndürmez, yerine dize yerine tamamen küçük fooharf değiştirir . downcase!Tamamen gerekli olmadıkça kullanmamanızı öneririm .


1
!

Bunu, ondan önce olan her şeyi yok eden patlayıcı bir değişiklik olarak düşünmeyi seviyorum. Patlama veya ünlem işareti, kodunuzda kalıcı bir değişiklik yaptığınız anlamına gelir.

Örneğin Ruby'nin küresel oyuncu değişikliği yöntemini kullanırsanız, gsub!yapılan oyuncu değişikliği kalıcı olur.

Hayal edebileceğiniz başka bir yol, bir metin dosyası açmak ve bul ve değiştir yapmak ve ardından kaydetmektir. !kodunuzda da aynısını yapar.

Eğer bash dünyasından gelirseniz bir başka yararlı hatırlatma da sed -ikalıcı olarak kaydedilmiş bir değişiklik yapmanın benzer bir etkisi.


1

"Yıkıcı Yöntemler" olarak adlandırılırlar Söz ettiğiniz nesnenin orijinal kopyasını değiştirme eğilimindedirler.

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

Alt satır: !yöntemler sadece çağrıldıkları nesnenin değerini değiştirirken, olmayan bir yöntem !, yöntemin çağrıldığı nesnenin üzerine yazmadan manipüle edilmiş bir değer döndürür.

Yalnızca !yöntemi çağırdığınız değişkende saklanan orijinal değere ihtiyaç duymayı planlamıyorsanız kullanın .

Gibi bir şey yapmayı tercih ederim:

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

VEYA

foo = "word"
puts foo.capitalize

Onun yerine

foo = "word"
foo.capitalize!
puts foo

Orijinal değere tekrar erişmek istiyorum.


1
Çünkü cevabınız hiçbir şekilde yardımcı olmadı. "Alt satır:! Yöntemleri sadece çağrıldıkları nesnenin değerini değiştirir" doğru değildir.
Darwin

@Darwin o does nesnenin değerini değiştirin. !değiştirilmiş bir kopyayı döndürmek yerine nesneyi değiştirir.
Charles

Peki bunun ne yaptığını düşünüyorsun? User.create!
Darwin

@Darwin hangi bağlamda? ActiveRecord?
Charles

Evet, ActiveRecord.
Darwin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.