Tutorial SwiftUI yang baru memiliki kode berikut:
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
Baris kedua kata some
, dan di situs mereka disorot seolah-olah itu kata kunci.
Swift 5.1 tampaknya tidak memiliki some
kata kunci, dan saya tidak melihat apa lagi yang some
bisa dilakukan kata itu di sana, karena kata itu pergi ke tempat biasanya tipenya. Apakah ada versi Swift yang baru dan tidak diumumkan? Apakah ini fungsi yang digunakan pada tipe yang tidak saya ketahui?
Apa yang dilakukan kata kunci some
?
Jawaban:
some View
adalah tipe hasil buram seperti yang diperkenalkan oleh SE-0244 dan tersedia di Swift 5.1 dengan Xcode 11. Anda dapat menganggap ini sebagai pengganti generik "terbalik".Tidak seperti placeholder generik reguler yang dipenuhi oleh penelepon:
Jenis hasil buram adalah tempat penampung generik implisit puas dengan implementasi , sehingga Anda bisa memikirkan ini:
terlihat seperti ini:
Bahkan, tujuan akhirnya dengan fitur ini adalah untuk memungkinkan pembalikan generik dalam bentuk yang lebih eksplisit ini, yang juga memungkinkan Anda menambahkan batasan, misalnya
-> <T : Collection> T where T.Element == Int
. Lihat posting ini untuk info lebih lanjut .Hal utama yang harus diambil dari hal ini adalah bahwa fungsi yang dikembalikan
some P
adalah yang mengembalikan nilai jenis beton tunggal tertentu yang sesuaiP
. Mencoba untuk mengembalikan berbagai jenis yang sesuai dalam fungsi menghasilkan kesalahan kompilator:Karena placeholder generik implisit tidak dapat dipenuhi oleh beberapa tipe.
Ini berbeda dengan fungsi yang dikembalikan
P
, yang dapat digunakan untuk merepresentasikan keduanyaS1
danS2
karena itu merepresentasikanP
nilai kesesuaian yang berubah-ubah :Oke, jadi manfaat apa yang
-> some P
dimiliki tipe hasil buram daripada tipe protokol kembali-> P
?1. Jenis hasil buram dapat digunakan dengan PAT
Keterbatasan protokol saat ini adalah bahwa PATs (protokol dengan tipe terkait) tidak dapat digunakan sebagai tipe aktual. Meskipun ini adalah batasan yang kemungkinan akan diangkat dalam versi bahasa yang akan datang, karena jenis hasil buram secara efektif hanya penampung generik, mereka dapat digunakan dengan PATs hari ini.
Ini berarti Anda dapat melakukan hal-hal seperti:
2. Jenis hasil buram memiliki identitas
Karena tipe hasil buram menegakkan tipe beton tunggal dikembalikan, kompiler tahu bahwa dua panggilan ke fungsi yang sama harus mengembalikan dua nilai dari jenis yang sama.
Ini berarti Anda dapat melakukan hal-hal seperti:
Ini legal karena kompiler mengetahui keduanya
x
dany
memiliki tipe beton yang sama. Ini merupakan persyaratan penting untuk==
, di mana kedua parameter jenisSelf
.Ini berarti bahwa ia mengharapkan dua nilai yang sama-sama bertipe sama dengan tipe konformasi beton. Bahkan jika
Equatable
dapat digunakan sebagai tipe, Anda tidak akan dapat membandingkan duaEquatable
nilai kesesuaian yang berubah-ubah satu sama lain, misalnya:Sebagai kompiler tidak dapat membuktikan bahwa dua sewenang-wenang
Equatable
nilai memiliki tipe beton mendasar yang sama.Dengan cara yang sama, jika kami memperkenalkan fungsi pengembalian tipe buram lainnya:
Contoh menjadi ilegal karena meskipun keduanya
foo
danbar
kembalisome Equatable
, mereka "membalikkan" penampung generikOutput1
danOutput2
dapat dipenuhi oleh berbagai jenis.3. Jenis hasil buram menulis dengan penampung generik
Tidak seperti nilai yang diketikkan dengan protokol biasa, tipe hasil buram cocok dengan placeholder generik biasa, misalnya:
Ini tidak akan berhasil jika
makeP
baru saja kembaliP
, karena duaP
nilai mungkin memiliki tipe beton dasar yang berbeda, misalnya:Mengapa menggunakan jenis hasil buram di atas jenis beton?
Pada titik ini Anda mungkin berpikir untuk diri sendiri, mengapa tidak menulis kode saja sebagai:
Nah, penggunaan jenis hasil buram memungkinkan Anda untuk membuat jenis
S
detail implementasi dengan hanya mengekspos antarmuka yang disediakan olehP
, memberi Anda fleksibilitas untuk mengubah jenis beton di kemudian hari tanpa melanggar kode apa pun yang tergantung pada fungsi.Misalnya, Anda dapat mengganti:
dengan:
tanpa melanggar kode apa pun yang memanggil
makeP()
.Lihat bagian Jenis Buram dari panduan bahasa dan proposal evolusi Swift untuk informasi lebih lanjut tentang fitur ini.
sumber
return
tidak diperlukan dalam fungsi ekspresi tunggalfunc makeP() -> some P
danfunc makeP() -> P
? Saya telah membaca proposal, dan tidak dapat melihat perbedaan ini untuk sampel mereka juga.some P
akan dibutuhkanJawaban yang lain melakukan pekerjaan yang baik untuk menjelaskan aspek teknis dari
some
kata kunci baru tetapi jawaban ini akan mencoba menjelaskan mengapa dengan mudah .Katakanlah saya memiliki hewan protokol dan saya ingin membandingkan jika dua hewan bersaudara:
Dengan cara ini, masuk akal untuk membandingkan jika dua hewan adalah saudara kandung jika mereka adalah jenis hewan yang sama.
Sekarang izinkan saya membuat contoh binatang hanya untuk referensi
Jalan tanpa
some T
Sekarang katakanlah saya memiliki fungsi yang mengembalikan hewan dari 'keluarga'.
Sekarang masalah yang muncul adalah jika saya mencoba melakukan ini:
Ini akan menimbulkan kesalahan .
Mengapa? Yah alasannya adalah, ketika Anda menelepon
animal1.isSibling(animal2)
Swift tidak tahu apakah hewan itu anjing, kucing, atau apa pun. Sejauh Swift tahu,animal1
dananimal2
bisa jadi spesies hewan yang tidak terkait . Karena kita tidak dapat membandingkan hewan dari jenis yang berbeda (lihat di atas). Ini akan salahBagaimana
some T
mengatasi masalah iniMari kita menulis ulang fungsi sebelumnya:
animal1
dananimal2
yang tidakAnimal
, tetapi mereka adalah kelas yang mengimplementasikan Animal .Apa yang memungkinkan Anda lakukan sekarang adalah ketika Anda menelepon
animal1.isSibling(animal2)
, Swift tahu ituanimal1
dananimal2
adalah tipe yang sama.Jadi cara saya suka memikirkannya:
(Penafian promosi diri) Saya telah menulis posting blog yang sedikit lebih mendalam (contoh yang sama seperti di sini) pada fitur baru ini
sumber
some
di tipe kembali berfungsi sebagai kendala untuk tubuh fungsi. Jadisome
perlu mengembalikan hanya satu jenis beton di seluruh fungsi tubuh. Sebagai contoh: jika adareturn randomDog
maka semua pengembalian harus bekerja denganDog
. Semua manfaat berasal dari batasan ini: ketersediaananimal1.isSibling(animal2)
dan manfaat kompilasifunc animalFromAnimalFamily() -> some Animal
(karena sekarangSelf
menjadi didefinisikan di bawah tenda). Apakah itu benar?Jawaban Hamish cukup mengagumkan dan menjawab pertanyaan dari sudut pandang teknis. Saya ingin menambahkan beberapa pemikiran tentang mengapa kata kunci
some
tersebut digunakan di tempat khusus ini di tutorial SwiftUI Apple dan mengapa itu praktik yang baik untuk diikuti.some
Bukan Persyaratan!Pertama-tama, Anda tidak perlu mendeklarasikan
body
tipe pengembalian sebagai jenis buram. Anda selalu dapat mengembalikan jenis beton daripada menggunakansome View
.Ini akan dikompilasi juga. Ketika Anda melihat ke
View
antarmuka, Anda akan melihat bahwa tipe kembalinyabody
adalah tipe terkait:Ini berarti bahwa Anda menentukan jenis ini dengan membubuhi keterangan
body
properti dengan jenis tertentu pilihan Anda. Satu-satunya persyaratan adalah bahwa jenis ini perlu mengimplementasikanView
protokol itu sendiri.Itu bisa berupa tipe spesifik yang mengimplementasikan
View
, misalnyaText
Image
Circle
atau jenis buram yang mengimplementasikan
View
, yaitusome View
Tampilan Umum
Masalah muncul ketika kami mencoba menggunakan tampilan tumpukan sebagai
body
jenis pengembalian, sepertiVStack
atauHStack
:Ini tidak dapat dikompilasi dan Anda akan mendapatkan kesalahan:
Itu karena tampilan tumpukan di SwiftUI adalah tipe umum ! 💡 (Dan hal yang sama berlaku untuk Daftar dan jenis tampilan wadah lainnya.)
Itu masuk akal karena Anda dapat menyambungkan sejumlah tampilan jenis apa pun (asalkan sesuai dengan
View
protokol). Jenis konkret dariVStack
dalam tubuh di atas sebenarnyaKetika nanti kami memutuskan untuk menambahkan tampilan ke tumpukan, tipe konkretnya berubah. Jika kita menambahkan teks kedua setelah yang pertama, kita dapatkan
Bahkan jika kita membuat perubahan kecil, sesuatu yang halus seperti menambahkan spacer antara teks dan gambar, tipe tumpukan berubah:
Dari apa yang bisa saya katakan, itulah alasan mengapa Apple merekomendasikan dalam tutorial mereka untuk selalu menggunakan
some View
, jenis buram yang paling umum yang memuaskan semua pandangan, sebagaibody
jenis pengembalian. Anda dapat mengubah implementasi / tata letak tampilan kustom Anda tanpa secara manual mengubah jenis pengembalian setiap waktu.Suplemen:
Jika Anda ingin mendapatkan pemahaman yang lebih intuitif tentang jenis hasil buram, saya baru-baru ini menerbitkan sebuah artikel yang mungkin layak dibaca:
🔗 Apa ini "beberapa" di SwiftUI?
sumber
Saya pikir apa yang hilang semua jawaban sejauh ini adalah yang
some
berguna terutama dalam sesuatu seperti DSL (bahasa domain-spesifik) seperti SwiftUI atau perpustakaan / kerangka kerja, yang akan membuat pengguna (programmer lain) berbeda dari diri Anda.Anda mungkin tidak akan pernah menggunakan
some
kode aplikasi normal Anda, kecuali mungkin sejauh itu dapat membungkus protokol generik sehingga dapat digunakan sebagai tipe (bukan hanya sebagai tipe batasan). Apa yangsome
dilakukan adalah membiarkan kompiler menyimpan pengetahuan tentang jenis sesuatu yang spesifik, sambil menempatkan fasad supertipe di depannya.Jadi di SwiftUI, di mana Anda adalah pengguna, semua yang perlu Anda ketahui adalah bahwa ada sesuatu
some View
, sementara di belakang layar semua jenis saputangan dapat melanjutkan dari mana Anda dilindungi. Objek ini sebenarnya tipe yang sangat spesifik, tetapi Anda tidak perlu mendengar tentang apa itu. Namun, tidak seperti protokol, itu adalah tipe yang lengkap, karena di mana pun itu muncul itu hanya fasad untuk beberapa tipe spesifik penuh.Dalam versi SwiftUI yang akan datang, di mana Anda mengharapkan
some View
, pengembang dapat mengubah jenis objek tertentu yang mendasarinya. Tapi itu tidak akan merusak kode Anda, karena kode Anda tidak pernah menyebutkan tipe yang mendasarinya.Jadi,
some
pada dasarnya membuat protokol lebih seperti superclass. Ini hampir merupakan tipe objek nyata, meskipun tidak cukup (misalnya, deklarasi metode protokol tidak dapat mengembalikan asome
).Jadi, jika Anda akan menggunakan
some
apa pun, kemungkinan besar adalah jika Anda menulis DSL atau framework / library untuk digunakan oleh orang lain, dan Anda ingin menutupi detail tipe yang mendasarinya. Ini akan membuat kode Anda lebih mudah digunakan orang lain, dan memungkinkan Anda untuk mengubah detail implementasi tanpa melanggar kode mereka.Namun, Anda juga dapat menggunakannya dalam kode Anda sendiri sebagai cara melindungi satu wilayah kode Anda dari rincian implementasi yang terkubur di wilayah lain dari kode Anda.
sumber
Kata
some
kunci dari Swift 5.1 ( proposal evolusi cepat ) digunakan bersama dengan Protokol sebagai jenis pengembalian.Catatan rilis Xcode 11 menyajikannya seperti itu:
Pada contoh di atas, Anda tidak perlu memberi tahu bahwa Anda akan mengembalikan
Array
. Itu memungkinkan Anda untuk bahkan mengembalikan tipe generik yang hanya sesuaiCollection
.Perhatikan juga kemungkinan kesalahan ini yang mungkin Anda hadapi:
Ini berarti Anda harus menggunakan ketersediaan untuk menghindari
some
di iOS 12 dan sebelumnya:sumber
some
di iOS 12 dan sebelumnya. Selama Anda melakukannya, Anda harus baik-baik saja. Masalahnya hanya bahwa kompiler tidak memperingatkan Anda untuk melakukan ini.some
kata kunci dalam contoh kode yang diberikan ini di Swift 5.0 atau Swift 4.2. Kesalahannya adalah: " Protokol 'Pengumpulan' hanya dapat digunakan sebagai batasan umum karena memiliki persyaratan tipe Self atau yang terkait "'some' berarti tipe buram. Di SwiftUI, View dideklarasikan sebagai protokol
Saat Anda membuat tampilan Anda sebagai Struct, Anda mematuhi protokol View dan mengatakan bahwa var body akan mengembalikan sesuatu yang akan mengkonfirmasi ke View Protocol. Ini seperti abstraksi protokol generik di mana Anda tidak perlu mendefinisikan tipe konkret.
sumber
Saya akan mencoba menjawab ini dengan contoh praktis yang sangat mendasar (apa ini jenis hasil buram tentang)
Dengan asumsi Anda memiliki protokol dengan tipe terkait, dan dua struct mengimplementasikannya:
Sebelum Swift 5.1, di bawah ini ilegal karena
ProtocolWithAssociatedType can only be used as a generic constraint
kesalahan:Tetapi dalam Swift 5.1 ini baik-baik saja (
some
ditambahkan):Di atas adalah penggunaan praktis, banyak digunakan dalam SwiftUI untuk
some View
.Tetapi ada satu batasan penting - tipe pengembalian perlu diketahui pada waktu kompilasi, jadi di bawah ini tidak akan berfungsi memberikan
Function declares an opaque return type, but the return statements in its body do not have matching underlying types
kesalahan:sumber
Kasus penggunaan sederhana yang muncul di pikiran adalah menulis fungsi generik untuk tipe numerik.
sumber
Bagi mereka yang pusing dengan subjek, di sini artikel yang sangat mendekripsi dan langkah demi langkah terima kasih kepada Vadim Bulavin.
https://www.vadimbulavin.com/opaque-return-types-and-the-some-keyword-in-swift/
sumber