Generic — esensi tipe generik dan parameter T

Penulis: IT Sectr Diterbitkan: 2026-06-18 Waktu membaca: 10 mnt

Generic (pemrograman generik) — adalah mekanisme Swift yang memungkinkan penulisan tipe dan fungsi dengan tipe terparameterisasi . Alih-alih menduplikasi kode untuk Int, String, dan struktur khusus, pengembang membuat solusi generik yang bekerja dengan tipe apa pun, sambil mempertahankan pengetikan yang ketat. Kompiler mengganti tipe konkret pada saat penggunaan, yang menjamin keamanan tanpa kehilangan kinerja. Menurut Swift Book, 2025, parameter generik adalah salah satu kemampuan kunci bahasa, yang mendasari perpustakaan standar dan SwiftUI.

Poin Utama

  • Generic — mekanisme pemrograman generik dengan parameter-tipe
  • Fungsi dengan parameter generik bekerja dengan tipe apa pun tanpa duplikasi kode
  • Batasan where mempersempit cakupan generik ke tipe yang memenuhi kondisi
  • Associated Types dalam protokol memungkinkan protokol menjadi generik
  • Kompiler menghasilkan kode terspesialisasi untuk setiap tipe konkret

Apa itu Generic di Swift?

Generic (tipe generik) — adalah konstruksi sintaksis Swift yang memungkinkan penulisan kode yang fleksibel dan dapat digunakan kembali dengan parameterisasi tipe. Alih-alih tipe konkret, placeholder ditulis dalam tanda kurung siku — biasanya , tetapi nama apa pun dapat digunakan. Generic mendasari SwiftUI (View, some View), perpustakaan standar (Array, Optional), dan Combine.

Mengapa Generic diperlukan

Tanpa generik, fungsi terpisah harus ditulis untuk setiap tipe: swapInts, swapStrings, swapDates. Fungsi generik swap menggantikan ketiga varian dengan satu deklarasi. Ini mengurangi duplikasi, meningkatkan keterbacaan, dan mengurangi kemungkinan kesalahan saat menyalin kode.

swift
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)

Kompiler Swift menghasilkan kode terspesialisasi untuk setiap penggunaan generik yang konkret. Ini berarti fungsi generik swapValues tidak memiliki overhead dibandingkan dengan fungsi yang ditulis manual untuk Int. Swift tidak menggunakan penghapusan tipe seperti Java — generik ada baik dalam fase kompilasi maupun runtime (meskipun optimasi dapat menspesialisasikannya).

Fungsi generik dengan parameter T

Fungsi generik — adalah fungsi yang menerima satu atau lebih parameter-tipe. Parameter-tipe ditunjukkan setelah nama fungsi dalam tanda kurung siku: . Mereka dapat digunakan dalam tanda tangan: tipe argumen, tipe kembalian, dan di dalam badan fungsi.

Beberapa parameter-tipe

Sebuah fungsi dapat memiliki beberapa parameter generik. Misalnya, fungsi findKey menerima kamus dengan kunci K dan nilai V. Setiap parameter-tipe unik dan dapat digunakan dalam batasan.

swift
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
}

Batasan K: Hashable dan where V: Equatable menjamin bahwa findKey hanya dapat dipanggil dengan kamus yang kuncinya dapat di-hash dan nilainya dapat dibandingkan. Batasan semacam itu bukan birokrasi, tetapi kebutuhan: tanpa Hashable, pencarian berdasarkan kunci tidak dapat diindeks, tanpa Equatable, value tidak dapat dibandingkan dengan dictValue.

Batasan tipe melalui where

where — adalah kata kunci Swift yang memberlakukan batasan tambahan pada parameter generik. Tidak seperti penentuan protokol sederhana dalam tanda kurung siku (), where memungkinkan pengungkapan kondisi yang lebih kompleks: kepatuhan terhadap beberapa protokol, hubungan antara parameter-tipe, dan penyempurnaan associated types.

Sintaks where

Klausa where ditulis setelah tanda tangan fungsi atau tipe, sebelum kurung kurawal pembuka. Dalam where dapat ditentukan bahwa T: Comparable & Hashable (dua protokol sekaligus), atau bahwa T.U == Int (konkretisasi associated type).

swift
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
    }
}

Ekstensi dengan where menambahkan metode hanya untuk tipe-tipe yang memenuhi kondisi. Container mendapatkan metode isSorted, sedangkan Container tidak, karena Any tidak Comparable. Ini adalah mekanisme fungsionalitas bersyarat yang kuat.

Associated Types dalam protokol

Associated Types (tipe terkait) — adalah cara untuk membuat protokol menjadi generik tanpa menentukan tipe konkret pada fase deklarasi. Alih-alih , protokol mendeklarasikan associatedtype, yang dikonkretisasi dalam implementasi. Ini sangat penting untuk koleksi: protokol Sequence tidak tahu elemen apa yang akan dimuat oleh sekuens.

Hubungan associated types melalui where

Dengan where, hubungan dapat dibuat antara associated types dari protokol yang berbeda. Misalnya, dapat diharuskan bahwa Item dari satu protokol cocok dengan Iterator.Element dari protokol lain. Ini menjamin kompatibilitas tipe pada tingkat kompilasi.

