Apa arti kode berikut di Ruby?
||=
Apakah ada arti atau alasan untuk sintaksis?
Pertanyaan ini telah sering dibahas di milis-rubel Ruby dan blog-blog Ruby sehingga sekarang ada utas-utas pada milis-Ruby yang satu-satunya tujuan adalah untuk mengumpulkan tautan ke semua utas lainnya pada milis-Ruby yang membahas masalah ini .
Ini dia: Daftar pasti utas dan halaman || = (OR Sama)
Jika Anda benar - benar ingin tahu apa yang sedang terjadi, lihat Bagian 11.4.2.3 "Penugasan singkat" dari Spesifikasi Draf Bahasa Ruby .
Sebagai perkiraan pertama,
a ||= b
setara dengan
a || a = b
dan tidak setara dengan
a = a || b
Namun, itu hanya perkiraan pertama, terutama jika a
tidak terdefinisi. Semantik juga berbeda tergantung pada apakah itu tugas variabel sederhana, tugas metode atau tugas pengindeksan:
a ||= b
a.c ||= b
a[c] ||= b
semua diperlakukan berbeda.
a = false; a ||= true
tidak tidak melakukan apa jawaban Anda mengatakan itu melakukan "nuansa".a ||= b
adalah operator penugasan bersyarat . Ini berarti jikaa
tidak terdefinisi atau palsu , maka evaluasib
dan atura
hasilnya . Secara setara, jikaa
didefinisikan dan dievaluasi untuk kebenaran, makab
tidak dievaluasi, dan tidak ada penugasan yang terjadi. Sebagai contoh:Yang membingungkan, tampilannya mirip dengan operator penugasan lain (seperti
+=
), tetapi berperilaku berbeda.a += b
diterjemahkan menjadia = a + b
a ||= b
diterjemahkan secara kasar menjadia || a = b
Ini adalah singkatan untuk
a || a = b
. Perbedaannya adalah bahwa, ketikaa
tidak ditentukan,a || a = b
akan dinaikkanNameError
, sedangkana ||= b
seta
keb
. Perbedaan ini tidak penting jikaa
danb
keduanya merupakan variabel lokal, tetapi signifikan jika keduanya merupakan metode pengambil / penyetel suatu kelas.Bacaan lebih lanjut:
sumber
h = Hash.new(0); h[1] ||= 2
. Sekarang perhatikan dua ekspansi yang mungkinh[1] = h[1] || 2
vsh[1] || h[1] = 2
. Kedua ekspresi mengevaluasi0
tetapi yang pertama tidak perlu meningkatkan ukuran hash. Mungkin itu sebabnya Matz memilih untuk||=
bersikap lebih seperti ekspansi kedua. (Saya mendasarkan ini pada contoh dari salah satu utas yang ditautkan dalam jawaban lain.)a || a = b
memunculkanNameError
jikaa
tidak terdefinisi.a ||= b
tidak, melainkan menginisialisasia
dan mengaturnyab
. Itulah satu-satunya perbedaan antara keduanya sejauh yang saya tahu. Demikian pula, satu-satunya perbedaan antaraa = a || b
dana ||= b
yang saya sadari adalah bahwa jikaa=
metode, itu akan dipanggil terlepas dari apa yanga
kembali. Juga, satu-satunya perbedaan antaraa = b unless a
dana ||= b
yang saya sadari adalah bahwa pernyataan itu dievaluasinil
daripadaa
jikaa
itu benar. Banyak perkiraan, tapi tidak ada yang setara ...Jawaban singkat dan lengkap
mengevaluasi cara yang sama seperti masing - masing baris berikut
-
Di samping itu,
mengevaluasi cara yang sama seperti masing - masing baris berikut
-
Sunting: Seperti yang AJedi32 tunjukkan dalam komentar, ini hanya berlaku jika: 1. a adalah variabel yang ditentukan. 2. Mengevaluasi satu kali dan dua kali tidak menghasilkan perbedaan dalam kondisi program atau sistem.
sumber
a
salah / nol / tidak terdefinisi, itu dievaluasi dua kali. (Tapi saya tidak tahu Ruby, jadi saya tidak tahu apakah nilai-nilai dapat 'dievaluasi' persis ...)a || a = b
,a ? a : a = b
,if a then a else a = b end
, Danif a then a = a else a = b end
akan melemparkan kesalahan jikaa
tidak terdefinisi, sedangkana ||= b
dana = a || b
tidak akan. Juga,a || a = b
,a ? a : a = b
,if a then a else a = b end
,a = a ? a : b
, danif a then a = a else a = b end
mengevaluasia
dua kali ketikaa
adalah truthy, sedangkana ||= b
dana = a || b
tidak.a || a = b
tidak akan mengevaluasia
dua kali kapana
benar.the end state will be equivalent after the whole line has been evaluated
Itu belum tentu benar. Bagaimana jikaa
suatu metode? Metode dapat memiliki efek samping. Misalnya Denganpublic; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5
,self.a ||= b
akan mengembalikan 6, tetapiself.a ? self.a : self.a = b
akan kembali 7.Singkatnya,
a||=b
berarti: Jikaa
adaundefined, nil or false
, tetapkanb
kea
. Kalau tidak, tetaplaha
utuh.sumber
x ||= y
carajika
x
memiliki nilai, biarkan saja dan jangan ubah nilainya, jika tidak, setelx
key
sumber
Artinya atau sama dengan. Ia memeriksa untuk melihat apakah nilai di sebelah kiri didefinisikan, lalu gunakan itu. Jika tidak, gunakan nilai di sebelah kanan. Anda dapat menggunakannya di Rails untuk menyimpan variabel instance dalam model.
Contoh cepat berbasis Rails, tempat kami membuat fungsi untuk mengambil pengguna yang saat ini masuk:
Itu memeriksa untuk melihat apakah variabel instance @current_user diatur. Jika ya, itu akan mengembalikannya, sehingga menghemat panggilan basis data. Namun jika tidak disetel, kami melakukan panggilan lalu mengatur variabel @current_user ke sana. Ini adalah teknik caching yang sangat sederhana tetapi bagus untuk ketika Anda mengambil variabel instance yang sama di aplikasi beberapa kali.
sumber
undefined
, tetapi juga padafalse
dannil
, yang mungkin tidak relevan untukcurrent_user
, tetapi terutamafalse
dapat tidak diharapkan dalam kasus lainadalah
"Jika x salah atau tidak terdefinisi, maka x arahkan ke y"
sumber
Tepatnya,
a ||= b
berarti "jikaa
tidak terdefinisi atau palsu (false
ataunil
), diatura
keb
dan dievaluasi ke (yaitu kembali)b
, jika tidak mengevaluasi kea
".Orang lain sering mencoba menggambarkan ini dengan mengatakan bahwa
a ||= b
itu setara dengana || a = b
ataua = a || b
. Kesetaraan ini dapat membantu untuk memahami konsep, tetapi perlu diketahui bahwa mereka tidak akurat dalam semua kondisi. Izinkan saya menjelaskan:a ||= b
⇔a || a = b
?Perilaku pernyataan ini berbeda ketika
a
variabel lokal tidak ditentukan. Dalam hal ini,a ||= b
akan diatura
keb
(dan dievaluasi keb
), sedangkana || a = b
akan meningkatNameError: undefined local variable or method 'a' for main:Object
.a ||= b
⇔a = a || b
?The kesetaraan laporan ini sering diasumsikan, karena kesetaraan yang sama berlaku untuk lainnya tugas disingkat operator (yaitu
+=
,-=
,*=
,/=
,%=
,**=
,&=
,|=
,^=
,<<=
, dan>>=
). Namun, untuk||=
perilaku pernyataan-pernyataan ini dapat berbeda kapana=
metode pada suatu objek dana
benar. Dalam hal ini,a ||= b
akan melakukan apa-apa (selain mengevaluasia
), sedangkana = a || b
akan memanggila=(a)
padaa
's penerima. Seperti yang telah ditunjukkan orang lain , ini dapat membuat perbedaan ketika menelepona=a
memiliki efek samping, seperti menambahkan kunci ke hash.a ||= b
⇔a = b unless a
??Perilaku pernyataan ini hanya berbeda dalam apa yang mereka evaluasi ketika
a
benar. Dalam hal ini,a = b unless a
akan mengevaluasi kenil
(meskipuna
masih tidak akan ditetapkan, seperti yang diharapkan), sedangkana ||= b
akan mengevaluasi kea
.a ||= b
⇔defined?(a) ? (a || a = b) : (a = b)
????Masih tidak. Pernyataan ini dapat berbeda ketika
method_missing
ada metode yang mengembalikan nilai kebenaran untuka
. Dalam hal ini,a ||= b
akan mengevaluasimethod_missing
pengembalian apa pun , dan tidak berusaha untuk menetapkana
, sedangkandefined?(a) ? (a || a = b) : (a = b)
akan ditetapkana
untukb
dan mengevaluasib
.Oke, oke, jadi apa yang
a ||= b
setara? Apakah ada cara untuk mengekspresikan ini di Ruby?Nah, dengan asumsi bahwa saya tidak mengabaikan apa pun, saya percaya
a ||= b
secara fungsional setara dengan ... ( drumroll )Tahan! Bukankah itu hanya contoh pertama dengan noop sebelumnya? Ya tidak cukup. Ingat bagaimana saya katakan sebelumnya bahwa
a ||= b
itu tidak hanya setara dengana || a = b
kapana
variabel lokal tidak ditentukan? Yah,a = nil if false
pastikan itua
tidak pernah ditentukan, meskipun garis itu tidak pernah dieksekusi. Variabel lokal di Ruby dibatasi secara leksikal.sumber
(a=b unless a) or a
a
merupakan metode, itu akan dipanggil dua kali alih-alih satu kali (jika itu mengembalikan nilai kebenaran pertama kali). Itu dapat menyebabkan perilaku berbeda jika, misalnya,a
membutuhkan waktu lama untuk kembali atau memiliki efek samping.b
untuka
, tidak dengan rhs masih menetapkan ke lhs, atau dengan kata lain, tidak dengan lhs masih set nilainya ke rhs?a ||= b
Jawaban terbaik yang saya temukan di Internet. Terima kasih.unless x x = y end
kecuali x memiliki nilai (bukan nil atau salah), atur sama dengan y
setara dengan
x ||= y
sumber
Misalkan
a = 2
danb = 3
LALU,
a ||= b
akan dihasilkana
nilai yaitu2
.Seperti ketika seorang mengevaluasi ke beberapa nilai yang tidak dihasilkan
false
ataunil
.. Karena itulah iall
tidak mengevaluasib
nilai itu.Sekarang Misalkan
a = nil
danb = 3
.Maka
a ||= b
akan dihasilkan3
yaitub
nilai 's.Ketika pertama kali mencoba untuk mengevaluasi nilai a yang dihasilkan
nil
.. jadi dievaluasib
nilai.Contoh terbaik yang digunakan dalam aplikasi ror adalah:
Di mana,
User.find_by_id(session[:user_id])
dipecat jika dan hanya jika@current_user
tidak diinisialisasi sebelumnya.sumber
a || = b
Menandakan jika ada nilai yang ada di 'a' dan Anda tidak ingin mengubahnya tetap menggunakan nilai itu, kalau tidak 'a' tidak memiliki nilai, gunakan nilai 'b'.
Kata-kata sederhana, jika sisi kiri jika bukan nol, arahkan ke nilai yang ada, atau arahkan ke nilai di sisi kanan.
sumber
setara dengan
dan tidak
karena situasi di mana Anda mendefinisikan hash dengan default (hash akan mengembalikan default untuk kunci yang tidak ditentukan)
jika Anda menggunakan:
a masih:
tetapi ketika Anda menulisnya seperti itu:
a menjadi:
karena Anda telah menetapkan nilai dirinya pada key
10
, yang defaultnya menjadi true, jadi sekarang hash didefinisikan untuk key10
, daripada tidak pernah melakukan penugasan sejak awal.sumber
Ini seperti contoh malas. Jika variabel sudah ditentukan maka akan mengambil nilai itu alih-alih membuat nilai lagi.
sumber
Harap juga ingat bahwa
||=
ini bukan operasi atom dan karenanya, ini tidak aman untuk thread. Sebagai pedoman praktis, jangan menggunakannya untuk metode kelas.sumber
Ini adalah notasi penugasan default
misalnya: x || = 1
ini akan memeriksa untuk melihat apakah x nil atau tidak. Jika x benar-benar nol maka akan menetapkan nilai baru itu (1 dalam contoh kita)
lebih eksplisit:
jika x == nil
x = 1
akhir
sumber
nil
ataufalse
, tidak hanyanil
|| = adalah operator penugasan bersyarat
setara dengan
atau sebagai alternatif
sumber
Jika
X
TIDAK memiliki nilai, itu akan diberi nilaiY
. Atau, itu akan mempertahankan nilai aslinya, 5 dalam contoh ini:sumber
Sebagai kesalahpahaman umum,
a ||= b
tidak sama dengana = a || b
, tetapi berperilaku sepertia || a = b
.Tapi inilah kasus rumit. Jika
a
tidak didefinisikan,a || a = 42
naikkanNameError
, sambila ||= 42
kembali42
. Jadi, mereka sepertinya bukan ekspresi yang setara.sumber
||=
memberikan nilai ke kanan hanya jika kiri == nil (atau tidak didefinisikan atau salah).sumber
Sintaks ruby-lang ini. Jawaban yang benar adalah dengan memeriksa dokumentasi ruby-lang. Semua penjelasan lainnya dikaburkan .
Google
"ruby-lang docs Assignment Disingkat".
Dokumentasi Ruby-lang
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
sumber
Karena
a
sudah diatur ke1
Karena
a
itunil
sumber
Ini diterjemahkan menjadi:
yang mana yang akan
akhirnya
Sekarang jika Anda memanggil ini lagi:
Sekarang jika Anda memanggil ini lagi:
Jika Anda amati,
b
nilai tidak akan diberikana
.a
masih akan memiliki5
.Ini adalah Pola Memoisasi yang digunakan di Ruby untuk mempercepat aksesor.
Ini pada dasarnya diterjemahkan menjadi:
Jadi, Anda akan melakukan panggilan ke database untuk pertama kalinya Anda memanggil metode ini.
Panggilan mendatang ke metode ini hanya akan mengembalikan nilai
@users
variabel instan.sumber
||=
disebut operator penugasan bersyarat.Ini pada dasarnya berfungsi sebagai
=
tetapi dengan pengecualian bahwa jika suatu variabel telah ditetapkan itu tidak akan melakukan apa-apa.Contoh pertama:
Contoh kedua:
Dalam contoh pertama
x
sekarang sama dengan 10. Namun, dalam contoh keduax
sudah didefinisikan sebagai 20. Jadi operator kondisional tidak berpengaruh.x
masih 20 setelah berjalanx ||= 10
.sumber
a ||= b
sama dengan mengatakana = b if a.nil?
ataua = b unless a
Tetapi apakah ketiga opsi ini menunjukkan kinerja yang sama? Dengan Ruby 2.5.1 ini
membutuhkan 0,099 Detik di PC saya, sementara
membutuhkan waktu 0,062 Detik. Itu hampir 40% lebih cepat.
dan kemudian kita juga memiliki:
yang membutuhkan 0,166 Detik.
Bukannya ini akan membuat dampak kinerja yang signifikan secara umum, tetapi jika Anda memang membutuhkan sedikit optimasi terakhir, maka pertimbangkan hasil ini. Omong-omong:
a = 1 unless a
lebih mudah dibaca untuk pemula, itu cukup jelas.Catatan 1: alasan untuk mengulangi garis tugas beberapa kali adalah untuk mengurangi overhead loop pada waktu yang diukur.
Catatan 2: Hasilnya serupa jika saya melakukan
a=nil
nol sebelum setiap tugas.sumber