Swift Generics Part I
Bài đăng này đã không được cập nhật trong 3 năm
Theo tài liệu: Tutorial
Generic programming
là 1 cách viết functions và kiểu dữ liệu trong khi đưa ra những giả định tối thiểu về loại của dữ liệu sử dụng. Code viết theo kiểu swift generics sẽ ko cần đòi hỏi cụ thể nào về dữ liệu, cho phép code trở nên linh hoạt, dễ sử dụng lại và tạo ra code đẹp hơn, sạch hơn, ít lỗi hơn. Bạn sẽ thấy generic được sử dụng rất nhiều trong swift, mà cụ thể hay gặp nhất đó là Optional type
. bạn có thể có optional của bất kỳ kiểu dữ liệu nào bạn muốn, kể cả kiểu dữ liệu bạn tự định nghĩa. kiểu dữ liệu optional được tạo ra theo kiểu generic theo dữ liệu nó cần chứa. Trong bài turorial này, chúng ta sẽ cùng xem xét các vấn đề sau:
- Generics là gì
- Sự hữu ích của Generics
- Cách viết generic functions và data strutures
- Cách sử dụng
type constraints
- Cách extend generic types
Getting Started
Tạo 1 file playground mới và viết đoạn code về function cộng 2 số nguyên như sau:
func addInts(x: Int, y: Int) -> Int {
return x + y
}
Nếu bạn cần 1 hàm nữa để cộng các số thực, bạn lại phải viết thêm:
func addDoubles(x: Double, y: Double) -> Double {
return x + y
}
let doubleSum = addDoubles(x: 1.0, y: 2.0)
function signatiures
(kiểu trả về và kiểu tham số đầu vào) của addInts
và addDoubles
là khác nhau, nhưng bodies
là giống hệt nhau. Như vậy không chỉ việc có tới 2 function cho 1 việc là cộng 2 số, mà bạn còn bị lặp code. Generics có thể được sử dụng để biến 2 function thành 1 và loại bỏ code lặp.
Other Examples of Swift Generics
Có thể bạn không để ý, nhưng hầu hết các structures phổ biến mà bạn sử dụng đều là options: arrays, dictionaries và optionals,..
Arrays
Thêm đoạn code sau vào playground:
let numbers = [1, 2, 3]
let firstNumber = numbers[0]
Ở đây bạn tạo ra 1 array với 3 số và lấy số đầu tiên ở trong array đó, tiếp theo option-click
vào numbers
rồi sau đó là firstNumber
bạn sẽ thấy:
Bởi vì swift có type inference
(sự tự suy luận kiểu dữ liệu) bạn không cần phải định nghĩa rõ ràng kiểu dữ liệu của các hằng số (constants), nhưng chúng luôn có kiểu chính xác: numbers
là kiểu [int]
và firstNumber
là Int
. Array
của swift là 1 kiểu generic type
. Generic types yêu cầu 1 tham số chỉ ra kiểu của dữ liệu để có thể xác định được chính xác. Khi bạn tạo ra 1 instance, bạn phải xác định luôn cả type parameter
của nó để instance có 1 kiểu cụ thể. Ở ví dụ trên, bởi vì type inference
và type safety
của Swift mà array number
chỉ có thể chứa giá trị kiểu Int
.
Bạn sẽ thấy bản chất của Array rõ ràng hơn bằng những dòng code sau, vẫn là 1 mảng kiểu Int:
var numbersAgain: Array<Int> = []
numbersAgain.append(1)
numbersAgain.append(2)
numbersAgain.append(3)
let firstNumberAgain = numbersAgain[0]
Bạn hãy check kiểu của numbersAgain
và firstNumberAgain
và bạn sẽ thấy kiểu của chúng vẫn y hệt như phía trên. Ở đây bạn đã chỉ ra kiểu của numbersAgain
bằng cách sử dụng explicit generic syntax
khi để <Int>
đi ngay sau Array
Hãy thử appending thứ gì khác ko phải là số nguyên vào array, như String
:
numbersAgain.append("All hail Lord Farquaad")
Bạn sẽ nhận được error Cannot convert value of type 'String' to expected argument type 'Int'
. Compiler đang nói rằng bạn ko thể thêm 1 chuỗi vào trong 1 mảng số nguyên. Bởi vì append
là 1 method của generic type Array
nên nó được gọi là generic method
. Nó sẽ biết kiểu của các thành phần bên trong array và sẽ không để bạn thêm những thứ ko cùng kiểu vào đó.
Dictionaries
Dictionaries
are also generic types and result in type-safe data structures. Tạo 1 dictionary như code dưới đây:
let countryCodes = ["Arendelle": "AR", "Genovia": "GN", "Freedonia": "FD"]
let countryCode = countryCodes["Freedonia"]
Check kiểu của cả countryCodes
và contryCode
,. bạn sẽ thấy countryCodes
là 1 dictionary với keys là kiểu String và giá trị cũng là kiểu String. Thử add thêm 1 item nữa vào trong countryCodes
như sau:
countryCodes["Dicaverio"] = 18
Bạn sẽ thấy build lỗi như sau: cannot assign value of type 'Int' to type 'String?'
Optionals
Ở ví dụ phía trên, bạn sẽ nhớ rằng kiểu value trong contryCodes
là String?
, mà là viết tắt cho:
Optional<String>
Bạn sẽ thấy rằng 2 ký tự <
>
chính là generic mà ta đã nói ở trên như khi khai báo rõ ràng Array
. Ở đây, compiler đã bắt buộc bạn chỉ có thể truy cập dictionary
với key là String
và luôn luôn nhận về value là String
. Một optional type
được sử dụng để đại diện cho countryCode
, bởi vì có thể không có value tương ứng với key được truyền vào. Nếu chúng ta cố gắng tìm kiếm "The Emerald City"
, thì giá trị value của countryCode
sẽ là nil vì nó không tồn tại trong dictionary.
Thêm đoạn code sau vào playground:
let optionalName = Optional<String>.some("Princess Moana")
if let name = optionalName {}
Check type của name, bạn sẽ thấy nó là String
. Cấu trúc if-let
ở trên được gọi là Optional Binding
là 1 generic transformation of sorts
- sự chuyển đổi động giữa các loại. Nó sẽ lấy giá trị generic của kiểu T?
và trả về cho bạn giá trị generic của kiểu T
. Nói 1 cách đơn giản, nếu optionalName
mà không bằng nil, code sẽ chạy vào bên trong {}
và ta sẽ sử dụng giá trị của optionalName
thông qua name
. Bạn có thể sử dụng if let
với bất kỳ kiểu cụ thể nào.
All rights reserved