Apa kata kunci `some` di Swift (UI)?

259

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 somekata kunci, dan saya tidak melihat apa lagi yang somebisa 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?

Nicholas
sumber
Bagi mereka yang pusing dengan subjek, di sini artikel yang sangat mendekripsi dan langkah demi langkah terima kasih kepada Vadim Bulavin. vadimbulavin.com/...
Luc-Olivier

Jawaban:

333

some Viewadalah 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:

protocol P {}
struct S1 : P {}
struct S2 : P {}

func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.

Jenis hasil buram adalah tempat penampung generik implisit puas dengan implementasi , sehingga Anda bisa memikirkan ini:

func bar() -> some P {
  return S1() // Implementation chooses S1 for the opaque result.
}

terlihat seperti ini:

func bar() -> <Output : P> Output {
  return S1() // Implementation chooses Output == S1.
}

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 Padalah yang mengembalikan nilai jenis beton tunggal tertentu yang sesuai P. Mencoba untuk mengembalikan berbagai jenis yang sesuai dalam fungsi menghasilkan kesalahan kompilator:

// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
  if x > 10 {
    return S1()
  } else {
    return S2()
  }
}

Karena placeholder generik implisit tidak dapat dipenuhi oleh beberapa tipe.

Ini berbeda dengan fungsi yang dikembalikan P, yang dapat digunakan untuk merepresentasikan keduanya S1 dan S2karena itu merepresentasikan Pnilai kesesuaian yang berubah-ubah :

func baz(_ x: Int) -> P {
  if x > 10 {
    return S1()
  } else {
    return S2()
  }
}

Oke, jadi manfaat apa yang -> some Pdimiliki 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:

func giveMeACollection() -> some Collection {
  return [1, 2, 3]
}

let collection = giveMeACollection()
print(collection.count) // 3

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:

//   foo() -> <Output : Equatable> Output {
func foo() -> some Equatable { 
  return 5 // The opaque result type is inferred to be Int.
}

let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.

Ini legal karena kompiler mengetahui keduanya xdan ymemiliki tipe beton yang sama. Ini merupakan persyaratan penting untuk ==, di mana kedua parameter jenis Self.

protocol Equatable {
  static func == (lhs: Self, rhs: Self) -> Bool
}

Ini berarti bahwa ia mengharapkan dua nilai yang sama-sama bertipe sama dengan tipe konformasi beton. Bahkan jika Equatabledapat digunakan sebagai tipe, Anda tidak akan dapat membandingkan dua Equatablenilai kesesuaian yang berubah-ubah satu sama lain, misalnya:

func foo(_ x: Int) -> Equatable { // Assume this is legal.
  if x > 10 {
    return 0
  } else {
    return "hello world"      
  }
}

let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.

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:

//   foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable { 
  return 5 // The opaque result type is inferred to be Int.
}

//   bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable { 
  return "" // The opaque result type is inferred to be String.
}

let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.

Contoh menjadi ilegal karena meskipun keduanya foodan barkembali some Equatable, mereka "membalikkan" penampung generik Output1dan Output2dapat 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:

protocol P {
  var i: Int { get }
}
struct S : P {
  var i: Int
}

func makeP() -> some P { // Opaque result type inferred to be S.
  return S(i: .random(in: 0 ..< 10))
}

func bar<T : P>(_ x: T, _ y: T) -> T {
  return x.i < y.i ? x : y
}

let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.

Ini tidak akan berhasil jika makePbaru saja kembali P, karena dua Pnilai mungkin memiliki tipe beton dasar yang berbeda, misalnya:

struct T : P {
  var i: Int
}

func makeP() -> P {
  if .random() { // 50:50 chance of picking each branch.
    return S(i: 0)
  } else {
    return T(i: 1)
  }
}

let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.

Mengapa menggunakan jenis hasil buram di atas jenis beton?

Pada titik ini Anda mungkin berpikir untuk diri sendiri, mengapa tidak menulis kode saja sebagai:

func makeP() -> S {
  return S(i: 0)
}

Nah, penggunaan jenis hasil buram memungkinkan Anda untuk membuat jenis Sdetail 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:

func makeP() -> some P {
  return S(i: 0)
}

dengan:

func makeP() -> some P { 
  return T(i: 1)
}

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.

