Ruby 3.0 đã chính thức hỗ trợ Pattern Matching

Pattern Matching trong Ruby cho phép giải cấu trúc dữ liệu một cách ngắn gọn, giúp dễ dàng gán giá trị cho các biến với cú pháp rõ ràng. Pattern matching là một tính năng đã được giới thiệu trong Ruby 2.7. Từ Ruby 3.0 trở đi, nó không còn là một tính năng thử nghiệm nữa và chúng ta có thể bắt đầu sử dụng nó một cách chính thức.

Warning Ruby 2.7: Pattern matching is experimental, and the behavior may change in future versions of Ruby!

Pattern Matching là gì?

Pattern matching là một tính năng cho phép bạn so sánh và hiểu cấu trúc dữ liệu. Điều này được thực hiện bằng cách kiểm tra cách thông tin được tổ chức và gán các phần tương ứng cho các biến cục bộ để sử dụng sau này.

Pattern Matching được hỗ trợ thông qua cú pháp case / in. Quan trọng là không nhầm lẫn với case / when và không kết hợp chúng. Nếu không có sự phù hợp với bất kỳ biểu thức nào và không có định nghĩa else, thì một ngoại lệ NoMatchingPatternError sẽ được raise

case <expression>
in <pattern1>
  # ...
in <pattern2>
  # ...
else
  # ...
end

Pattern có thể là:

  • Value: Any Ruby object (compared with the === operator, as in ‘when’).
  • Array: Array pattern: [<subpattern>, <subpattern>, <subpattern>, <subpattern>, ...].
  • Find: Search pattern: [*variable, <subpattern>, <subpattern>, <subpattern>, <subpattern>, ..., *variable].
  • Hash: Hash pattern: {key: <subpattern>, key: <subpattern>, ...}.
  • Alternative: Pattern combination with | (vertical bar).
  • Variable capture<pattern> => variable or variable.

Định nghĩa Pattern Matching

# Define a method that uses pattern matching with case/in
def process_data(data)
  case data
  in { type: "number", value: Integer => num }
    puts "Received a number: #{num}"
  in { type: "string", value: String => str }
    puts "Received a string: #{str}"
  in { type: "array", value: Array => arr }
    puts "Received an array: #{arr}"
  in { type: "hash", value: Hash => hash }
    puts "Received a hash: #{hash}"
  else
    puts "Received something else."
  end
end

# Test the method with different data structures
process_data({ type: "number", value: 42 })               # Output: Received a number: 42
process_data({ type: "string", value: "Hello, Ruby!" })   # Output: Received a string: Hello, Ruby!
process_data({ type: "array", value: [1, 2, 3] })         # Output: Received an array: [1, 2, 3]
process_data({ type: "hash", value: { key: "value" } })   # Output: Received a hash: {:key=>"value"}
process_data({ type: "unknown", value: "unknown data" })  # Output: Received something else.

Deconstruct và Deconstruct_keys

Đây là hai phương thức đặc biệt trong pattern matching: deconstruct, được gọi khi đánh giá trên một Array, và deconstruct_keys được gọi khi đánh giá trên một Hash. Hãy xem một ví dụ:

class Coordinates
  attr_accessor :x, :y

  def initialize(x, y)
    @x = x
    @y = y
  end

  def deconstruct
    [@x, @y]
  end

  def deconstruct_key
    {x: @x, y: @y}
  end
end

Khi một thể hiện của lớp Coordinate được đánh giá trên một Array

c = Coordinates.new(32,50)

case c
in [a,b]
  p a #=> 32
  p b #=> 50
end

Khi một thể hiện của lớp Coordinate được đánh giá trên một Hash

case c
in {x:, y:}
  p x #=> 32
  p y #=> 50
end

Nếu class không có 2 methods trên thì sẽ báo lỗi

#<Coordinate:0x000000010d27fb10 @x=32, @y=50>: #<Coordinate:0x000000010d27fb10 @x=32, @y=50> does not respond to #deconstruct (NoMatchingPatternError)

Tham khảo thêm tại: https://docs.ruby-lang.org/en/master/syntax/pattern_matching_rdoc.html

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like