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.↩