Một điều tôi yêu thích về Ruby là độ sâu của tính năng. Bạn có thể dùng một operator, nhưng đào sâu một chút và bạn sẽ thấy chỉ mới cào được bề mặt khả năng của nó. Toán tử splat khiêm tốn (* và **) là ví dụ tuyệt vời.
Bạn có thể đã dùng splats cho đối số "catch-all". Và đó là tất cả hầu hết mọi người dùng nó cho.
def go(x, *args) puts args.inspect end go("a", "b", "c")
Nếu bạn dùng cú pháp keyword argument mới, dùng double splat như sau:
def go(**params) puts params.inspect end go(x: 100, y: 200)
Điều này hữu ích, nhưng bạn có thể dùng splats cho nhiều hơn thế. Hãy đào sâu!
Dùng array để truyền nhiều arguments
Không chỉ dùng splats khi định nghĩa method, bạn cũng có thể dùng khi gọi method. Chúng cho phép truyền array vào function mong đợi nhiều arguments. Item đầu trong array thành argument đầu, item thứ hai thành argument thứ hai, etc.
def go(x, y) end point = [12, 10] go(*point)
Và đừng quên double splat cho keyword arguments kiểu mới:
def go(x:, y:) end point = { x: 100, y: 200 } go(**point)
Splat không phải ở cuối
Mặc dù thường để splatted arguments ở cuối argument list, không có luật bắt buộc.
Bạn có thể đặt splat bất kỳ đâu trong argument list.
def go(x, *args, y) puts x # => 1 puts y # => 5 puts args.inspect # => [2,3,4] end go(1, 2, 3, 4, 5)
Array Destructuring
Tất cả tricks với arguments trên chỉ là trường hợp đặc biệt của array destructuring.
Nếu bạn không quen thuật ngữ "array destructuring", nó đơn giản nghĩa là chia array thành các item riêng lẻ. Trông như sau:
a, b = [1, 2] puts a # 1 puts b # 2
Điều này hoạt động tốt nhưng phiền khi phải chỉ định biến cho mọi item trong array. Toán tử splt giải quyết - hoạt động như wildcard. Hãy xem vài ví dụ.
Lấy phần tử đầu tiên từ array (Popping)
Thỉnh thoảng hữu ích khi lấy item đầu tiên của array mà không alter array gốc. Ví dụ này làm điều đó.
first, *remainder = [1, 2, 3, 4, 5] first # => 1 remainder # => [2, 3, 4, 5]
Nếu chỉ muốn item đầu mà không cần phần còn lại, dùng cú pháp:
first, * = [1, 2, 3, 4, 5] first # => 1
Lấy phần tử cuối
Để lấy item cuối array thay vì đầu, chỉ cần đặt splt ở đầu như sau:
*prefix, last = [1, 2, 3, 4, 5] last # => 5 prefix # => [1, 2, 3, 4]
Lại nữa, nếu không muốn biến cụ thể, không cần gán:
Lấy n phần tử đầu và cuối của array
Nếu đặt splat ở giữa, bạn có thể lấy số lượng tùy ý item từ mỗi đầu array.
first, *, last = [1, 2, 3, 4, 5] first # => 1 last # => 5
Hạn chế
Khi dùng splat trong array destructuring, bạn vẫn phải chỉ định vị trí item array liên quan đến đầu và cuối array. Vì vậy nó không phải tool tốt nhất để extract item từ giữa array dài.
Cũng, tôi không tìm thấy trick cool nào dùng double-splat (**) để chơi với hash. Buồn!
Xây dựng array (Constructing arrays)
Toán tử splat hữu ích không chỉ cho destructuring array mà cả constructing chúng.
Trong ví dụ sau, chúng ta dùng splat join hai array.
[*[1,2], *[3,4]] => [1, 2, 3, 4]
Điều này tương đương [[1, 2], [3,4]].flatten.
Nếu đó là hết câu chuyện, nó không hữu ích lắm. Nhưng splat có khả năng kỳ lạ khác. Nó có thể coerce object thành array thông minh.
# Thường `*thing` wrap `thing` trong array x = *"hi mom" # => ["hi mom"] # ...trừ khi nó nil x = *nil # => [] # Arrays pass through unchanged x = *[1,2,3] # => [1, 2, 3] # Nhưng hash chuyển thành array x = *{a: 1} # => [[:a, 1]]
Điều này cho chúng ta tool xây array mà không cần type coercion thủ công nhiều.
Ví dụ, tưởng tượng bạn collect array string cho config system. Thông thường bạn muốn:
- Check nếu array tồn tại, init nếu không
- Reflect thông minh nếu ai đó cố thêm array string, không chỉ single string
Toán tử splat cho chúng ta miễn phí:
# Config hash có thể có hoặc không có :ignore array. config = { } # Callback function có thể trả array # hoặc single item. def add_ignores "scoundrels" # cũng có thể là array như ["scoundrels", "cads", "ne'er-do-wells"] end # Đây là nơi phép màu xảy ra. Không quan trọng bạn # bắt đầu với gì, bạn nhận array things to ignore. config[:ignore] = [*config[:ignore], *add_ignores()]
Đó là xong
Tôi hy vọng rõ ràng bạn không nên rewrite tất cả array-manipulation code dùng splats. Chúng không phải lúc nào cũng đúng tool, và làm code khó đọc nếu dùng quá nhiều.
Tuy nhiên, đôi khi array splat trick chính là thứ bạn cần. Tôi hy vọng, khi lúc đó đến, bạn sẽ thử một cái. :)