Aşağıdaki kod Ruby'de ne anlama geliyor?
||=
Sözdiziminin herhangi bir anlamı veya nedeni var mı?
Aşağıdaki kod Ruby'de ne anlama geliyor?
||=
Sözdiziminin herhangi bir anlamı veya nedeni var mı?
Yanıtlar:
Bu soru Ruby posta listelerinde ve Ruby bloglarında o kadar sık tartışılmıştır ki şimdi Ruby posta listesinde tek amacı bu sorunu tartışan Ruby posta listesindeki diğer tüm konulara bağlantılar toplamaktır. .
İşte bir tane: || = (VEYA Eşit) konuların ve sayfaların kesin listesi
Eğer varsa gerçekten ne olup bittiğini bilmek istiyorum, bir "Kısaltılmış atamaları" Bölüm 11.4.2.3 bakmak Yakut Dili Taslak Şartname .
İlk yaklaşım olarak,
a ||= b
eşittir
a || a = b
ve eşdeğer değil
a = a || b
Ancak bu, özellikle a
tanımsızsa , sadece bir ilk yaklaşımdır . Anlambilim ayrıca, basit bir değişken atama, yöntem atama veya dizin oluşturma atama olmasına bağlı olarak da değişir:
a ||= b
a.c ||= b
a[c] ||= b
hepsi farklı muamele görüyor.
a = false; a ||= true
gelmez değil Cevabınız bir "nüans" yapar dediğini yap.
a ||= b
a, koşullu atama operatörü . Bunun anlamı , eğer a
tanımlanmamış veya Falsey , daha sonra değerlendirmek b
ve set a
sonuca . Eşdeğer olarak, a
doğruluk için tanımlanır ve değerlendirilirse, o zaman b
değerlendirilmez ve hiçbir ödev gerçekleşmez. Örneğin:
a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0
foo = false # => false
foo ||= true # => true
foo ||= false # => true
Şaşırtıcı bir şekilde, diğer atama operatörlerine (örneğin +=
) benzer, ancak farklı davranır.
a += b
Çevirir a = a + b
a ||= b
kabaca çevirir a || a = b
Bunun için kestirme bir yöntemdir a || a = b
. Fark ne zaman, yani a
tanımsız, a || a = b
getireceğini NameError
oysa a ||= b
setleri a
için b
. Bu ayrım, eğer önemsizdir a
ve b
hem yerel hem de değişken olan, ancak, ya bir sınıfın bir alıcı / ayarlayıcı yöntemi ise anlamlıdır.
Daha fazla okuma:
h = Hash.new(0); h[1] ||= 2
. Şimdi h[1] = h[1] || 2
vs iki olası genişletmeleri düşünün h[1] || h[1] = 2
. Her iki ifade de değerlendirilir, 0
ancak ilki gereksiz yere karma boyutunu artırır. Belki de bu yüzden Matz ||=
ikinci genişleme gibi davranmayı seçti . (Bunu başka bir cevapta bağlantılı olan konuların
a || a = b
bir NameError
if yükseltir a
. a ||= b
değil, başlangıç a
durumuna getirir ve olarak ayarlar b
. Bildiğim kadarıyla ikisi arasındaki tek fark bu. Benzer şekilde, farkında olduğum a = a || b
ve a ||= b
fark ettiğim tek fark , eğer a=
bir yöntem ise, ne a
döndürürse döndürsün çağrılır . Ayrıca arasındaki tek fark a = b unless a
ve a ||= b
Bildiğim kadarıyla buna ifadesi değerlendirir olmasıdır nil
yerine a
eğer a
truthy olduğunu. Yaklaşık bir sürü, ama oldukça eşdeğer bir şey yok ...
a ||= b
aşağıdaki satırların her biri ile aynı şekilde değerlendirir
a || a = b
a ? a : a = b
if a then a else a = b end
-
Diğer yandan,
a = a || b
aşağıdaki satırların her biri ile aynı şekilde değerlendirir
a = a ? a : b
if a then a = a else a = b end
-
Düzenleme: AJedi32 yorumlarda belirtildiği gibi, bu sadece şu geçerli tutar: 1. a tanımlı bir değişkendir. 2. Bir kez ve iki kez değerlendirmek, program veya sistem durumunda bir fark yaratmaz.
a
, false / zero / undefined ise, iki kez değerlendirildiğini gösterir. (Ama Ruby'yi bilmiyorum, bu yüzden değerlerin tam olarak 'değerlendirilebileceğini' bilmiyorum ...)
a || a = b
, a ? a : a = b
, if a then a else a = b end
Ve if a then a = a else a = b end
eğer bir hata atar a
tanımlanmamış, oysa a ||= b
ve a = a || b
bunu yapmaz. Ayrıca a || a = b
, a ? a : a = b
, if a then a else a = b end
, a = a ? a : b
, ve if a then a = a else a = b end
değerlendirmek a
iki kez ne zaman a
truthy olduğunu oysa a ||= b
ve a = a || b
yapma.
a || a = b
değerlendirmez . a
a
the end state will be equivalent after the whole line has been evaluated
Bu mutlaka doğru olmayabilir. Ya a
bir yöntem? Yöntemlerin yan etkileri olabilir. Örneğin İle public; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5
, self.a ||= b
6 geri döner, ancak self.a ? self.a : self.a = b
7 geri döner.
Anlamına gelir veya eşittir. Soldaki değerin tanımlanıp tanımlanmadığını kontrol eder, sonra bunu kullanın. Değilse, sağdaki değeri kullanın. Modellerde örnek değişkenleri önbelleğe almak için Rails'te kullanabilirsiniz.
Oturum açmış olan kullanıcıyı getirmek için bir işlev oluşturduğumuz hızlı Rails tabanlı bir örnek:
class User > ActiveRecord::Base
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
end
@Current_user örnek değişkeninin ayarlanıp ayarlanmadığını kontrol eder. Öyleyse, döndürür ve böylece bir veritabanı çağrısını kaydeder. Ancak ayarlanmazsa, çağrıyı yaparız ve sonra @current_user değişkenini buna ayarlarız. Bu gerçekten basit bir önbellekleme tekniğidir, ancak aynı örnek değişkenini uygulamada birden çok kez aldığınızda mükemmeldir.
undefined
, aynı zamanda false
ve nil
bununla ilgili olmayabilir ve current_user
özellikle false
diğer durumlarda beklenmedik olabilir
x ||= y
dır-dir
x || x = y
"x yanlış veya tanımsızsa x, y'yi gösterir"
Kesin olarak a ||= b
"belirtilen yöntemler a
tanımlanmamış ya da (falsy olan false
ya da nil
), set a
için b
ve (diğer bir deyişle dönüş) değerlendirmek b
başka bir şekilde değerlendirilmesi, a
".
Diğerleri a ||= b
bunu a || a = b
veya ile eşdeğer diyerek bunu göstermeye çalışırlar a = a || b
. Bu eşdeğerleri konsepti anlamak için yararlı olabilir, ancak bunlar farkında olabilir değil her koşulda doğru. Açıklamama izin ver:
a ||= b
⇔a || a = b
?
Bu ifadelerin davranışı, a
tanımsız bir yerel değişken olduğunda farklılık gösterir . Bu durumda, a ||= b
koyacaktır a
için b
(ve değerlendirmek b
oysa) a || a = b
olacak zam NameError: undefined local variable or method 'a' for main:Object
.
a ||= b
⇔a = a || b
?
Bu ifadelerin denklik çoğu zaman benzer bir denklik diğeri için de geçerlidir, çünkü varsayılır kısaltılmış atama operatörleri (yani +=
, -=
, *=
, /=
, %=
, **=
, &=
, |=
, ^=
, <<=
, ve >>=
). Ancak, için ||=
bu tabloların davranış olabilir zaman farklı a=
bir nesne üzerinde bir yöntem olup, a
truthy olup. Bu durumda, a ||= b
(hiç değerlendirmek başka bir şey yapacak a
, oysa) a = a || b
arayacak a=(a)
üzerinde a
'in alıcısı. Diğerlerinin de belirttiği gibi , bu arama yaparken a=a
bir karmaya anahtar eklemek gibi yan etkileri olduğunda fark yaratabilir .
a ||= b
⇔a = b unless a
??
Bu ifadelerin davranışı, yalnızca doğru olduğunda ne değerlendirdiklerine a
göre değişir. Bu durumda, a = b unless a
değerlendirilecek nil
(yine a
de beklendiği gibi ayarlanmayacak), oysa a ||= b
değerlendirecektir a
.
a ||= b
⇔defined?(a) ? (a || a = b) : (a = b)
????
Hala hayır. Bu ifadeler, method_missing
doğruluk değeri döndüren bir yöntem bulunduğunda farklılık gösterebilir a
. Bu durumda, a ||= b
her ne kadar değerlendirecek method_missing
dönüşleri ve sete denemez a
, oysa defined?(a) ? (a || a = b) : (a = b)
belirleyecektir a
için b
ve değerlendirmek b
.
Tamam, tamam, peki olduğu a ||= b
eşdeğer? Bunu Ruby'de ifade etmenin bir yolu var mı?
Eh, ben inanıyorum, ben bir şey bakan değilim varsayarak a ||= b
(... işlevsel eşdeğerdir Trampet )
begin
a = nil if false
a || a = b
end
Tut! Bundan önce noop olan ilk örnek değil mi? Pek iyi değil. Daha önce nasıl söylediğimi hatırlıyorum a ||= b
, ancak tanımlanmamış bir yerel değişkenin a || a = b
ne zaman eşdeğer olmadığını a
? Eh, a = nil if false
olmasını sağlar a
bu hat asla çalıştırılmaz halde tanımsız asla. Ruby'deki yerel değişkenler sözlüksel olarak kapsamlıdır.
(a=b unless a) or a
a
bir yöntemdir, bunun yerine (bir truthy değerini ilk kez dönerse) bir kez iki kez çağrılır. Örneğin, a
geri dönmesi uzun sürerse veya yan etkileri varsa davranışların farklı olmasına neden olabilir .
b
içina
sol eksen hala rhs'sine değerini belirlemez, rhs'si hala lhs atamak değil veya başka bir deyişle?
a ||= b
İnternette bulduğum en iyi cevap. Teşekkürler.
Varsayalım a = 2
veb = 3
O zaman, yani değeri a ||= b
ile sonuçlanacaktır .a
2
Bir değerle sonuçlanmadığı zaman ortaya çıkan false
ya da nil
.. Bu yüzden değerini ll
değerlendirmez b
.
Şimdi varsayalım a = nil
ve b = 3
.
O a ||= b
zaman 3
yani b
'değeri ile sonuçlanacaktır .
İlk olarak a'nın değerini, nil
yani bunun değerini değerlendirmeyi denedi b
.
Ror uygulamasında kullanılan en iyi örnek:
#To get currently logged in iser
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
# Make current_user available in templates as a helper
helper_method :current_user
Nerede, User.find_by_id(session[:user_id])
yalnızca ve @current_user
daha önce başlatılmazsa tetiklenir .
a || = b
'A' içinde herhangi bir değerin olup olmadığını ve bu değeri kullanarak keep değerini değiştirmek istemediğinizi belirtir, aksi takdirde 'a' herhangi bir değere sahip değilse, 'b' değerini kullanın.
Basit kelimeler, eğer sol taraf boş değilse, mevcut değere, diğer taraf sağ taraftaki değere işaret eder.
a ||= b
eşittir
a || a = b
ve yok
a = a || b
varsayılan değeri olan bir karma tanımladığınız durum nedeniyle (karma tanımsız anahtarlar için varsayılan değeri döndürür)
a = Hash.new(true) #Which is: {}
Eğer kullanırsan:
a[10] ||= 10 #same as a[10] || a[10] = 10
a hala:
{}
ama böyle yazdığınızda:
a[10] = a[10] || 10
a olur:
{10 => true}
çünkü 10
varsayılan olarak true değerine ayarlanmış olan anahtarın kendisinin değerini atamış olursunuz , öyleyse artık 10
ödevi asla yerine getirmek yerine anahtar için tanımlanmıştır .
Lütfen ||=
bunun bir atomik işlem olmadığını ve bu nedenle iş parçacığı için güvenli olmadığını unutmayın. Genel kural olarak, sınıf yöntemleri için kullanmayın.
Bu varsayılan atama gösterimi
örneğin: x || = 1
bu, x'in sıfır olup olmadığını kontrol eder. X gerçekten sıfır ise, o zaman bu yeni değeri atar (örneğimizde 1)
daha açık:
if x == nil
x = 1
son
nil
da false
, sadecenil
Eğer X
bir değere sahip DEĞİLDİR, bu değeri atanacaktır Y
. Aksi takdirde, bu örnekte 5 olan orijinal değerini koruyacaktır:
irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5
# Now set x to nil.
irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10
||=
yalnızca left == nil (veya undefined veya false ise) sağa değer atar.
Bu yakut dili sözdizimi. Doğru cevap ruby-lang belgelerini kontrol etmektir. Diğer tüm açıklamalar gizlidir .
"ruby-lang dokümanlar Kısaltılmış Atama".
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
b = 5
a ||= b
Bu şu anlama gelir:
a = a || b
hangisi olacak
a = nil || 5
en sonunda
a = 5
Şimdi tekrar ararsanız:
a ||= b
a = a || b
a = 5 || 5
a = 5
b = 6
Şimdi tekrar ararsanız:
a ||= b
a = a || b
a = 5 || 6
a = 5
Eğer gözlemlerseniz, b
değer atanmaz a
. a
hala olacak 5
.
Accesso'ları hızlandırmak için Ruby'de kullanılan bir Memoization Kalıbı.
def users
@users ||= User.all
end
Bu temelde şu anlama gelir:
@users = @users || User.all
Bu nedenle, bu yöntemi ilk çağırdığınızda veritabanına bir çağrı yapacaksınız.
Bu yönteme gelecekteki çağrılar @users
örnek değişkeninin değerini döndürecektir .
||=
koşullu atama operatörü olarak adlandırılır.
Temel olarak çalışır, =
ancak bir değişken önceden atanmışsa hiçbir şey yapmayacaktır.
İlk örnek:
x ||= 10
İkinci örnek:
x = 20
x ||= 10
İlk örnekte x
şimdi 10'a eşittir. Ancak, ikinci örnekte x
zaten 20 olarak tanımlanmıştır. Dolayısıyla koşullu işlecin bir etkisi yoktur. x
koştuktan sonra hala 20 yaşında x ||= 10
.
a ||= b
demekle aynı a = b if a.nil?
veyaa = b unless a
Ancak 3 seçeneğin tümü aynı performansı gösteriyor mu? Ruby 2.5.1 ile bu
1000000.times do
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
end
bilgisayarımda 0.099 saniye sürüyor
1000000.times do
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
end
0.062 Saniye sürer. Bu neredeyse% 40 daha hızlı.
ve sonra:
1000000.times do
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
end
0.166 Saniye sürüyor.
Bunun genel olarak önemli bir performans etkisi yaratacağı değil, ancak son optimizasyon bitine ihtiyacınız varsa, bu sonucu göz önünde bulundurun. Bu arada: a = 1 unless a
acemi için okunması daha kolaydır, açıklayıcıdır.
Not 1: Atama satırını birden çok kez tekrar etmenin nedeni, ölçülen sürede döngü yükünü azaltmaktır.
Not 2: a=nil
Her atamadan önce sıfır yaparsam sonuçlar benzerdir .