Tư duy trong ngôn ngữ Swift, Phần 2: map those arrays
Trong phần 1, ta đã biết cách làm thế nào để tránh force-unwrapping optionals
, để giải cứu ponies 🐴 và tránh code bị crash. Trong phần 2 này, ta sẽ chỉnh sửa code để làm nó trở nên Swift-er hơn thông qua map()
và flatMap()
.
Phần 2 này sẽ nói về
map
vàflatMap
trênArays
Nhắc lại, tư duy trong Swift
Đây là code khi kết thúc phần 1
1 |
|
Mục đích là áp dụng nhiều patterns và cú pháp Swift-er để làm cho code tốt hơn và ngắn gọn hơn.
Giới thiệu map()
map()
là một method của Array
. map() có thể lấy một function như là một tham số của nó, điều này giải thích làm thế nào mà mỗi phần tử trong mảng biến đổi thành một giá trị mới. Nó cho phép biến đổi một mảng [X]
thành mảng [Y]
chỉ bằng cách giải thích làm thế nào để biến đổi X -> Y
, mà không cần tạo ra 1 mảng tạm thời làm trung gian.
Do đó, trong trường hợp này, thay vì sử dụng vòng lặp for
như đã làm trước đó, ta có thể áp dụng map
cho jsonItems
(JSON array của NSDictionary
) và đưa ra cách để biến đổi mỗi NSDictionary
thành một ListItem
instance.
1 |
|
Đó có vẻ là một sự thay đổi đơn giản, nhưng nó cho phép ta tập trung vào câu hỏi “làm cách nào để biến đổi một NSDictionary
thành một ListItem
” - đây là mấu chốt của vấn đề - và quan trọng hơn là tránh được việc tạo một mảng trung gian như trong Obj. Luôn luôn tránh tình trạng này khi có thể.
Hư hỏng dữ liệu
Có một vấn đề với code ở trên là chúng ta vẫn tạo ra được một ListItem
thậm chí nếu dữ liệu đầu vào không đúng. Nhưng nếu một phần trong NSDictionary
không đúng thì chúng ta vẫn sẽ kết thúc ở đầu ra với mảng rỗng ListItem()
. Điều này thực sự không có ý nghĩa.
Quan trọng hơn, chúng ta vẫn đang giết chết một vài ponies 🐴 như cách ta đang dùng NSURL!
và code vẫn cho phép tạo ra một ListItem
instances mà không có NSURL
(item.url
không bị ảnh hưởng nếu không có giá trị trong "url"
) và code của chúng ta sẽ bị crash nếu chúng ta cố gắng truy cập NSURL!
không hợp lệ.
Để giải quyết, chúng ta có thể làm cho việc biến đổi đơn giản hơn bằng cách trả về một nil
ListItem
nếu đầu vào không hợp lệ. Việc này được đánh giá cao hơn so với ListItem
bị hỏng hoặc rỗng.
1 |
|
Nhưng nếu chúng ta vẫn dùng jsonItems.map
để biến đổi từ NSDictionary -> ListItem?
, nó vẫn có thể tạo ra một mảng [ListItem?]
mà mảng này vẫn chứa những nil items tại những vị trí mà NSDictionary
không hợp lệ. Cách này là tốt hơn trước đó, nhưng vẫn chưa giải quyết được việc này.
Sử dụng flatMap()
flatMap()
sẽ giải quyết vấn đề còn tồn tại ở trên.
flatMap()
tương tự như map()
nhưng nó sử dụng cách biến đổi T->U?
thay vì T->U
, và nó không add những item mà giá trị sau khi biến đổi là nil (tức là thằng nào nil thì không add vào mảng cuối cùng)
Áp dụng và chúng ta có code như sau:
1 |
|
Bây giờ code chỉ trả về một ListItem
hợp lệ nếu các đầu vào đều có giá trị (trong đó NSURL
đảm bảo sẽ không nil
). Nếu đầu vào không hợp lệ, guard
statement sẽ trả về nil
sớm, và flatMap
không add các thành phần không hợp lệ này vào mảng được trả về.
Điều này làm cho code tốt hơn và an toàn hơn, phải không nào? Và chúng ta loại bỏ các vấn đề hư hỏng dữ liệu và các rủi ro có thể gặp.
Kết luận
Trong phần này, chúng ta đã biết cách làm thế nào để thay thế vòng lặp for
bằng map
hoặc flatMap
, và chúng ta đảm bảo code an toàn hơn bằng cách tránh tạo đầu ra không phù hợp khi dữ liệu đầu vào không hợp lệ.
Trong phần tiếp theo, chúng ta sẽ xem xét làm thế nào để biến đổi ListItem
như một struct
và khám phá cách dùng khác của map
và flatMap
- đặc biệt ở Optionals
.
Trong khi chờ đợi phần tiếp theo, hãy dành thời gian để khám phá sức mạnh của map()
và flatMap()
trên mảng. Tôi biết chúng có thể là đáng sợ hay phức tạp lúc đầu, nhưng một khi bạn hiểu được nó, bạn sẽ muốn sử dụng chúng ở khắp mọi nơi!