0
0
Lập trình
Admin Team
Admin Teamtechmely

Tránh Sử Dụng &:to_s Trong Ruby và Lựa Chọn Các Cách Thay Thế Rõ Ràng Hơn

Đăng vào 7 tháng trước

• 3 phút đọc

Chủ đề:

#ruby

Tránh Sử Dụng &:to_s Trong Ruby

Trong Ruby, việc sử dụng cú pháp rút gọn với các symbol làm đối số cho block, như &:to_s, rất phổ biến. Mặc dù cú pháp này trông ngắn gọn và thanh lịch, nhưng nó có thể gây khó hiểu cho người mới bắt đầu và không phải lúc nào cũng được hỗ trợ tốt bởi các IDE hay công cụ refactoring.

Gần đây, những tùy chọn trực quan hơn như it_1 đã được giới thiệu, điều này đặt ra câu hỏi: liệu các nhóm có nên bắt đầu thống nhất phong cách của họ xung quanh những tùy chọn này không?

Bài viết này sẽ khám phá ý tưởng về việc cố tình tránh cú pháp block-pass với symbol và trình bày một cách tiếp cận thực tiễn bằng cách sử dụng RuboCop.

Sự Phát Triển Của Các Tham Số Block

Ruby đã trải qua nhiều giai đoạn phát triển liên quan đến tham số block.

ruby Copy
# Tất cả các cách dưới đây đều trả về ["1", "2", "3"]

# Cách cơ bản nhất
[1, 2, 3].map { |i| i.to_s }

# Kể từ Ruby 1.9
[1, 2, 3].map(&:to_s)

# Kể từ Ruby 2.7 (Tham số Đánh số)
[1, 2, 3].map { _1.to_s }

# Kể từ Ruby 3.4 (Tham số `it`)
[1, 2, 3].map { it.to_s }

Cách Cơ Bản

Cách cổ điển yêu cầu phải chỉ định tên cho tham số block:

ruby Copy
[1, 2, 3].map { |i| i.to_s }

Mặc dù tên biến không quan trọng, bạn vẫn cần phải cung cấp một tên.

Cách Sử Dụng Symbol#to_proc

Ruby 1.9 đã giới thiệu cú pháp rút gọn bằng cách sử dụng Symbol#to_proc:

ruby Copy
[1, 2, 3].map(&:to_s)

Về mặt nội bộ, :to_s.to_proc hoạt động như sau:

ruby Copy
sym = :to_s
blk = sym.to_proc

# Tương đương với:
# ->(obj, *args, **kwargs, &block) { obj.public_send(:to_s, *args, **kwargs, &block) }

blk.call(1)  # => "1"

Khi được truyền như một block (&:to_s), Ruby sẽ tự động gọi to_proc và thực thi phương thức.

Tham Số Đánh Số và it

Sau đó, đã có Tham số Đánh số (_1) trong Ruby 2.7 và cú pháp it trong Ruby 3.4, cả hai đều thể hiện ý tưởng rằng “tên không quan trọng”.

ruby Copy
[1, 2, 3].map { _1.to_s }
[1, 2, 3].map { it.to_s }

Tại Sao Nên Tránh Sử Dụng Symbol Block-Pass?

Động lực đứng sau các cú pháp mới này là để làm cho sự “không có tên” của tham số trở nên rõ ràng. Cả _1it đều giải quyết vấn đề này, và cá nhân tôi thích it — nó đọc tự nhiên, là bổ sung mới nhất và phù hợp với các xu hướng hiện tại của Ruby.

Vấn đề với Symbol#to_proccác lập trình viên không sử dụng Ruby thường gặp khó khăn trong việc hiểu nó ngay lập tức. Ruby thú vị bởi vì nó cung cấp nhiều cách để viết cùng một thứ, nhưng nếu chúng ta muốn Ruby giữ được tính thân thiện với người mới và hấp dẫn, khả năng đọc hiểu là rất quan trọng.

Hơn nữa, _1it tích hợp tốt hơn với các IDE và công cụ refactoring.

Đó là lý do tại sao tôi tin rằng Symbol#to_proc nên được giới hạn ở các trường hợp mã golf hoặc niche và chúng ta nên ngừng sử dụng nó trong mã sản xuất hàng ngày.

Một Custom RuboCop Cop

Để thực thi ý tưởng này, dưới đây là một custom RuboCop cop. Nó sẽ đánh dấu các cách sử dụng như array.map(&:to_s) và đề xuất thay thế chúng bằng it (hoặc _1).

Nó hoạt động như một phiên bản ngược của Style::SymbolProc.

ruby Copy
# Để kích hoạt custom cop này, thêm vào `.rubocop.yml`:
#
# require:
#   - path/to/custom/cop/avoid_symbol_block_pass.rb
#
# Custom/AvoidSymbolBlockPass:
#   Enabled: true
#
# --- Ví dụ vi phạm (NG) ---
# array.map(&:to_s)
# users.each(&:destroy)
#
# --- Được phép (OK) ---
# array.map { it.to_s }
# users.each { it.destroy }

class RuboCop::Cop::Custom::AvoidSymbolBlockPass < RuboCop::Cop::Base
  MSG = "Tránh sử dụng Symbol#to_proc (`&:to_s`). Hãy cân nhắc sử dụng `it` hoặc `_1` thay thế."

  def on_block_pass(node)
    return unless node.children.first&.sym_type?

    add_offense(node)
  end
end

Kết Luận

  • Ruby cung cấp nhiều cú pháp block, mỗi cú pháp đều có bối cảnh lịch sử riêng.
  • Symbol#to_proc (&:to_s) rất ngắn gọn, nhưng không thân thiện với người mới và không thân thiện với IDE.
  • Nên ưu tiên các lựa chọn rõ ràng hơn như it (hoặc _1).
  • Sử dụng custom cop RuboCop để thực thi phong cách này trong đội của bạn.

Bằng cách chuyển hướng khỏi cú pháp symbol block-pass, chúng ta có thể làm cho các mã nguồn Ruby trở nên tiếp cận hơn, nhất quán hơn và dễ bảo trì hơn.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào