Sử dụng Generics trong Swift

Cập nhật ngày: 16/04/2024 - Đã có 901 lượt xem bài viết này!
Sử dụng Generics trong Swift
Lập trình Generic là cách để viết các func mà không quan tâm đến kiểu dữ liệu. Mảng là một ví dụ như thế, bạn có thể thêm phần từ có kiểu Int hoặc AnyObject vào mảng mà chưa cần biết kiểu của nó trước khi thêm vào.

Sử dụng Generics trong Swift

Lập trình Generic là cách để viết các func mà không quan tâm đến kiểu dữ liệu. Mảng là một ví dụ như thế, bạn có thể thêm phần từ có kiểu Int hoặc AnyObject vào mảng mà chưa cần biết kiểu của nó trước khi thêm vào.

1.Generic Functions

Đầu tiên tạo một playground: File/New/Playground…., bạn đặt tên Generics và chọn iOS và chọn Next/Create.

Bắt đầu với cách tạo generic function. Mục đích của chúng ta là kiểm tra xem 2 đối tượng có giống kiểu hay không. Nếu chúng có kiểu giống nhau thì kiểm tra xem giá trị có giống nhau hay không.

func sameType(one: Int, two: Int) -> Void {
    if(type(of: one) == type(of: two)) {

        print("Same")

    }
    else {
        print("not same type")
    }
}

Đối với func vừa viết thì nó chỉ kiểm tra giá trị kiểu Int. Nếu muốn kiểm tra kiểu String thì lại viết một hàm tương tự nhưng khác kiểu của tham số sao. Nhưng không đến đây chúng ta sẽ sử dụng generic type thì nó sẽ tổng quát hơn nhiều.

func sameType(one: T, two: E) -> Void {
    if(type(of: one) == type(of: two)) {
        print("Same")

    }
    else {
        print("not same type")
    }

}

Ở đây cú pháp của nó chỉ ra kiểu để sử dụng là T và E được để trong . Sau khi khai báo T, E thì có thể sử dụng trong func.

2. Generic Classes và Structures

Một queue là một dữ liệu có cấu trúc giống như list và stack, nhưng bạn có thể thêm vào ở đuôi và lấy ra ở đầu, nó cũng giống như NSOperationQueue và GCD(dispatch_async).

Khởi tạo một struct như sau:

struct Queue {
}

Queue là một generic với kiểu là Element. Thì với queue nó có thể enqueue(thêm dữ liệu vào) và dequeue(lấy dữ liệu ra).Thêm các đoạn mã sau để có thể enqueue và dequeue:

    private var elements = [Element]()
    init(array: [Element]) {
        self.elements = array
    }
    mutating func enqueue(newElement: Element) {
        elements.append(newElement)
    }
   
    mutating func dequeue() -> Element? {
        guard !elements.isEmpty else {
            return nil
        }
        return elements.remove(at: 0)
    }

Bản chất queue cũng là một mảng nên sẽ cần khai báo 1 mảng có kiểu dữ liệu “element” và 2 funcs là enqueue và dequeue.

Điều cần nhớ là kiểu Element có thể được sử dụng bất kỳ đâu khi ở trong thân struct.

Thêm đoạn mã sau để xem các câu lệnh ở trên có chạy đúng không

var q = Queue(array: [1, "tu", "trinhminhcuong", 3])

q.enqueue(newElement: 4)
q.enqueue(newElement: 2)

q.dequeue()
q.dequeue()
q.dequeue()
q.dequeue()

3. Protocols và Constraints

Trong nhiều trường hợp chúng ta muốn thao tác so sánh giữa các đối tượng ví dụ như tìm index của một phần tử trong mảng.

Như sau:

   func findIndex(of valueToFind: T) -> Int? {

        for (index, value) in self.elements.enumerated() {

            if let elementValue = value as? T

            {
                if valueToFind == elementValue
                {
                    return index
                }
            }
        }
        return nil
   }

Ở đây trong bài này sử dụng optional binding để kiểm tra 2 biến cùng kiểu. Ở đây trình biên dịch sẽ báo lỗi “Binary operator == cannot be applied to two T operands”. Vì T không hỗ trợ toán tử ‘==’. Cũng may là Swift cung cấp protocol ‘Equatable’.

    func findIndex(of valueToFind: T) -> Int? {
        for (index, value) in self.elements.enumerated() {
            if let elementValue = value as? T
            {
                if valueToFind == elementValue
                {
                    return index
                }
            }
        }
        return nil
    }

