Apa yang dilakukan &. (ampersand dot) maksud di Ruby?

Jawaban:

205

Ini disebut Operator Navigasi Aman. Diperkenalkan di Ruby 2.3.0, ia memungkinkan Anda memanggil metode pada objek tanpa khawatir objek itu mungkin nil(Menghindari undefined method for nil:NilClasskesalahan), mirip dengan trymetode di Rails .

Jadi kamu bisa menulis

@person&.spouse&.name

dari pada

@person.spouse.name if @person && @person.spouse

Dari Documents :

my_object.my_method

Ini mengirimkan pesan my_method ke my_object. Objek apa pun bisa menjadi penerima tetapi tergantung pada visibilitas metode mengirim pesan dapat meningkatkan NoMethodError.

Anda dapat menggunakan &. untuk menunjuk penerima, maka my_method tidak dipanggil dan hasilnya nol ketika penerima nol. Dalam hal ini, argumen my_method tidak dievaluasi.

Santhosh
sumber
13
sebenarnya, ini bekerja seperti try!metode, bukantry
Grzegorz
58

Catatan: Meskipun @Santosh memberikan jawaban yang jelas dan lengkap, saya ingin menambahkan lebih banyak latar belakang dan menambahkan catatan penting tentang penggunaannya dengan variabel non instance.


Ini disebut " Operator Navigasi Aman " ( alias "operator rantai opsional", "operator tidak bersyarat", dll .). Matz tampaknya menyebutnya "operator yang kesepian". Itu diperkenalkan di Ruby 2.3 . Ini mengirim metode ke objek hanya jika tidak nil.

Contoh:

# Call method `.profile` on `user` only if `user` is not `nil`
@user&.profile

# Equivalent to
unless @user.nil?
  @user.profile
end

"Kasus tepi" dengan variabel lokal:

Harap dicatat, kode di atas menggunakan variabel instan. Jika Anda ingin menggunakan operator navigasi yang aman dengan variabel lokal, Anda harus memeriksa apakah variabel lokal Anda ditentukan terlebih dahulu.

# `user` local variable is not defined previous
user&.profile

# This code would throw the following error:
NameError: undefined local variable or method `user' for main:Object

Untuk memperbaiki masalah ini, periksa apakah variabel lokal Anda didefinisikan terlebih dahulu atau setel ke nil:

# Option 1: Check the variable is defined
if defined?(user)
  user&.profile
end

# Option 2: Define your local variable. Example, set it to nil
user = nil
user&.profile     # Works and does not throw any errors

Latar belakang metode

Rails memiliki trymetode yang pada dasarnya melakukan hal yang sama. Ini menggunakan sendmetode secara internal untuk memanggil metode. Matz menyarankan agar ini lambat dan ini harus menjadi fitur bahasa bawaan.

Banyak bahasa pemrograman lain memiliki fitur yang serupa: Objective C, Swift, Python, Scala, CoffeeScript, dll. Namun, sintaksis yang umum adalah ?.(titik pertanyaan). Tapi, sintaks ini tidak bisa diadopsi oleh Ruby. Karena ?diizinkan dalam nama metode dan dengan demikian, ?.urutan simbol sudah menjadi kode Ruby yang valid. Sebagai contoh:

2.even?.class  # => TrueClass

Itu sebabnya komunitas Ruby harus membuat sintaks yang berbeda. Itu adalah diskusi aktif dan pilihan yang berbeda dianggap ( .?, ?, &&, dll). Berikut adalah daftar beberapa pertimbangan:

u.?profile.?thumbnails
u\profile\thumbnails
u!profile!thumbnails
u ? .profile ? .thumbnails
u && .profile && .thumbnails

# And finally
u&.profile&.thumbnails

Saat memilih sintaks, pengembang melihat berbagai kasus tepi dan diskusi ini cukup berguna untuk dijalani. Jika Anda ingin melihat semua varian dan nuansa operator, silakan lihat diskusi pengantar fitur ini pada pelacak isu Ruby resmi.

Uzbekjon
sumber
Apa yang '.?' ? Saya pikir sudah diputuskan bahwa sintaks ini tidak akan mungkin untuk digunakan. Saya hanya bisa mendapatkan '&.' bekerja.
Keith Bennett
2
Tepat, seperti yang saya tulis .?dan opsi lain dipertimbangkan, tetapi &.terpilih! Jadi, hanya &.akan bekerja.
Uzbekjon
Oh, maaf, saya belum membaca sampai akhir. Bukankah lebih baik jika contoh memiliki sintaks yang benar?
Keith Bennett
@KeithBennett Saya mengerti maksud Anda. Saya memiliki kesalahan ketik pada contoh pertama saya. Anda benar, itu pasti &.dan tidak .?, buruk saya. Memperbarui jawaban saya. Terimakasih atas peringatannya!
Uzbekjon
@ Uzbekjon Masih ada salah ketik pada contoh kasus Tepi (opsi 1): user.?profileharus user&.profile(tidak dapat mengeditnya sendiri karena hanya mengedit 1 karakter!).
Yanis Vieilly
7

Berhati-hatilah! Meskipun operator navigasi yang aman nyaman, juga bisa menipu Anda untuk mengubah logika Anda dengannya. Saya sarankan menghindari penggunaannya dalam kontrol aliran. Contoh:

str = nil

puts "Hello" if str.nil? || str.empty?
# The above line is different than the below line
puts "Hello" if str&.empty?

Dalam contoh pertama, str.nil?mengembalikan truedan str.empty?tidak pernah dipanggil, menyebabkan putspernyataan dieksekusi. Namun dalam contoh kedua, str&.empty?mengembalikan nilyang falsey, dan putspernyataan itu tidak pernah dieksekusi.

Thomas Deranek
sumber
Menarik, meskipun secara teknis dalam pernyataan pertama Anda str.nil?adalah benar (seperti yang Anda katakan) yang berarti str.empty?tidak akan dipanggil sama sekali (itulah cara kerja ||operator). Pernyataan Anda selanjutnya benar.
Ollie Bennett
1
Oh, tangkapan yang bagus. Saya tidak yakin bagaimana saya melewatkan itu. Saya akan memperbaiki posting saya. Terima kasih!
Thomas Deranek
2
memang benar bahwa jauh lebih mudah untuk menggunakan logika yang salah, tetapi Anda memeriksa berbagai hal di sini. baris kedua setara dengan jika str && str.empty? tidak nihil || kosong. operator navigasi yang aman masih sangat valid untuk digunakan untuk kontrol aliran puts "hello" unless str&.present?(rel hanya untuk metode sekarang?)
Sampson Crowley
1

digunakan untuk nil check, seperti di kotlin dan swift Misalnya; dengan Object -> Swift dan Kotlin

model = car?.model

model ini bisa nil (Swift) atau null (Kotlin) jika kita belum mendefinisikan nilai model di kelas mobil. kami menggunakan ampersand bukan tanda tanya di ruby

model = car&.model

jika menggunakan car.model tanpa ampersand dan jika model nol, sistem tidak dapat terus berjalan.

Umut ADALI
sumber