Tư duy trong ngôn ngữ Swift, Phần 3: Struct vs. Class
Nhắc lại phần trước
Trong phần 2, chúng ta đã biết cách sử dụng map
và flatMap
trên array để tránh các biến trung gian khi biến đổi và thay vào đó chúng ta đã sử dụng functional programming. [1]
Đây là code ở cuối của phần 2:
1 |
|
Hôm nay chúng ta chỉ thay đổi đơn giản nhưng sẽ làm cho code thinner và Swift-er hơn.
Struct vs Class
Một lỗi khác mà người-mới-tìm-hiểu swift mắc phải trong đoạn code trên là bắt đầu với một class
. Đó là điều dễ hiểu, bởi vì trong ObjC chúng ta sử dụng class
ở khắp mọi nơi.
Không có gì sai với class
. Bạn vẫn có thể sử dụng chúng ở Swift. Nhưng trong Swift, sử dụng struct
là một phương pháp mạnh mẽ: nó không chỉ giới hạn trong 1 vùng nắm giữ values.
Struct
ở Swift có khả năng tương tự như class - ngoại trừ thừa kế - nhưng thay vào đó là value-types trong khi class là reference-types, passed by reference thay vì bị sao chép, như trong Objective-C (và dấu * xấu xí ở khắp nơi)
Tôi sẽ không nói đến việc sử dụng struct
và value types đối đầu với class
và reference types: Tôi đề nghị bạn xem vấn đề này từ Andy Matuschak. Tôi không thể làm tốt hơn so với Andy!
Chuyển đổi class sang struct
Trong trường hợp của chúng ta, một struct
có vẻ thích hợp hơn vì nó mang những giá trị, và không có ý định thay đổi (và sử dụng sao chép hơn là tham chiếu).
Ngoài ra, lợi thế của chuyển đổi sang một struct
ở đây là nó có một constructor ngầm theo mặc định nếu bạn không khởi tạo giá trị cho nó. Như vậy chúng ta có thể dễ dàng xây dựng một ListItem
sử dụng constructor mặc định của ListItem(icon: …, title: …, url: …)
Cuối cùng, bây giờ, chúng ta không thể tạo ra một ListItem
bị nil bởi vì chúng ta loại bỏ các vấn đề hư hỏng dữ liệu, chúng ta có thể loại bỏ các giá trị mặc định ""
cho title, nhưng quan trọng hơn là chúng ta có thể cứu pony cuối cùng 🐴 bằng cách chuyển đổi NSURL!
sang NSURL
. [2]
Code bây giờ sẽ như thế này:
1 |
|
Bây giờ chúng ta chỉ cần tạo ra instance của ListItem
như là bước cuối cùng. Bởi vì init
mặc định của struct
sẽ tạo giá trị mặc định cho các property, nếu bạn không tạo ra 1 func init
riêng. Chúng ta có thể làm điều tương tự với class
, nhưng với class
chúng ta phải khai báo các init
riêng.
Coalescing operator
Trong ví dụ trên, tôi cũng sử dụng một thủ thuật mới, sử dụng ??
operator để cung cấp cho một giá trị mặc định trong trường hợp iconName
là nil
.
operator ??
có một chút tương tự như opt ?: val
của ObjC, ta đã biết opt ?? val
sẽ trả về giá trị của opt
nếu nó non-nil
, và bằng val
nếu opt
là nil
. Điều đó có nghĩa rằng nếu opt
là kiểu T?, thì val
phải là kiểu T
.
Vì vậy, iconName ?? ""
sẽ trả về ""
khi iconName
là nil
, và kéo theo UIImage
cũng là nil
.
Kết luận
Chúng ta đã không làm được gì nhiều trong phần 3 này, chỉ thay đổi một class
thành một struct
.
Nhưng chúng ta đã cứu pony cuối cùng bằng cách loại bỏ !
ở NSURL!
🎉 . Và bạn đã có nhiều thứ để đọc và học hỏi bằng cách xem bài viết của Andy về «Value Types»😃.
Phần 4, sẽ được về map
và flatMap
một lần nữa, nhưng lần này là trên Optionals
.
[1]. Đúng là bạn đã sử dụng functional programming mà bạn không hề biết↩
[2]. NSURL!
này tôi đã không giải quyết ngay từ đầu bởi vì tôi biết chắc rằng ta sẽ giải quyết nó ở phần này.↩