Hamish
sumber
20
Tidak terkait: Pada Swift 5.1, returntidak diperlukan dalam fungsi ekspresi tunggal
ielyamani
3
Tapi apa perbedaan antara: func makeP() -> some Pdan func makeP() -> P? Saya telah membaca proposal, dan tidak dapat melihat perbedaan ini untuk sampel mereka juga.
Artem
2
Penanganan tipe Swifts berantakan. Apakah kekhususan ini benar-benar sesuatu yang tidak dapat ditangani pada waktu kompilasi? Lihat C # untuk referensi yang menangani semua kasus ini secara implisit melalui sintaksis sederhana. Swifts perlu memiliki sintaksis kargo-kultus yang hampir tidak ada gunanya dan benar-benar mengaburkan bahasa. Bisakah Anda menjelaskan alasan desain untuk ini? (Jika Anda memiliki tautan ke proposal di github, itu juga bagus) Sunting: Hanya perhatikan itu tertaut di bagian atas.
SacredGeometry
2
@Zmaster Kompilator akan memperlakukan dua jenis pengembalian buram sebagai berbeda bahkan jika implementasi untuk keduanya mengembalikan jenis beton yang sama. Dengan kata lain, jenis beton tertentu yang dipilih disembunyikan dari penelepon. (Saya bermaksud memperluas bagian kedua dari jawaban saya untuk membuat hal-hal seperti ini sedikit lebih eksplisit, tetapi belum sempat untuk itu).
Hamish
52

Jawaban yang lain melakukan pekerjaan yang baik untuk menjelaskan aspek teknis dari somekata kunci baru tetapi jawaban ini akan mencoba menjelaskan mengapa dengan mudah .


Katakanlah saya memiliki hewan protokol dan saya ingin membandingkan jika dua hewan bersaudara:

protocol Animal {
    func isSibling(_ animal: Self) -> Bool
}

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

class Dog: Animal {
    func isSibling(_ animal: Dog) -> Bool {
        return true // doesn't really matter implementation of this
    }
}

Jalan tanpa some T

Sekarang katakanlah saya memiliki fungsi yang mengembalikan hewan dari 'keluarga'.

func animalFromAnimalFamily() -> Animal {
    return myDog // myDog is just some random variable of type `Dog`
}

Catatan: fungsi ini sebenarnya tidak bisa dikompilasi. Ini karena sebelum fitur 'beberapa' ditambahkan, Anda tidak dapat mengembalikan jenis protokol jika protokol menggunakan 'Cukup' atau generik . Tapi katakanlah Anda bisa ... berpura-pura ini meng-mydog hewan abstrak, mari kita lihat apa yang terjadi

Sekarang masalah yang muncul adalah jika saya mencoba melakukan ini:

let animal1: Animal = animalFromAnimalFamily()
let animal2: Animal = animalFromAnimalFamily()

animal1.isSibling(animal2) // error

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, animal1dan animal2bisa jadi spesies hewan yang tidak terkait . Karena kita tidak dapat membandingkan hewan dari jenis yang berbeda (lihat di atas). Ini akan salah

Bagaimana some Tmengatasi masalah ini

Mari kita menulis ulang fungsi sebelumnya:

func animalFromAnimalFamily() -> some Animal {
    return myDog
}
let animal1 = animalFromAnimalFamily()
let animal2 = animalFromAnimalFamily()

animal1.isSibling(animal2)

animal1dan animal2yang tidak Animal , tetapi mereka adalah kelas yang mengimplementasikan Animal .

Apa yang memungkinkan Anda lakukan sekarang adalah ketika Anda menelepon animal1.isSibling(animal2), Swift tahu itu animal1dan animal2adalah tipe yang sama.

Jadi cara saya suka memikirkannya:

some Tmemungkinkan Swift mengetahui implementasi apa Tyang sedang digunakan tetapi pengguna kelas tidak.

(Penafian promosi diri) Saya telah menulis posting blog yang sedikit lebih mendalam (contoh yang sama seperti di sini) pada fitur baru ini