Ngoài protocol ‘Equatable’ thì swift còn hỗ trợ protocol khác như ‘Hashable và Comparable’ để sử dụng toán tử  ‘<’ và ‘>’.

4. Associated Types

Khi bạn định nghĩa một protocol, thì đôi khi nên sử dụng associated types như là một phẩn của protocol để dễ kiển soát cũng như thao tác hơn. Khi khai báo chỉ cần từ khoá associatedtype “tên”, hơn nữa nó cung cấp luôn các func để so sánh “==, > , <…”

protocol Container {
    associatedtype ItemType
    mutating func append(_ item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

Container protol định nghĩa với các chức năng:

Thêm phần tử bàng func append(_:)

Lấy ra số lượng phần tử

Lấy ra phần tử theo chỉ số index và trả về ItemType

5. Where Clause

Swift cũng cho phép sử dụng where clauses với generic. Generic where clause cho phép xác định một associated type phải tuân thủ theo một protocol hoặc điều kiện nào đó. Một generic where clause bắt đầu với từ khoá where tiếp theo là các rang buộc cho associated type. Generic clause được viết ở bên phải đằng sau kiểu trả về của func. Ví dụ dưới đây là func allItemsMatch, nó kiểm tra xem 2 đối tượng truyền vào có các phần tử giống nhau hay không.

func allItemsMatch
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool

    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {   
    // Check that both containers contain the same number of items.
        if someContainer.count != anotherContainer.count {
            return false
        }
    // Check each pair of items to see if they are equivalent.
        for i in 0..

6. Tóm lại

Bài này đã tôi đã giới thiệu qua cơ bản và tác dụng của generics về các khai báo sử dụng ở functions, class, struct..

Nếu bạn có thể hiểu rõ và vận dụng tốt thì có thể xử lý những vấn đề phực tạp tốt hơn.
 

BTV. Phạm Thị Mỹ Phương
Phòng Truyền Thông ImicroSoft Hồ Chí Minh
Hotline: 0916 878 224
Email: phuongptm@imicrosoft.edu.vn

 

Bạn đang muốn tìm kiếm 1 công việc với mức thu nhập cao.
✅ Hoặc là bạn đang muốn chuyển đổi công việc mà chưa biết theo học ngành nghề gì cho tốt.
✅ Giới thiệu với bạn Chương trình đào tạo nhân sự dài hạn trong 12 tháng với những điều đặc biệt mà chỉ có tại IMIC và đây cũng chính là sự lựa chọn phù hợp nhất dành cho bạn:
👉 Thứ nhất: Học viên được đào tạo bài bản kỹ năng, kiến thức chuyên môn lý thuyết, thực hành, thực chiến nhiều dự án và chia sẻ những kinh nghiệm thực tế từ Chuyên gia có nhiều năm kinh nghiệm dự án cũng như tâm huyết truyền nghề.
👉 Thứ hai: Được ký hợp đồng cam kết chất lượng đào tạo cũng như mức lương sau tốt nghiệp và đi làm tại các đối tác tuyển dụng của IMIC. Trả lại học phí nếu không đúng những gì đã ký kết.
👉 Thứ ba: Cam kết hỗ trợ giới thiệu công việc sang đối tác tuyển dụng trong vòng 10 năm liên tục.
👉 Thứ tư: Được hỗ trợ tài chính với mức lãi suất 0 đồng qua ngân hàng VIB Bank.
👉  Có 4 Chương trình đào tạo nhân sự dài hạn dành cho bạn lựa chọn theo học. Gồm có:
1)  Data Scientist full-stack
2)  Embedded System & IoT development full-stack
3)  Game development full-stack
4)  Web development full-stack 
✅ Cảm ơn bạn đã dành thời gian lắng nghe những chia sẻ của mình. Và tuyệt vời hơn nữa nếu IMIC được góp phần vào sự thành công của bạn. 
✅ Hãy liên hệ ngay với Phòng tư vấn tuyển sinh để được hỗ trợ về thủ tục nhập học.
✅ Chúc bạn luôn có nhiều sức khỏe và thành công!