@user.update_languages(params[:language][:language1],
params[:language][:language2],
params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------"
+ lang_errors.full_messages.inspect
if params[:user]
@user.state = params[:user][:state]
success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------"
+ lang_errors.full_messages.inspect
if lang_errors.full_messages.empty?
@user
objek menambahkan kesalahan ke lang_errors
variabel dalam update_lanugages
metode. ketika saya melakukan save pada @user
objek saya kehilangan kesalahan yang awalnya disimpan dalam lang_errors
variabel.
Meskipun apa yang saya coba lakukan akan lebih merupakan peretasan (yang sepertinya tidak berfungsi). Saya ingin memahami mengapa nilai variabel terhapus. Saya mengerti lewat referensi jadi saya ingin tahu bagaimana nilai dapat disimpan dalam variabel itu tanpa terhapus.
Jawaban:
Dalam terminologi tradisional, Ruby benar-benar merupakan nilai tambah . Tapi bukan itu yang sebenarnya kamu tanyakan di sini.
Ruby tidak memiliki konsep nilai murni, non-referensi, jadi Anda tentu tidak dapat meneruskannya ke suatu metode. Variabel selalu referensi ke objek. Untuk mendapatkan objek yang tidak akan berubah dari bawah Anda, Anda perlu menggandakan atau mengkloning objek yang Anda lewati, sehingga memberikan objek yang tidak memiliki referensi orang lain. (Meskipun ini bukan anti peluru) - kedua metode kloning standar melakukan salinan dangkal, jadi variabel instance dari klon masih menunjuk ke objek yang sama dengan yang asli lakukan. Jika objek yang dirujuk oleh ivars bermutasi, itu akan masih muncul dalam salinan, karena itu merujuk objek yang sama.)
sumber
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Penjawab lainnya semuanya benar, tetapi seorang teman meminta saya untuk menjelaskan ini kepadanya dan apa yang sebenarnya menjadi intinya adalah bagaimana Ruby menangani variabel, jadi saya pikir saya akan membagikan beberapa gambar / penjelasan sederhana yang saya tulis untuknya (permintaan maaf untuk panjangnya) dan mungkin beberapa penyederhanaan berlebihan):
T1: Apa yang terjadi ketika Anda menetapkan variabel baru
str
ke nilai'foo'
?A: Label yang dipanggil
str
dibuat yang menunjuk ke objek'foo'
, yang untuk keadaan interpreter Ruby ini berada di lokasi memori2000
.T2: Apa yang terjadi ketika Anda menetapkan variabel yang ada
str
ke objek baru menggunakan=
?A: Label
str
sekarang menunjuk ke objek yang berbeda.Q3: Apa yang terjadi ketika Anda menetapkan variabel baru
=
kestr
?A: Label baru bernama
str2
dibuat yang menunjuk pada objek yang sama denganstr
.T4: Apa yang terjadi jika objek direferensikan oleh
str
danstr2
diubah?A: Kedua label masih menunjuk pada objek yang sama, tetapi objek itu sendiri telah bermutasi (isinya telah berubah menjadi sesuatu yang lain).
Bagaimana ini berhubungan dengan pertanyaan awal?
Ini pada dasarnya sama dengan apa yang terjadi di Q3 / Q4; metode mendapatkan salinan pribadi dari variabel / label (
str2
) yang diteruskan ke sana (str
). Itu tidak dapat mengubah objek yangstr
ditunjuk label , tetapi itu dapat mengubah konten objek yang keduanya rujuk mengandung yang lain:sumber
Ruby menggunakan "referensi objek lewat"
(Menggunakan terminologi Python.)
Untuk mengatakan Ruby menggunakan "pass by value" atau "pass by reference" tidak cukup deskriptif untuk membantu. Saya pikir karena kebanyakan orang tahu hari ini, bahwa terminologi ("nilai" vs "referensi") berasal dari C ++.
Dalam C ++, "pass by value" berarti fungsi mendapatkan salinan variabel dan setiap perubahan pada salinan tidak mengubah yang asli. Itu juga berlaku untuk objek. Jika Anda melewatkan variabel objek berdasarkan nilai, maka seluruh objek (termasuk semua anggotanya) akan disalin dan perubahan apa pun pada anggota tidak mengubah anggota tersebut pada objek asli. (Ini berbeda jika Anda melewatkan pointer dengan nilai tetapi Ruby tetap tidak memiliki pointer, AFAIK.)
Keluaran:
Dalam C ++, "lulus dengan referensi" berarti fungsi mendapatkan akses ke variabel asli. Itu dapat menetapkan integer literal baru dan variabel asli kemudian akan memiliki nilai itu juga.
Keluaran:
Ruby menggunakan pass by value (dalam pengertian C ++) jika argumennya bukan objek. Tapi di Ruby semuanya adalah objek, jadi benar-benar tidak ada nilai yang lewat dalam pengertian C ++ di Ruby.
Di Ruby, "lewat referensi objek" (untuk menggunakan terminologi Python) digunakan:
Karenanya Ruby tidak menggunakan "pass by reference" dalam pengertian C ++. Jika ya, maka menetapkan objek baru ke variabel di dalam fungsi akan menyebabkan objek lama dilupakan setelah fungsi kembali.
Keluaran:
* Inilah sebabnya, di Ruby, jika Anda ingin memodifikasi objek di dalam suatu fungsi tetapi melupakan perubahan itu ketika fungsi kembali, maka Anda harus secara eksplisit membuat salinan objek sebelum membuat perubahan sementara pada salinan.
sumber
def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
. Ini mencetak "Ruby is by-value". Tetapi variabel di dalamnyafoo
dipindahkan. Jikabar
akan menjadi array, penugasan kembali tidak akan berpengaruhbaz
. Mengapa?Ruby adalah nilai per nilai. Selalu. Tidak ada pengecualian. Tidak ada seandainya. Tidak ada tapi
Berikut ini adalah program sederhana yang menunjukkan fakta itu:
sumber
Ruby adalah pass-by-value dalam arti yang ketat, TETAPI nilainya adalah referensi.
Ini bisa disebut " pass-reference-by-value ". Artikel ini memiliki penjelasan terbaik yang pernah saya baca: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Pass-reference-by-value secara singkat dapat dijelaskan sebagai berikut:
Perilaku yang dihasilkan sebenarnya merupakan kombinasi dari definisi klasik pass-by-reference dan pass-by-value.
sumber
Sudah ada beberapa jawaban yang bagus, tetapi saya ingin memposting definisi sepasang otoritas pada subjek, tetapi juga berharap seseorang dapat menjelaskan apa yang dimaksud otoritas Matz (pencipta Ruby) dan David Flanagan dalam buku O'Reilly mereka yang sangat bagus, Bahasa Pemrograman Ruby .
Ini semua masuk akal bagi saya sampai paragraf terakhir, dan terutama kalimat terakhir itu. Ini paling menyesatkan, dan lebih buruk lagi membingungkan. Bagaimana, dengan cara apa pun, modifikasi terhadap referensi yang dilewatkan oleh nilai dapat mengubah objek yang mendasarinya?
sumber
Ruby adalah pass-by-reference. Selalu. Tidak ada pengecualian. Tidak ada seandainya. Tidak ada tapi
Berikut ini adalah program sederhana yang menunjukkan fakta itu:
sumber
bar
metode Anda . Anda hanya memodifikasi objek yang referensi menunjuk ke, tetapi tidak referensi itu sendiri. Mereka satu-satunya cara untuk memodifikasi referensi di Ruby adalah dengan penugasan. Anda tidak dapat mengubah referensi dengan memanggil metode di Ruby karena metode hanya dapat dipanggil pada objek dan referensi bukan objek di Ruby. Sampel kode Anda menunjukkan bahwa Ruby telah berbagi status yang bisa berubah-ubah (yang tidak sedang dibahas di sini), namun demikian, hal itu tidak menjelaskan perbedaan antara pass-by-value dan pass-by-reference.Parameter adalah salinan dari referensi asli. Jadi, Anda dapat mengubah nilai, tetapi tidak dapat mengubah referensi asli.
sumber
Coba ini:--
identifier a berisi object_id 3 untuk value object 1 dan identifier b berisi object_id 5 untuk value object 2.
Sekarang lakukan ini: -
Sekarang, a dan b keduanya berisi object_id 5 yang sama yang merujuk ke objek nilai 2. Jadi, variabel Ruby berisi object_ids untuk merujuk ke objek nilai.
Melakukan hal berikut juga memberikan kesalahan: -
tetapi melakukan ini tidak akan memberikan kesalahan: -
Berikut identifier objek nilai pengembalian 11 yang id objeknya 23 yaitu object_id 23 berada di identifier a, Sekarang kita melihat contoh dengan menggunakan metode.
arg in foo ditugaskan dengan nilai balik x. Ini jelas menunjukkan bahwa argumen dilewatkan oleh nilai 11, dan nilai 11 menjadi objek sendiri memiliki id objek unik 23.
Sekarang lihat ini juga: -
Di sini, identifier arg pertama berisi object_id 23 untuk merujuk 11 dan setelah penugasan internal dengan nilai objek 12, itu berisi object_id 25. Tapi itu tidak mengubah nilai yang dirujuk oleh pengidentifikasi x yang digunakan dalam metode pemanggilan.
Oleh karena itu, Ruby diteruskan oleh nilai dan variabel Ruby tidak mengandung nilai tetapi berisi referensi ke objek nilai.
sumber
Ruby ditafsirkan. Variabel adalah referensi ke data, tetapi bukan data itu sendiri. Ini memfasilitasi menggunakan variabel yang sama untuk data dari berbagai jenis.
Penugasan lhs = rhs kemudian menyalin referensi pada rhs, bukan data. Ini berbeda dalam bahasa lain, seperti C, di mana tugas tidak menyalin data ke lhs dari rhs.
Jadi untuk pemanggilan fungsi, variabel yang dikirimkan, misalkan x, memang disalin ke variabel lokal dalam fungsi, tetapi x adalah referensi. Kemudian akan ada dua salinan referensi, keduanya merujuk data yang sama. Satu akan berada di pemanggil, satu di fungsi.
Tugas dalam fungsi kemudian akan menyalin referensi baru ke versi fungsi x. Setelah ini, versi x penelepon tetap tidak berubah. Itu masih referensi ke data asli.
Sebaliknya, menggunakan metode .replace pada x akan menyebabkan ruby melakukan salinan data. Jika ganti digunakan sebelum penugasan baru maka penelepon memang akan melihat perubahan data dalam versinya juga.
Demikian pula, selama referensi asli sesuai dengan variabel yang diteruskan, variabel instan akan sama dengan yang dilihat pemanggil. Dalam kerangka suatu objek, variabel instan selalu memiliki nilai referensi yang paling terkini, baik yang disediakan oleh pemanggil atau diatur dalam fungsi kelas yang diteruskan.
'Panggilan berdasarkan nilai' atau 'panggilan dengan referensi' kacau di sini karena kebingungan mengenai '=' Dalam bahasa yang dikompilasi '=' adalah salinan data. Di sini, dalam bahasa yang ditafsirkan ini '=' adalah salinan referensi. Dalam contoh Anda memiliki referensi yang diteruskan diikuti oleh salinan referensi meskipun '=' yang clobbers yang asli lulus dalam referensi, dan kemudian orang-orang membicarakannya seolah-olah '=' adalah salinan data.
Agar konsisten dengan definisi, kita harus tetap menggunakan '.replace' karena ini adalah salinan data. Dari perspektif '. Ganti' kita melihat bahwa ini memang lulus dengan referensi. Lebih jauh, jika kita berjalan di debugger, kita melihat referensi dilewatkan, karena variabel adalah referensi.
Namun jika kita harus menjaga '=' sebagai kerangka referensi, maka memang kita bisa melihat data yang diteruskan hingga tugas, dan kemudian kita tidak bisa melihatnya lagi setelah penugasan sementara data pemanggil tetap tidak berubah. Pada tingkat perilaku, ini dilewati oleh nilai selama kami tidak menganggap nilai yang diteruskan sebagai komposit - karena kami tidak akan dapat menyimpan bagian darinya sambil mengubah bagian lainnya dalam satu tugas tunggal (karena tugas itu mengubah referensi dan yang asli keluar dari ruang lingkup). Juga akan ada kutil, dalam hal variabel variabel dalam objek akan menjadi referensi, seperti semua variabel. Karenanya kita akan dipaksa untuk berbicara tentang melewati 'referensi berdasarkan nilai' dan harus menggunakan lokasi terkait.
sumber
Perlu dicatat bahwa Anda bahkan tidak perlu menggunakan metode "ganti" untuk mengubah nilai nilai asli. Jika Anda menetapkan salah satu nilai hash untuk hash, Anda mengubah nilai aslinya.
sumber
Pembaruan di objek yang sama tidak akan membuat referensi ke memori baru karena masih di memori yang sama. Berikut ini beberapa contoh:
sumber
Ya tapi ....
Ruby memberikan referensi ke sebuah objek dan karena semua yang ada di ruby adalah sebuah objek, maka Anda bisa mengatakan itu lewat referensi.
Saya tidak setuju dengan posting di sini yang mengklaim itu lewat nilai, yang tampak seperti permainan yang simpatik dan simpatik bagi saya.
Namun, efeknya "menyembunyikan" perilaku karena sebagian besar operasi ruby menyediakan "di luar kotak" - misalnya operasi string, menghasilkan salinan objek:
Ini berarti bahwa sebagian besar waktu, objek asli dibiarkan tidak berubah memberikan penampilan yang ruby adalah "lewat nilai".
Tentu saja ketika merancang kelas Anda sendiri, pemahaman tentang detail perilaku ini penting untuk perilaku fungsional, efisiensi memori dan kinerja.
sumber