Downgoat
sumber
2
Jadi ide Anda adalah bahwa penelepon dapat mengambil keuntungan dari kenyataan bahwa dua panggilan ke fungsi mengembalikan tipe yang sama meskipun penelepon tidak tahu tipe apa itu?
matt
1
@ Matt dasarnya yup. Konsep yang sama ketika digunakan dengan bidang, dll— penelepon diberikan jaminan bahwa tipe pengembalian akan selalu menjadi tipe yang sama tetapi tidak mengungkapkan apa jenisnya.
Downgoat
@Downgoat terima kasih banyak atas kiriman dan jawaban yang sempurna. Seperti yang saya mengerti somedi tipe kembali berfungsi sebagai kendala untuk tubuh fungsi. Jadi someperlu mengembalikan hanya satu jenis beton di seluruh fungsi tubuh. Sebagai contoh: jika ada return randomDogmaka semua pengembalian harus bekerja dengan Dog. Semua manfaat berasal dari batasan ini: ketersediaan animal1.isSibling(animal2)dan manfaat kompilasi func animalFromAnimalFamily() -> some Animal(karena sekarang Selfmenjadi didefinisikan di bawah tenda). Apakah itu benar?
Artem
5
Baris ini yang saya butuhkan, animal1 dan animal2 bukan Animal, tapi mereka kelas yang mengimplementasikan Animal, sekarang semuanya masuk akal!
aross
29

Jawaban Hamish cukup mengagumkan dan menjawab pertanyaan dari sudut pandang teknis. Saya ingin menambahkan beberapa pemikiran tentang mengapa kata kunci sometersebut 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 bodytipe pengembalian sebagai jenis buram. Anda selalu dapat mengembalikan jenis beton daripada menggunakan some View.

struct ContentView: View {
    var body: Text {
        Text("Hello World")
    }
}

Ini akan dikompilasi juga. Ketika Anda melihat ke Viewantarmuka, Anda akan melihat bahwa tipe kembalinya bodyadalah tipe terkait:

public protocol View : _View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    associatedtype Body : View

    /// Declares the content and behavior of this view.
    var body: Self.Body { get }
}

Ini berarti bahwa Anda menentukan jenis ini dengan membubuhi keterangan bodyproperti dengan jenis tertentu pilihan Anda. Satu-satunya persyaratan adalah bahwa jenis ini perlu mengimplementasikan Viewprotokol itu sendiri.

Itu bisa berupa tipe spesifik yang mengimplementasikan View, misalnya

  • Text
  • Image
  • Circle
  • ...

atau jenis buram yang mengimplementasikan View, yaitu

  • some View

Tampilan Umum

Masalah muncul ketika kami mencoba menggunakan tampilan tumpukan sebagai bodyjenis pengembalian, seperti VStackatau HStack:

struct ContentView: View {
    var body: VStack {
        VStack {
            Text("Hello World")
            Image(systemName: "video.fill")
        }
    }
}

Ini tidak dapat dikompilasi dan Anda akan mendapatkan kesalahan:

Referensi ke tipe umum 'VStack' membutuhkan argumen di <...>

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 Viewprotokol). Jenis konkret dari VStackdalam tubuh di atas sebenarnya

VStack<TupleView<(Text, Image)>>

Ketika nanti kami memutuskan untuk menambahkan tampilan ke tumpukan, tipe konkretnya berubah. Jika kita menambahkan teks kedua setelah yang pertama, kita dapatkan

VStack<TupleView<(Text, Text, Image)>>    

Bahkan jika kita membuat perubahan kecil, sesuatu yang halus seperti menambahkan spacer antara teks dan gambar, tipe tumpukan berubah:

VStack<TupleView<(Text, _ModifiedContent<Spacer, _FrameLayout>, Image)>>

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, sebagai bodyjenis 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?

Mischa
sumber
2
Ini. Terima kasih! Jawaban Hamish sangat lengkap, tetapi jawaban Anda memberi tahu saya persis mengapa itu digunakan dalam contoh-contoh ini.
Chris Marshall
Saya suka ide "beberapa". Adakah ide jika menggunakan "beberapa" memengaruhi waktu kompilasi sama sekali?
Tofu Warrior
@Mischa jadi bagaimana cara membuat tampilan generik? dengan protokol yang berisi pandangan dan perilaku lain?
theMouk
27

Saya pikir apa yang hilang semua jawaban sejauh ini adalah yang someberguna 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 somekode aplikasi normal Anda, kecuali mungkin sejauh itu dapat membungkus protokol generik sehingga dapat digunakan sebagai tipe (bukan hanya sebagai tipe batasan). Apa yang somedilakukan 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, somepada dasarnya membuat protokol lebih seperti superclass. Ini hampir merupakan tipe objek nyata, meskipun tidak cukup (misalnya, deklarasi metode protokol tidak dapat mengembalikan a some).

Jadi, jika Anda akan menggunakan someapa 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.