swift
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() }
}

IntStack mengkonkretisasi Element sebagai Int, menggunakan typealias. Kompiler memeriksa apakah semua persyaratan protokol terpenuhi dengan tipe ini. Tanpa associated types, StackProtocol dengan protokol generik harus ditulis, tetapi Swift menggunakan associated types untuk keseragaman dengan jembatan Objective-C dan keterbacaan yang lebih baik.

Generic dalam ekstensi dan subscript

Ekstensi generik memungkinkan penambahan metode ke tipe generik dengan batasan tambahan. Ini adalah pola “konformitas bersyarat”, ketika tipe mendapatkan fungsionalitas hanya dalam kondisi tertentu. Subscript juga bisa bersifat generik.

Subscript generik

Subscript dapat bersifat generik: ia menerima parameter generik dalam tanda kurung siku. Ini berguna untuk akses aman ke koleksi dengan indeks arbitrer, ketika indeks dapat berupa tipe yang berbeda.

swift
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] }
    }
}

Konstruksi semacam itu memberikan komposisi yang kuat: metode sum muncul hanya di array numerik, dan subscript dengan indeks arbitrer bekerja dengan sekuens indeks bilangan bulat apa pun. Kompiler sendiri mengelola visibilitas anggota-anggota ini berdasarkan kondisi where.

Kesalahan umum saat bekerja dengan generik

Kesalahan saat menggunakan generik sering terkait dengan batasan yang salah atau upaya menggunakan generik di mana tipe konkret diperlukan. Mari kita lihat tiga skenario umum yang dihadapi pengembang.

Parameterisasi berlebihan

Menambahkan parameter generik di mana tipe konkret sudah cukup — adalah anti-pola. Jika suatu fungsi selalu bekerja dengan String, tidak perlu membuatnya . Ini memperumit kode tanpa manfaat. Generik dibenarkan ketika tipe benar-benar bervariasi, bukan untuk “fleksibilitas masa depan” yang abstrak.

Batasan where yang hilang

Memanggil metode pada parameter generik tanpa menentukan bahwa metode tersebut ada — adalah kesalahan. tidak dapat memanggil .count jika tidak ditentukan bahwa T: Collection. Selalu tambahkan batasan pada parameter-tipe, jika tidak, kompiler akan menolak kode.

swift
// ❌ 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 }

Kesalahannya dapat dimengerti: generik dapat berupa tipe apa pun dan kompiler tidak tahu apakah ia memiliki count. Batasan Collection memecahkan masalah. Demikian pula untuk Equatable, Hashable, Numeric — selalu tentukan protokol jika Anda berencana memanggil metode atau operator pada parameter generik.

Pertanyaan yang Sering Diajukan

Apa itu Generic di Swift dengan kata sederhana?

Generic — adalah cara menulis kode yang bekerja dengan tipe apa pun, tanpa menduplikasi logika yang sama untuk Int, String, dan tipe lainnya. Alih-alih tipe konkret, placeholder digunakan, yang digantikan oleh tipe nyata pada saat penggunaan.

Apa perbedaan Generic dengan Any?

Generic menyimpan informasi tentang tipe konkret pada fase kompilasi, yang memungkinkan kompiler memeriksa tipe dan menghasilkan kode yang dioptimalkan. Any — adalah penghapusan tipe: nilai apa pun dapat diteruskan, tetapi tipe hilang dan diperlukan konversi (as?).

Bagaimana cara membatasi Generic dengan protokol?

Gunakan sintaks T: SomeProtocol dalam tanda kurung siku atau klausa terpisah where T: SomeProtocol. Batasan menjamin bahwa parameter generik mendukung metode dan properti tertentu.

Apa itu Associated Type dalam protokol?

Associated Type (associatedtype) — adalah placeholder untuk tipe di dalam protokol. Protokol tidak menentukan tipe konkret, tetapi mendeklarasikan associatedtype yang dikonkretisasi dalam implementasi: Array memiliki Element, Dictionary — Key dan Value.

Apakah Generic bekerja lebih cepat atau lebih lambat dari tipe konkret?

Swift mengkompilasi kode generik menjadi versi terspesialisasi untuk setiap tipe konkret. Dalam praktiknya, fungsi generik untuk Int tidak lebih lambat dari fungsi yang ditulis manual untuk Int. Tidak ada overhead untuk abstraksi.

Ringkasan

  • Generic — mekanisme pemrograman generik dengan parameter-tipe
  • Fungsi dan tipe dengan parameter generik menggantikan banyak implementasi yang digandakan
  • Batasan where mempersempit cakupan generik ke kondisi yang diperlukan
  • Associated Types memungkinkan protokol menjadi generik tanpa konkretisasi pada fase deklarasi
  • Ekstensi dengan where menambahkan fungsionalitas hanya ketika kondisi terpenuhi
  • Kompiler menghasilkan kode terspesialisasi — generik tidak menambah overhead
  • Parameterisasi berlebihan — anti-pola, gunakan generik hanya ketika tipe benar-benar bervariasi

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga