Generic แบบเฉพาะเจาะจงของเจนเนอริกไทปและพารามิเตอร์ T

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-18 เวลาอ่าน: 10 นาที

Generic (การเขียนโปรแกรมแบบทั่วไป) — เป็นกลไกของ Swift ที่ช่วยให้เขียนชนิดข้อมูลและฟึงก์ชันโดยมีพารามิเตอร์ชนิด แทนที่จะทำซ้ำโค้ดสำหรับ Int, String และโครงสร้างที่กำหนดเอง, นักพัณฐ์สร้างโซลูชันทั่วไปอันเดียวที่ทำงานกับชนิดใดก็ได้, โดยยังคงการกำหนดชนิดอย่างเข้มงวด ตัวแปลจัดเกิดจะแทนที่ชนิดเฉพาะเจาะจงในขณะที่ใช้งาน, รับประกันความปลอดภัยโดยไม่เสียประสิทธิภาพ ตาม Swift Book, 2025, พารามิเตอร์ generic เป็นหนึ่งในความสามารถหลักของภาษา, ซึ่งเป็นรากฐานของไลบรารีมาตรฐานและ SwiftUI

หัวข้อสำคัญ

  • Generic — กลไกการเขียนโปรแกรมแบบทั่วไปโดยมีพารามิเตอร์ชนิด
  • ฟึงก์ชัน ที่มีพารามิเตอร์ generic ทำงานกับชนิดใดก็ได้โดยไม่ต้องทำซ้ำโค้ด
  • ข้อจำกัด where จำกัดขอเขตของ generic ให้แค่ชนิดที่ตรงตามเงื่อนไข
  • Associated Types ในโปรโตคอลทำให้โปรโตคอลเป็น generic ได้
  • ตัวแปลจัดเกิด สร้างโค้ดเฉพาะเจาะจงสำหรับแต่ละชนิดเฉพาะเจาะจง

Generic ใน Swift คืออะไร?

Generic (ชนิดทั่วไป) — เป็นโครงสร้างทางไวยากรณ์ของ Swift ที่ช่วยให้เขียนโค้ดที่ยืดหยุ่นและสามารถใช้ซ้ำได้โดยมีการกำหนดพารามิเตอร์ชนิด แทนที่จะเป็นชนิดเฉพาะเจาะจง, ตัวเตือนตำแหน่งจะถูกเขียนในเครื่องหมายมุม — โดยทั่วไป , แต่สามารถใช้ชื่อใดก็ได้ Generics เป็นรากฐานของ SwiftUI (View, some View), ไลบรารีมาตรฐาน (Array, Optional) และ Combine

ทำไมต้องใช้ Generics

หากไม่มี generics, คุณจะต้องเขียนฟึงก์ชันแยกต่างสำหรับแต่ละชนิด: swapInts, swapStrings, swapDates ฟึงก์ชัน swap แบบ generic หนึ่งตัวแทนที่สามตัวแปรด้วยการประกาศเดียว ซึ่งช่วยลดการทำซ้ำ, ปรับปรุงความสามารถในการอ่านและลดโอกาสเกิดข้อผิดพลาดเมื่อคัดลอกโค้ด

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)

ตัวแปลจัดเกิด Swift สร้าง โค้ดเฉพาะเจาะจง สำหรับแต่ละการใช้งานแบบเฉพาะเจาะจงของ generic ซึ่งหมายความว่า ฟึงก์ชัน generic swapValues ไม่มีค่าใช้จ่ายเพิ่มเมื่อเทียบกับฟึงก์ชันที่เขียนด้วยมือสำหรับ Int Swift ไม่ใช้การลบชนิดข้อมูลเหมือน Java — generics มีอยู่ทั้งในขณะเรียบเรียงและขณะทำงาน (แม้ว่าการเพิ่มเติมประสิทธิภาพจะทำให้พวกมันเฉพาะเจาะจงได้)