matt
sumber
23

Kata somekunci dari Swift 5.1 ( proposal evolusi cepat ) digunakan bersama dengan Protokol sebagai jenis pengembalian.

Catatan rilis Xcode 11 menyajikannya seperti itu:

Fungsi sekarang dapat menyembunyikan tipe pengembalian konkretnya dengan mendeklarasikan protokol apa yang sesuai dengannya, alih-alih menentukan jenis pengembalian yang tepat:

func makeACollection() -> some Collection {
    return [1, 2, 3]
}

Kode yang memanggil fungsi dapat menggunakan antarmuka protokol, tetapi tidak memiliki visibilitas ke tipe yang mendasarinya. ( SE-0244 , 40538331)

Pada contoh di atas, Anda tidak perlu memberi tahu bahwa Anda akan mengembalikan Array. Itu memungkinkan Anda untuk bahkan mengembalikan tipe generik yang hanya sesuai Collection.


Perhatikan juga kemungkinan kesalahan ini yang mungkin Anda hadapi:

jenis pengembalian 'beberapa' hanya tersedia di iOS 13.0.0 atau lebih baru

Ini berarti Anda harus menggunakan ketersediaan untuk menghindari somedi iOS 12 dan sebelumnya:

@available(iOS 13.0, *)
func makeACollection() -> some Collection {
    ...
}
Cur
sumber
1
Terima kasih banyak atas jawaban terfokus ini dan masalah kompiler dalam Xcode 11 beta
brainray
1
Anda seharusnya menggunakan ketersediaan untuk menghindari somedi iOS 12 dan sebelumnya. Selama Anda melakukannya, Anda harus baik-baik saja. Masalahnya hanya bahwa kompiler tidak memperingatkan Anda untuk melakukan ini.
matt
2
Cœur, seperti yang Anda tunjukkan, deskripsi Apple yang ringkas menjelaskan semuanya: Fungsi sekarang dapat menyembunyikan jenis pengembalian konkretnya dengan mendeklarasikan protokol apa yang sesuai dengannya, alih-alih menentukan jenis pengembalian yang tepat. Dan kemudian kode memanggil fungsi dapat menggunakan antarmuka protokol. Rapi dan kemudian beberapa.
Fattie
Ini (menyembunyikan tipe pengembalian konkret) sudah dimungkinkan tanpa menggunakan kata kunci "some". Itu tidak menjelaskan efek menambahkan "beberapa" ke dalam metode tanda tangan.
Vince O'Sullivan
@ VinceO'Sullivan Tidak mungkin untuk menghapus somekata 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 "
Cœur
2

'some' berarti tipe buram. Di SwiftUI, View dideklarasikan sebagai protokol

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    associatedtype Body : View

    /// Declares the content and behavior of this view.
    var body: Self.Body { get }
}

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.

varunrathi28
sumber
2

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:

protocol ProtocolWithAssociatedType {
    associatedtype SomeType
}

struct First: ProtocolWithAssociatedType {
    typealias SomeType = Int
}

struct Second: ProtocolWithAssociatedType {
    typealias SomeType = String
}

Sebelum Swift 5.1, di bawah ini ilegal karena ProtocolWithAssociatedType can only be used as a generic constraintkesalahan:

func create() -> ProtocolWithAssociatedType {
    return First()
}

Tetapi dalam Swift 5.1 ini baik-baik saja ( someditambahkan):

func create() -> some ProtocolWithAssociatedType {
    return First()
}

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 typeskesalahan:

func create() -> some ProtocolWithAssociatedType {
    if (1...2).randomElement() == 1 {
        return First()
    } else {
        return Second()
    }
}
tzaloga
sumber
0

Kasus penggunaan sederhana yang muncul di pikiran adalah menulis fungsi generik untuk tipe numerik.

/// Adds one to any decimal type
func addOne<Value: FloatingPoint>(_ x: Value) -> some FloatingPoint {
    x + 1
}

// Variables will be assigned 'some FloatingPoint' type
let double = addOne(Double.pi) // 4.141592653589793
let float = addOne(Float.pi) // 4.141593

// Still get all of the required attributes/functions by the FloatingPoint protocol
double.squareRoot() // 2.035090330572526
float.squareRoot() // 2.03509

// Be careful, however, not to combine 2 'some FloatingPoint' variables
double + double // OK 
//double + float // error
Artem Ilyumzhinov
sumber