Generic (generic na programming) — ay isang mekanismo ng Swift na nagpapahintulot sa pagsulat ng mga uri at function na may parametrisadong uri
Mga Pangunahing Punto
Generic (generic na uri) — ay isang syntactic na konstruksyon ng Swift na nagpapahintulot sa pagsulat ng nababaluktot, magagamit muli na code na may parametrisasyon ng uri. Sa halip ng konkretong uri, isang placeholder ay isinusulat sa mga angle bracket — karaniwang
Kung walang generic, kailangan isulat ang magkakahiwalay na function para sa bawat uri: swapInts, swapStrings, swapDates. Ang generic na function na swap ay pumapalit sa lahat ng tatlong variant na may isang deklarasyon. Ito ay nagbabawas ng pag-duplicate, nagpapataas ng pagiging nababasa, at nagpapababa ng posibilidad ng mga pagkakamali sa pagkopya ng code.
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var x = 10
var y = 20
swapValues(&x, &y)
Ang Swift compiler ay lumilikha ng espesyalisadong code para sa bawat konkretong paggamit ng generic. Ibig sabihin nito na ang generic na function na swapValues
Mga generic na function — ay mga function na tumatanggap ng isa o higit pang mga parameter-uri. Ang mga parameter-uri ay ipinapakita pagkatapos ng pangalan ng function sa mga angle bracket:
Ang isang function ay maaaring magkaroon ng maramihang generic na parameter. Halimbawa, ang function na findKey
func findKey<K: Hashable, V>(
for value: V,
in dictionary: [K: V]
) -> K? where V: Equatable {
for (key, dictValue) in dictionary {
if dictValue == value {
return key
}
}
return nil
}
Ang mga paghihigpit na K: Hashable at where V: Equatable ay ginagarantiyahan na ang findKey ay matawag lamang sa isang dictionary na ang mga key ay nahahash at ang mga value ay maihahambing. Ang mga ganitong paghihigpit ay hindi burukrasya, kundi pangangailangan: kung walang Hashable, hindi maindeks ang paghahanap sa pamamagitan ng key, kung walang Equatable, hindi maihahambing ang value sa dictValue.
where — ay isang keyword ng Swift na nagpapataw ng karagdagang mga paghihigpit sa mga generic na parameter. Hindi tulad ng simpleng pagtukoy ng protocol sa mga angle bracket (
Ang where clause ay isinusulat pagkatapos ng signature ng function o uri, bago ang pambukas na curly brace. Sa where maaaring tukuyin na T: Comparable & Hashable (sabay na dalawang protocol), o na T.U == Int (konkretisasyon ng associated type).
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
}
extension Container where Item: Comparable {
func isSorted() -> Bool {
// Implementation available only if Item: Comparable
return true
}
}
Ang extension na may where ay nagdadagdag ng mga pamamaraan lamang para sa mga uri na nakakatugon sa kondisyon. Ang Container
Associated Types (mga kaugnay na uri) — ay isang paraan upang gawing generic ang protocol nang hindi tinutukoy ang konkretong uri sa phase ng deklarasyon. Sa halip ng
Sa tulong ng where, ang mga ugnayan ay maaaring itatag sa pagitan ng associated types ng iba't ibang mga protocol. Halimbawa, maaaring kailanganin na ang Item ng isang protocol ay tumugma sa Iterator.Element ng isa pa. Ito ay ginagarantiyahan ang pagiging tugma ng uri sa antas ng compilation.
protocol StackProtocol {
associatedtype Element
mutating func push(_ item: Element)
mutating func pop() -> Element?
}
struct IntStack: StackProtocol {
typealias Element = Int
private var items: [Int] = []
mutating func push(_ item: Int) { items.append(item) }
mutating func pop() -> Int? { items.popLast() }
}
Ang IntStack ay nagkokonkreto ng Element bilang Int, gamit ang typealias. Ang compiler ay nagsusuri kung ang lahat ng mga kinakailangan ng protocol ay natutugunan sa uri na ito. Kung walang associated types, kailangan isulat ang StackProtocol
Mga generic na extension ay nagpapahintulot sa pagdaragdag ng mga pamamaraan sa generic na uri na may karagdagang mga paghihigpit. Ito ay pattern ng “kondisyonal na pagsunod”, kung saan ang uri ay nakakakuha ng pag-andar lamang sa ilalim ng tiyak na mga kondisyon. Ang mga subscript ay maaari ding maging generic.
Ang isang subscript ay maaaring maging generic: ito ay tumatanggap ng generic na mga parameter sa mga angle bracket. Ito ay kapaki-pakinabang para sa ligtas na pag-access sa mga koleksyon na may arbitraryong index, kung saan ang index ay maaaring maging iba't ibang uri.
extension Array where Element: Numeric {
func sum() -> Element {
return reduce(0, +)
}
}
extension Array {
subscript<Indices: Sequence>(indices: Indices) -> [Element]
where Indices.Element == Int {
return indices.map { self[$0] }
}
}
Ang ganitong konstruksyon ay nagbibigay ng malakas na komposisyon: ang pamamaraang sum ay lumilitaw lamang sa mga numerikong array, at ang subscript na may arbitraryong mga index ay gumagana sa anumang sequence ng integer na mga index. Ang compiler mismo ang namamahala sa visibility ng mga miyembrong ito batay sa mga kondisyon ng where.
Mga pagkakamali sa paggamit ng generic ay madalas na nauugnay sa hindi tamang mga paghihigpit o pagtatangkang gamitin ang generic kung saan kailangan ang konkretong uri. Tingnan natin ang tatlong karaniwang senaryo na kinakaharap ng mga developer.
Ang pagdaragdag ng mga generic na parameter kung saan sapat na ang konkretong uri — ay isang anti-pattern. Kung ang isang function ay palaging gumagana sa String, hindi kailangang gawin itong
Ang pagtawag ng pamamaraan sa isang generic na parameter nang hindi tinutukoy na ang pamamaraan ay umiiral — ay isang pagkakamali.
// ❌ Error: value has no count method
func countElements<T>>(value: T) -> Int { value.count }
// ✅ Works: T: Collection guarantees count exists
func countElements<T: Collection>(value: T) -> Int { value.count }
Ang pagkakamali ay mauunawaan: ang generic
Mga Madalas Itanong
Generic — ay isang paraan ng pagsulat ng code na gumagana sa anumang uri, nang hindi nadu-duplicate ang parehong lohika para sa Int, String at iba pang uri. Sa halip ng konkretong uri, ginagamit ang placeholder
Generic ay nagpapanatili ng impormasyon tungkol sa konkretong uri sa compilation phase, na nagpapahintulot sa compiler na suriin ang mga uri at lumikha ng optimize na code. Any — ay pagbura ng uri: anumang halaga ay maaaring ipasa, ngunit ang uri ay nawawala at kinakailangan ang conversion (as?).
Gamitin ang syntax na T: SomeProtocol sa mga angle bracket o isang hiwalay na clause na where T: SomeProtocol. Ginagarantiyahan ng mga paghihigpit na ang generic na parameter ay sumusuporta sa tiyak na mga pamamaraan at pag-aari.
Associated Type (associatedtype) — ay isang placeholder para sa uri sa loob ng protocol. Ang protocol ay hindi tumutukoy ng konkretong uri, kundi nagdedeklara ng associatedtype na konkretisado sa implementasyon: ang Array ay may Element, ang Dictionary — Key at Value.
Ang Swift ay nagko-compile ng generic code sa espesyalisadong bersyon para sa bawat konkretong uri. Sa praktika, ang generic na function para sa Int ay hindi mas mabagal kaysa sa manual na isinulat na function para sa Int. Walang overhead para sa abstraction.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din