Swift Generics
Bài đăng này đã không được cập nhật trong 7 năm
Bài dịch từ https://www.raywenderlich.com/154371/swift-generics-tutorial-getting-started
Mở đầu
Hãy nhìn vào 2 đoạn code dưới đây
func add(x: Int, y: Int) -> Int {
return x + y
}
func add(x: Double, y: Double) -> Double {
return x + y
}
Rõ ràng 2 function này đều làm chung 1 nhiệm vụ - cộng x và y, tuy nhiên, chỉ kiểu giá trị truyền vào của chúng khác nhau (kiểu giá trị trả về khác nhau) mà chúng ta phải tạo ra 2 function riêng biệt thì thật là lãng phí, và sau này, để support cho cả cộng Float, UInt ... bạn phải tạo thêm các function khác. Để support việc này, Swift cung cấp cho ta 1 công cụ, đó là Generics
Cùng tìm hiểu kỹ hơn về Generics
qua các ví dụ dưới đây nhé
Viết một Generic Data Struct
struct Queue<Element> {
}
Đoạn code trên là 1 ví dụ về 1 Generic Data Struct
và bạn có thể hiểu nó 1 cách đơn giản : Queue
là 1 generic với type Element
, ví dụ Queue<String>, Queue<Int>
struct Queue<Element> {
fileprivate var elements: [Element] = []
mutating func enqueue(newElement: Element) {
elements.append(newElement)
}
mutating func dequeue() -> Element? {
guard !elements.isEmpty else { return nil }
return elements.remove(at: 0)
}
}
Như bạn đã thấy, chúng ta có thể sử dụng Element
như là 1 type
và bạn có thể sử dụng nó thay thế cho Int, String, Double ... như ví dụ dưới đây
var q = Queue<Int>()
q.enqueue(newElement: 4)
q.enqueue(newElement: 2)
q.dequeue()
q.dequeue()
q.dequeue()
q.dequeue()
Viết một Generic Function
việc khai báo cho 1 function cũng đơn giản và tương tự như Struct, chúng ta có thể hình dung đơn giản nó qua ví dụ bên dưới
func pairs<Key, Value>(from dictionary: [Key: Value]) -> [(Key, Value)] {
return Array(dictionary)
}
let somePairs = pairs(from: ["minimum": 199, "maximum": 299])
// result is [("maximum", 299), ("minimum", 199)]
let morePairs = pairs(from: [1: "Swift", 2: "Generics", 3: "Rule"])
// result is [(2, "Generics"), (3, "Rule"), (1, "Swift")]```
## Constraining a Generic Type ##
Cùng bắt đầu với ví dụ tìm giá trị giữa của array dưới đây
```Swift
func mid<T>(array: [T]) -> T? {
guard !array.isEmpty else { return nil }
return array.sorted()[(array.count - 1) / 2]
}
Compiler sẽ báo lỗi ở chỗ gọi sorted(). Để hàm sorted() có thể hoạt động, các phần tử của array phải Comparable
. Rõ ràng, trong trường hợp này, các phần từ của array sẽ phải bị giới hạn (phải Comparable
). Chúng ta sẽ sửa lại 1 chút
func mid<T: Comparable>(array: [T]) -> T? {
guard !array.isEmpty else {
return nil
}
return array.sorted()[(array.count - 1) / 2]
}
và bây giờ, chúng ta có thể thoải mái sử dụng function trên với array của các Comparable
element
mid(array: ["abe", "abd", "cbd"])
mid(array: [1,3,4,2,6,3])
Quay trở lại bài toán ban đầu,
func add(x: Int, y: Int) -> Int {
return x + y
}
func add(x: Double, y: Double) -> Double {
return x + y
}
Khi chúng ta gộp chung 2 function trên và sử dụng Generic
func add<T>(x: T, y: T) -> T {
return x + y
}
chúng ta sẽ nhận được 1 thông báo lỗi rằng toán tử +
chỉ support cho 1 số kiểu dữ liệu nhất định chứ k phải tất cả. Để giải quyết vấn đề này, đơn giản chỉ cần sử dụng luôn cái mà chúng ta đã nói ở trên
protocol Sumable {
static func + (lhs: Self, rhs: Self) -> Self
}
extension Int: Sumable {
}
extension Double: Sumable {
}
extension String: Sumable {
}
func add<T: Sumable>(x: T, y: T) -> T {
return x + y
}
add(x: 1, y: 1)
add(x: 1.0, y: 1.0)
add(x: "Make it ", y: "Awesome")
Enumerations With Associated Values
Nếu đã sử dụng Alamofire
chắc hẳn bạn đều biết đến những dòng code này
public struct DataResponse<Value> {
public let result: Result<Value>
}
public enum Result<Value> {
case success(Value)
case failure(Error)
}
Đó là 1 cách biểu diễn thường gặp của “functional” error-handling
là result enum
. Nó là 1 enum generic với 2 case trả về, trả về value hoặc thông báo lỗi.
Tương tự như ví dụ đó, chúng ta có thể làm 1 ví dụ
enum MathError: Error {
case divisionByZero
}
func divide(_ x: Int, by y: Int) -> Result<Int> {
guard y != 0 else {
return .failure(MathError.divisionByZero)
}
return .success(x / y)
}
Kết
Trên đây là 1 số ví dụ đơn giản để bạn hiểu hơn về Generic
trong Swift
. Bạn có thể download phần source code ở đây và tìm hiểu thêm về tại phần Generic trong tài liệu của Apple
All rights reserved