Saya benar-benar baru mengenal Swift dan saya baru saja membaca bahwa kelas diteruskan oleh referensi dan array / string dll disalin.
Apakah cara lulus dengan referensi sama seperti di Objective-C atau Java di mana Anda benar-benar meneruskan referensi "a" atau apakah itu benar lewat referensi?
swift
pass-by-reference
pass-by-value
pass-by-pointer
gran_profaci.dll
sumber
sumber
Jawaban:
Jenis Hal di Swift
Aturannya adalah:
Instance kelas adalah tipe referensi (yaitu referensi Anda ke instance kelas secara efektif adalah pointer )
Fungsi adalah tipe referensi
Yang lainnya adalah tipe nilai ; "yang lainnya" berarti contoh dari struct dan contoh enum, karena hanya itu yang ada di Swift. Array dan string adalah instance struct, misalnya. Anda bisa meneruskan referensi ke salah satu dari hal itu (sebagai argumen fungsi) dengan menggunakan
inout
dan mengambil alamat, seperti yang ditunjukkan oleh newacct. Tapi tipe itu sendiri adalah tipe nilai.Apa Arti Jenis Referensi Bagi Anda
Objek tipe referensi dalam praktiknya khusus karena:
Penugasan belaka atau meneruskan ke fungsi dapat menghasilkan banyak referensi ke objek yang sama
Objek itu sendiri bisa berubah meskipun referensinya adalah konstanta (
let
, baik eksplisit maupun tersirat).Mutasi objek memengaruhi objek itu seperti yang terlihat oleh semua referensi padanya.
Itu bisa berbahaya, jadi waspadalah. Di sisi lain, meneruskan tipe referensi jelas efisien karena hanya sebuah pointer yang disalin dan diteruskan, yang sepele.
Apa Arti Jenis Nilai Bagi Anda
Jelas, meneruskan tipe nilai adalah "lebih aman", dan
let
berarti seperti yang dikatakan: Anda tidak dapat mengubah instance struct atau instance enum melaluilet
referensi. Di sisi lain, keamanan itu dicapai dengan membuat salinan nilai yang terpisah, bukan? Bukankah itu membuat pengoperan jenis nilai berpotensi mahal?Ya dan tidak. Ini tidak seburuk yang Anda kira. Seperti yang dikatakan Nate Cook, meneruskan tipe nilai tidak selalu berarti menyalin, karena
let
(eksplisit atau tersirat) menjamin keabadian sehingga tidak perlu menyalin apa pun. Dan bahkan melewati menjadivar
referensi tidak berarti bahwa hal-hal akan disalin, hanya bahwa mereka dapat jika diperlukan (karena ada mutasi). Para dokter secara khusus menyarankan Anda untuk tidak membengkokkan celana dalam.sumber
inout
terlepas dari tipenya. Apakah sesuatu itu lewat-demi-referensi adalah ortogonal terhadap tipe.Itu selalu nilai lewat jika parameternya tidak
inout
.Itu selalu merupakan referensi lewat jika parameternya adalah
inout
. Namun, ini agak rumit karena Anda perlu menggunakan&
operator secara eksplisit pada argumen saat meneruskan keinout
parameter, jadi mungkin tidak sesuai dengan definisi tradisional pass-by-reference, di mana Anda meneruskan variabel secara langsung.sumber
inout
)inout
sebenarnya tidak lewat referensi tapi copy-in copy-out Ini hanya menjamin bahwa nilai setelah panggilan fungsi diubah akan ditugaskan ke argumen asli. Parameter Masuk-KeluarSegala sesuatu di Swift diteruskan oleh "copy" secara default, jadi ketika Anda meneruskan tipe-nilai Anda mendapatkan salinan dari nilai tersebut, dan ketika Anda mengirimkan tipe referensi Anda mendapatkan salinan referensi, dengan semua yang tersirat. (Artinya, salinan referensi masih menunjuk ke contoh yang sama dengan referensi asli.)
Saya menggunakan kutipan menakutkan di sekitar "salinan" di atas karena Swift melakukan banyak pengoptimalan; sedapat mungkin, itu tidak menyalin sampai ada mutasi atau kemungkinan mutasi. Karena parameter tidak dapat diubah secara default, ini berarti seringkali tidak ada salinan yang benar-benar terjadi.
sumber
Berikut adalah contoh kode kecil untuk melewati referensi. Hindari melakukan ini, kecuali Anda punya alasan kuat.
Sebut saja seperti ini
sumber
inout
adalah salinan masuk, salinan keluar. Ini pertama-tama akan menyalin di objek, lalu menimpa objek asli setelah fungsi kembali. Meskipun kelihatannya sama, ada perbedaan yang tidak kentara.The Apel Swift Developer blog memiliki posting yang disebut Nilai dan Referensi Jenis yang menyediakan diskusi yang jelas dan rinci tentang topik ini sangat.
Kutipan:
Posting blog Swift terus menjelaskan perbedaan dengan contoh dan menyarankan kapan Anda akan menggunakan salah satunya.
sumber
Kelas dilewatkan oleh referensi dan yang lain diteruskan dengan nilai secara default. Anda dapat menyampaikan referensi dengan menggunakan
inout
kata kunci.sumber
inout
adalah salinan masuk, salinan keluar. Ini pertama-tama akan menyalin di objek, lalu menimpa objek asli setelah fungsi kembali. Meskipun kelihatannya sama, ada perbedaan yang tidak kentara.Jika Anda menggunakan inout dengan operator infix seperti + = maka simbol & alamat dapat diabaikan. Saya kira kompilator mengasumsikan lewat referensi?
origDictionary + = newDictionaryToAdd
Dan bagusnya kamus ini 'tambah' hanya melakukan satu tulisan ke referensi aslinya juga, sangat bagus untuk mengunci!
sumber
Kelas dan struktur
Salah satu perbedaan terpenting antara struktur dan kelas adalah bahwa struktur selalu disalin ketika diteruskan dalam kode Anda, tetapi kelas diteruskan oleh referensi.
Penutupan
Jika Anda menetapkan closure ke properti instance kelas, dan closure tersebut menangkap instance itu dengan merujuk ke instance atau anggotanya, Anda akan membuat siklus referensi yang kuat antara closure dan instance tersebut. Swift menggunakan daftar tangkapan untuk memutus siklus referensi yang kuat ini
ARC (Penghitungan Referensi Otomatis)
Penghitungan referensi hanya berlaku untuk instance kelas. Struktur dan enumerasi adalah tipe nilai, bukan tipe referensi, dan tidak disimpan dan diteruskan oleh referensi.
sumber