ฟึงก์ชันทั่วไปกับพารามิเตอร์ T

ฟึงก์ชัน generic คือฟึงก์ชันที่รับพารามิเตอร์ชนิดหนึ่งหรือมากกว่า พารามิเตอร์ชนิดจะถูกระบุหลังชื่อฟึงก์ชันในเครื่องหมายมุม: สามารถใช้ในลายมือ: ชนิดอาร์กิวเมนต์, ชนิดผลลัพธ์ และภายในตัวฟึงก์ชัน

พารามิเตอร์ชนิดหลายตัว

ฟึงก์ชันสามารถมี หลาย พารามิเตอร์ generic ตัวอย่างเช่น, ฟึงก์ชัน findKey รับพจนานุกรมที่มีคีย์ K และค่า V แต่ละพารามิเตอร์ชนิดเป็นเฉพาะและสามารถใช้ในข้อจำกัดได้

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
}

ข้อจำกัด K: Hashable และ where V: Equatable รับประกันว่า findKey สามารถเรียกได้เฉพาะกับพจนานุกรมที่มีคีย์ที่สามารถ hash ได้และค่าที่เปรียบเทียบได้ ข้อจำกัดเหล่านี้ไม่ใช่ระบบข้าราชการแต่เป็นความจำเป็น: หากไม่มี Hashable คุณจะไม่สามารถทำดัชนีการค้นหาโดยคีย์ได้, หากไม่มี Equatable คุณจะไม่สามารถเปรียบเทียบ value กับ dictValueได้

ข้อจำกัดชนิดโดยผ่าน where

where — เป็นคำสำคัญของ Swift ที่ใช้กำหนดข้อจำกัดเพิ่มเติมบนพารามิเตอร์ generic แตกต่างจากการระบุโปรโตคอลในเครื่องหมายมุม (), where ช่วยให้สามารถแสดงเงื่อนไขที่ซับซ้อนขึ้นได้: การปฏิบัติตามโปรโตคอลหลายตัว, ความสัมพันธ์ระหว่างพารามิเตอร์ชนิดและการระบุรายละเอียดของ associated types

ไวยากรณ์ where

ประโยก where จะถูกเขียนหลังลายมือฟึงก์ชันหรือชนิด, ก่อนเครื่องหมายปีกษาเปิด ใน where คุณสามารถระบุได้ว่า T: Comparable & Hashable (ปฏิบัติตามโปรโตคอลสองตัวพร้อมกัน) หรือ T.U == Int (การทำให้ 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
    }
}

ส่วนขยายที่มี where จะเพิ่มเมธอดต่างๆ เฉพาะ สำหรับชนิดที่ตรงตามเงื่อนไข Container จะได้เมธอด isSorted, ในขณะที่ Container จะไม่ได้ เพราะ Any ไม่ใช่ Comparable นี้เป็นกลไกที่ทรงพลังสำหรับฟังก์ชันแบบมีเงื่อนไข

Associated Types ในโปรโตคอล

Associated Types (ชนิดสมาชิก) — เป็นวิธีทำให้โปรโตคอลเป็น generic โดยไม่ต้องระบุชนิดเฉพาะเจาะจงในขณะประกาศ แทนที่จะเป็น , โปรโตคอลจะประกาศ associatedtype, ซึ่งจะถูกกำหนดเฉพาะเจาะจงในการนำไปใช้ ทั้งนี้มีความสำคัญเฉพาะสำหรับคอลเลกชัน: โปรโตคอล Sequence ไม่รู้ว่าลำดับจะมีอะไรบ้าง

การเชื่อมโยง Associated Types ผ่าน where

