06/04/2021, 14:47

Kiểu dữ liệu Symbol trong Ruby - Ruby căn bản

Trong bài này chúng ta sẽ tìm hiểu kiểu dữ liệu Symboy trong Ruby, học cách sử dụng Symboy qua các ví dụ giúp bạn nắm vững hơn. Đây là một phần trong series các kiểu dữ liệu trong Ruby. Có thể nói kiểu dữ liệu trong Ruby là khá đa dạng, trong bài này mình xin phép giới thiệu cho các bạn một kiểu ...

Trong bài này chúng ta sẽ tìm hiểu kiểu dữ liệu Symboy trong Ruby, học cách sử dụng Symboy qua các ví dụ giúp bạn nắm vững hơn. Đây là một phần trong series các kiểu dữ liệu trong Ruby.

Có thể nói kiểu dữ liệu trong Ruby là khá đa dạng, trong bài này mình xin phép giới thiệu cho các bạn một kiểu dữ liệu mới đó chính là Symbol.

1. Symbol là gì ?

Symbol giống như một String thế nhưng Symbol là một chuỗi bất biến nghĩa là chúng ta không thể thay đổi được giá trị của Symbol, thường được dùng để đại diện cho danh tính của đối tượng. Khi mới bắt đầu học Ruby, sẽ có rất nhiều người bị nhầm lẫn giữa Symbol với một variable (biến), thật ra thì chúng không có liên quan với nhau.

Một Symbol sẽ có dạng như thế này

:something

Kể cả khi chúng ta viết như thế này, chỉ cần đúng cú pháp của Symbol thì nó sẽ vẫn biết đó là một Symbol

:"something".class
=> Symbol

:'something'.class
=> Symbol

Để khai báo một Symbol chúng ta sử dụng dấu hai chấm và theo sau đó là một từ nào đó. Một symbol thuộc class Symbol

a = :something
=> :something

a.class
=> Symbol

2. Khác biệt giữa String và Symbol

Khi mà tiếp xúc với Symbol người ta thường hay nhầm lẫn giữa Symbol và String, vì thế để cho chúng ta nắm được định nghĩa về kiểu dữ liệu này dễ dàng hơn thì mình cũng sẽ giới thiệu một vài sự khác biệt giữa StringSymbol ở trong phần này.

Khả năng bất biến

Như đã giới thiệu ở phần khái niệm mình đã nói, khi khai báo một Symbol thì giá trị này sẽ là không đổi

Đối với String, mọi thứ sẽ vẫn bình thường nếu như chúng ta thay đổi một giá trị ở trong ch

str = "quang phu"
=> "quang phu"

str[0] = "Q"
=> "Q"

puts str
=> "Quang phu"

Thế nhưng nếu bạn làm điều tượng tự với Symbol thì sẽ lỗi ngay.

str = :quangphu
=> :quangphu

str[0] = "Q"

=> Traceback (most recent call last):
        4: from /home/quangphu/.rbenv/versions/2.6.5/bin/irb:23:in `<main>'
        3: from /home/quangphu/.rbenv/versions/2.6.5/bin/irb:23:in `load'
        2: from /home/quangphu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.2.7/exe/irb:11:in `<top (required)>'
        1: from (irb):22
NoMethodError (undefined method `[]=' for :quangphu:Symbol)

Lưu trữ trong bộ nhớ

Vấn đề lưu trữ bộ nhớ là một vấn đề khá đáng lưu tâm trong lập trình vì nó sẽ ảnh hưởng đến performance của chương trình chúng ta.

Với String

"quang phu".object_id
=> 47357664248440

"quang phu".object_id
=> 47357662248800

"quang phu".object_id
=> 47357663872780

Với Symbol

:quangphu.object_id
=> 2014748

:quangphu.object_id
=> 2014748

:quangphu.object_id
=> 2014748

Trong ví dụ trên chúng ta sẽ dụng phương thức object_id để khiểm tra vùng nhớ được lưu trữ trong Ruby.

Dễ dàng nhận thấy rằng đối với String, thì mỗi lần chúng ta khai báo một chuỗi thì String đều tạo cho chúng một vùng nhớ mới mặc dù là giá trị của chúng đều như nhau. Khác với String thì Symbol lại cho một hiệu suất tốt hơn khi mà đối với những giá trị đã được khai báo chúng sẽ cấp phát một vùng nhớ, và bộ nhớ đó thì vẫn ở đấy, khi chúng ta khai báo một Symbol mới thì nó sẽ vẫn dùng giá trị tồn tại trước đó để sử dụng mà không phải là cấp phát 1 bộ nhớ mới.

Qua những giải thích trên thì chúng ta cũng có thể thấy rõ được Symbol cho chúng ta một performance tốt hơn là String, vì chúng tái sử dụng bộ nhớ chứ không phải tạo mới liên tục, điêu này sẽ làm giảm vấn đề lãng phí bộ nhớ.

Khi code chúng ta nên cân nhắc khi nào có thể dùng Symbol thay vì String để mang lại hiệu suất tốt hơn.

Symbol có nhanh hơn String không ?

Ở phần trên thì mình có nói về việc xử lý bộ nhớ của Symbol tốt hơn String, vậy liệu tốc độ của Symbol có nhanh hơn không thì mình sẽ cùng các bạn kiểm chứng

Để kiểm tra được tốc độ của chương trình mình sẽ sử dụng một thư viện là benchmark. Để sử dụng được thư viện này thì chúng ta cần require nó vào, vì nó chưa được tích hợp sẵn trong Ruby. Mình sẽ nói rõ hơn về thư viện này ở một bài khác.

require 'benchmark'
  str = Benchmark.measure do
    10_000_000.times do
      "phu" == "phu"
    end
  end.total

  sym = Benchmark.measure do
    10_000_000.times do
      :phu == :phu
    end
  end.total

puts "Toc do cua String: #{str}"
puts "Toc do cua Symbol: #{sym}"

Kết quả

Toc do cua String: 7.503974
Toc do cua Symbol: 3.0673269999999997

Kết quả cho chúng ta thấy Symbol có tốc độ nhanh hơn String là khá nhiều, đây là những tiện lợi mà Symbol mang lại nếu như chúng ta sử dụng nó.

3. Chuyển đổi dữ liệu qua lại giữa Symbol và String

Nếu muốn chuyển đổi qua lại giữa hai kiểu dữ liệu này, bạn có thể làm những cách sau.

Từ Symbol sang String

name = :phu
=> :phu

name.class
=> Symbol 

name = name.to_s
=> "phu" 

name.class
=> String 

Từ String sang Symbol

name = "phu"
=> "phu" 

name.class
=> String 

name = name.to_sym
=> :phu 

name.class
=> Symbol

4. Kết luận

Trong bài này chúng ta đã cùng đi tìm hiểu một kiểu dữ liệu khá mới trong Ruby đó chính là Symbol. Chúng ta hãy cố gắng hiểu rõ những lợi ích mà Symbol mang lại để có thể sử dụng chúng tốt trong thực tế, cụ thể lợi ích mà Symbol mang lại chính là performance của chương trình.

Tạ Quốc Bảo

23 chủ đề

7270 bài viết

0