Setiap kali saya menukar nilai dalam array, saya pastikan saya menyimpan salah satu nilai dalam variabel referensi. Tetapi saya menemukan bahwa Ruby dapat mengembalikan dua nilai serta secara otomatis menukar dua nilai. Sebagai contoh,
array = [1, 3, 5 , 6 ,7]
array[0], array[1] = array[1] , array[0] #=> [3, 1]
Saya bertanya-tanya bagaimana Ruby melakukan ini.
Jawaban:
Tidak seperti bahasa lain, nilai kembalian dari setiap pemanggilan metode di Ruby selalu berupa objek. Ini dimungkinkan karena, seperti semua yang ada di Ruby,
nil
itu sendiri adalah sebuah objek.Ada tiga pola dasar yang akan Anda lihat. Tidak mengembalikan nilai tertentu:
def nothing end nothing # => nil
Mengembalikan nilai singular:
def single 1 end x = single # => 1
Ini sejalan dengan apa yang Anda harapkan dari bahasa pemrograman lain.
Hal-hal menjadi sedikit berbeda ketika berhadapan dengan beberapa nilai pengembalian. Ini perlu ditentukan secara eksplisit:
def multiple return 1, 2 end x = multiple # => [ 1, 2 ] x # => [ 1, 2 ]
Saat melakukan panggilan yang mengembalikan beberapa nilai, Anda dapat memecahnya menjadi variabel independen:
x, y = multiple # => [ 1, 2 ] x # => 1 y # => 2
Strategi ini juga berfungsi untuk jenis substitusi yang Anda bicarakan:
a, b = 1, 2 # => [1, 2] a, b = b, a # => [2, 1] a # => 2 b # => 1
sumber
[1, 2]
dan ini akan bekerja sama seperti contoh Anda di atas.1,2
dengan sendirinya tidak valid, tetapi salah satureturn 1,2
atau[1,2]
berfungsi.Tidak, Ruby sebenarnya tidak mendukung pengembalian dua objek. (BTW: Anda mengembalikan objek, bukan variabel. Lebih tepatnya, Anda mengembalikan pointer ke objek.)
Itu, bagaimanapun, mendukung penugasan paralel. Jika Anda memiliki lebih dari satu objek di sisi kanan tugas, objek dikumpulkan menjadi
Array
:foo = 1, 2, 3 # is the same as foo = [1, 2, 3]
Jika Anda memiliki lebih dari satu "target" (variabel atau metode penyetel) di sisi kiri tugas, variabel terikat ke elemen
Array
di sisi kanan:a, b, c = ary # is the same as a = ary[0] b = ary[1] c = ary[2]
Jika ruas kanan bukan sebuah
Array
, itu akan diubah menjadi satu dengan menggunakanto_ary
metode inia, b, c = not_an_ary # is the same as ary = not_an_ary.to_ary a = ary[0] b = ary[1] c = ary[2]
Dan jika kita menggabungkan keduanya, kita mendapatkannya
a, b, c = d, e, f # is the same as ary = [d, e, f] a = ary[0] b = ary[1] c = ary[2]
Terkait dengan ini adalah operator percikan di sisi kiri tugas. Artinya "ambil semua elemen kiri-atas
Array
di sisi kanan":a, b, *c = ary # is the same as a = ary[0] b = ary[1] c = ary.drop(2) # i.e. the rest of the Array
Dan yang tak kalah pentingnya, tugas paralel dapat disarangkan menggunakan tanda kurung:
a, (b, c), d = ary # is the same as a = ary[0] b, c = ary[1] d = ary[2] # which is the same as a = ary[0] b = ary[1][0] c = ary[1][1] d = ary[2]
Ketika Anda
return
dari sebuah metode ataunext
ataubreak
dari sebuah blok, Ruby akan memperlakukan hal semacam ini seperti sisi kanan sebuah tugas, jadireturn 1, 2 next 1, 2 break 1, 2 # is the same as return [1, 2] next [1, 2] break [1, 2]
Ngomong-ngomong, ini juga berfungsi dalam daftar parameter metode dan blok (dengan metode yang lebih ketat dan blok tidak terlalu ketat):
def foo(a, (b, c), d) p a, b, c, d end bar {|a, (b, c), d| p a, b, c, d }
Pemblokiran menjadi "kurang ketat" misalnya yang membuat
Hash#each
berhasil. Sebenarnya iniyield
adalah satu dua elemenArray
kunci dan nilai ke blok, tetapi biasanya kami menulissome_hash.each {|k, v| }
dari pada
some_hash.each {|(k, v)| }
sumber
tadman dan Jörg W Mittag mengenal Ruby lebih baik dari saya, dan jawaban mereka tidak salah, tapi saya rasa mereka tidak menjawab apa yang OP ingin tahu. Saya pikir pertanyaannya tidak jelas. Dalam pemahaman saya, apa yang OP ingin tanyakan tidak ada hubungannya dengan mengembalikan banyak nilai.
Pertanyaan sebenarnya adalah, ketika Anda ingin mengganti nilai dua variabel
a
danb
(atau dua posisi dalam array seperti pada pertanyaan awal), mengapa tidak perlu menggunakan variabel temporaltemp
seperti:a, b = :foo, :bar temp = a a = b b = temp
tapi bisa dilakukan langsung seperti:
a, b = :foo, :bar a, b = b, a
Jawabannya, dalam penugasan rangkap seluruh ruas kanan dievaluasi sebelum penugasan ruas kiri secara keseluruhan, dan tidak dilakukan satu persatu. Jadi
a, b = b, a
tidak sama dengana = b; b = a
.Pertama mengevaluasi seluruh sisi kanan sebelum penugasan adalah kebutuhan yang mengikuti dari penyesuaian ketika kedua sisi
=
memiliki jumlah istilah yang berbeda, dan deskripsi Jörg W Mittag mungkin secara tidak langsung terkait dengan itu, tetapi itu bukan masalah utama.sumber
Array adalah pilihan yang bagus jika Anda hanya memiliki sedikit nilai. Jika Anda ingin beberapa nilai kembali tanpa harus mengetahui (dan bingung dengan) urutan hasil, alternatifnya adalah mengembalikan Hash yang berisi nilai bernama apa pun yang Anda inginkan.
misalnya
def make_hash x = 1 y = 2 {x: x, y: y} end hash = make_hash # => {:x=>1, :y=>2} hash[:x] # => 1 hash[:y] # => 2
sumber