ด้วยการใช้ where คุณสามารถสร้าง ความสัมพันธ์ ระหว่าง associated types ของโปรโตคอลต่างๆ ตัวอย่างเช่น, คุณสามารถกำหนดได้ว่า Item ของโปรโตคอลหนึ่งตรงกับ Iterator.Element ของอีกโปรโตคอลหนึ่ง ซึ่งรับประกันความเข้ากันได้ของชนิดในระดับตัวแปลจัดเกิด

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 ทำให้ Element กลายเป็น Int โดยใช้ typealias ตัวแปลจัดเกิดจะตรวจสอบว่าข้อกำหนดทั้งหมดของโปรโตคอลได้รับการตรงตามด้วยชนิดนี้ หากไม่มี associated types, คุณจะต้องเขียน StackProtocol โดยใช้โปรโตคอล generic, แต่ Swift ใช้ associated types เพื่อความสอดคล้องกับสะพาน Objective-C และความสามารถในการอ่านที่ดีขึ้น

Generic ในส่วนขยายและซับสคริปต์

ส่วนขยาย generic ช่วยให้เพิ่มเมธอดให้กับชนิด generic โดยมีข้อจำกัดเพิ่มเติม นี้คือรูปแบบ “การปฏิบัติตามแบบมีเงื่อนไข”, ซึ่งชนิดจะได้รับฟังก์ชันภายใต้เงื่อนไขบางอย่างเท่านั้น ซับสคริปต์ก็สามารถเป็น generic ได้

ซับสคริปต์ generic

ซับสคริปต์สามารถเป็น generic ได้: มันรับพารามิเตอร์ generic ในเครื่องหมายมุม ซึ่งมีประโยชน์สำหรับการเข้าถึงคอลเลกชันอย่างปลอดภัยโดยใช้ดัชนีตามอำเหมาใจ, ในกรณีที่ดัชนีสามารถเป็นได้หลายชนิด

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

โครงสร้างนี้ให้ การรวมกัน ที่ทรงพลัง: เมธอด sum จะปรากฏเฉพาะในอาร์เรย์ตัวเลข, และซับสคริปต์ที่มีดัชนีตามอำเหมาใจจะทำงานกับลำดับของดัชนีเลขจำนวนเท่านั้น ตัวแปลจัดเกิดจะจัดการการมองเห็นของสมาชิกเหล่านี้โดยอัตโนมัติตามเงื่อนไข where

ข้อผิดพลาดทั่วไปเมื่อทำงานกับ Generic

ข้อผิดพลาด เมื่อใช้ generic มักเกี่ยวข้องกับข้อจำกัดที่ไม่ถูกต้องหรือความพยายามใช้ generic ในที่ที่ต้องการชนิดเฉพาะเจาะจง มาดูสามสถานการณ์ทั่วไปที่นักพัณฐ์พบเจอ

การกำหนดพารามิเตอร์มากเกินไป

การเพิ่มพารามิเตอร์ generic ในที่ชนิดเฉพาะเจาะจงก็เพียงพอเป็นรูปแบบที่ไม่ดี หากฟึงก์ชันทำงานกับ String เสมอ, ไม่จำเป็นต้องทำให้เป็น ซึ่งทำให้โค้ดซับซ้อนโดยไม่จำเป็น Generic มีความเหมาะสมเมื่อชนิดแตกต่างกันจริง, ไม่ใช่สำหรับ“ความยืดหยุ่นในอนาคต”แบบนามธรรม

ขาดข้อจำกัด where

การเรียกเมธอดบนพารามิเตอร์ generic โดยไม่ได้ระบุว่าเมธอดนั้นมีอยู่เป็นข้อผิดพลาด ไม่สามารถเรียก .count ได้หากไม่ได้ระบุว่า T: Collection เพิ่มข้อจำกัดใส่พารามิเตอร์ชนิดเสมอ, มิฉะนั้นตัวแปลจัดเกิดจะปฏิเสธโค้ด

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 }

