Kiểu dữ liệu Symbol trong Ruby
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
Bài viết này được đăng tại [free tuts .net]
: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 String và Symbol ở 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.