ข้อผิดพลาดชัดเจน: generic สามารถเป็นได้ ทุก ชนิด, และตัวแปลจัดเกิดไม่รู้ว่ามันมี count หรือไม่ ข้อจำกัด Collection แก้ปัญหาได้ เช่นเดียวกันสำหรับ Equatable, Hashable, Numeric — ระบุโปรโตคอลเสมอหากคุณวางแผนจะเรียกเมธอดหรือตัวดำเนินการบนพารามิเตอร์ generic

คำถามที่พบบ่อย

Generic ใน Swift คืออะไรในคำพูดง่ายๆ?

Generic เป็นวิธีเขียนโค้ดที่ทำงานกับชนิดใดก็ได้, โดยไม่ต้องทำซ้ำตรรกะเดียวกันสำหรับ Int, String และชนิดอื่นๆ แทนที่จะเป็นชนิดเฉพาะเจาะจง, จะใช้ตัวเตือนตำแหน่ง ซึ่งจะถูกแทนที่ด้วยชนิดจริงในขณะที่ใช้งาน

Generic แตกต่างจาก Any อย่างไร?

Generic เก็บข้อมูลเกี่ยวกับชนิดเฉพาะเจาะจงไว้ในขณะเรียบเรียง, ทำให้ตัวแปลจัดเกิดสามารถตรวจสอบชนิดและสร้างโค้ดที่เพิ่มเติมแล้ว Any คือการลบชนิด: ค่าใดก็สามารถส่งไปได้, แต่ชนิดจะหายไปและต้องใช้การแปลงชนิด (as?)

จำกัด Generic ด้วยโปรโตคอลได้อย่างไร?

ใช้ไวยากรณ์ T: SomeProtocol ในเครื่องหมายมุมหรือประโยก where แยกต่างแยก where T: SomeProtocol ข้อจำกัดรับประกันว่าพารามิเตอร์ generic รองรับเมธอดและคุณสมบัติเฉพาะเจาะจง

Associated Type ในโปรโตคอลคืออะไร?

Associated Type (associatedtype) คือตัวเตือนตำแหน่งสำหรับชนิดภายในโปรโตคอล โปรโตคอลจะไม่ระบุชนิดเฉพาะเจาะจงแต่จะประกาศ associatedtype, ซึ่งจะถูกกำหนดเฉพาะเจาะจงในการนำไปใช้: Array มี Element, Dictionary มี Key และ Value

Generic เร็วหรือช้ากว่าชนิดเฉพาะเจาะจง?

Swift แปลงโค้ด generic เป็น รุ่นเฉพาะเจาะจง สำหรับแต่ละชนิดเฉพาะเจาะจง ในทางปฏิบัติ, ฟึงก์ชัน generic สำหรับ Int ไม่ช้ากว่าฟึงก์ชันที่เขียนด้วยมือสำหรับ Int ไม่มีค่าใช้จ่ายเพิ่มสำหรับการเอนกลางอย่างเป็นนามธรรม

สรุป

  • Generic — กลไกการเขียนโปรแกรมแบบทั่วไปโดยมีพารามิเตอร์ชนิด
  • ฟึงก์ชันและชนิด ที่มีพารามิเตอร์ generic แทนที่การนำไปใช้ที่ซ้ำกันหลายฉบับ
  • ข้อจำกัด where จำกัดขอเขตของ generic ให้เหลือเฉพาะเงื่อนไขที่จำเป็น
  • Associated Types ทำให้โปรโตคอลสามารถเป็น generic ได้โดยไม่ต้องกำหนดเฉพาะเจาะจงในขณะประกาศ
  • ส่วนขยาย ที่มี where จะเพิ่มฟังก์ชันเมื่อตรงตามเงื่อนไข
  • ตัวแปลจัดเกิด สร้างโค้ดเฉพาะเจาะจง — generic ไม่มีค่าใช้จ่ายเพิ่ม
  • การกำหนดพารามิเตอร์มากเกินไป เป็นรูปแบบที่ไม่ดี — ใช้ generic เมื่อชนิดแตกต่างกันจริงเท่านั้น

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม