Nếu có ít nhất hai trường hợp của cùng một chuỗi trong tập lệnh của tôi, thay vào đó tôi có nên sử dụng một ký hiệu không?
Nếu có ít nhất hai trường hợp của cùng một chuỗi trong tập lệnh của tôi, thay vào đó tôi có nên sử dụng một ký hiệu không?
Câu trả lời:
Một nguyên tắc chung đơn giản là sử dụng các ký hiệu mỗi khi bạn cần số nhận dạng nội bộ. Đối với Ruby <2.2, chỉ sử dụng các biểu tượng khi chúng không được tạo động, để tránh rò rỉ bộ nhớ.
Lý do duy nhất để không sử dụng chúng cho các số nhận dạng được tạo động là vì lo ngại về bộ nhớ.
Câu hỏi này rất phổ biến vì nhiều ngôn ngữ lập trình không có ký hiệu, chỉ có chuỗi và do đó chuỗi cũng được sử dụng làm định danh trong mã của bạn. Bạn nên lo lắng về những biểu tượng có nghĩa là gì , không chỉ khi bạn nên sử dụng các biểu tượng . Các ký hiệu được dùng để nhận dạng. Nếu bạn tuân theo triết lý này, rất có thể bạn sẽ làm đúng.
Có một số khác biệt giữa việc triển khai các ký hiệu và chuỗi. Điều quan trọng nhất về các biểu tượng là chúng không thể thay đổi . Điều này có nghĩa là chúng sẽ không bao giờ bị thay đổi giá trị. Do đó, các ký hiệu được khởi tạo nhanh hơn các chuỗi và một số thao tác như so sánh hai ký hiệu cũng nhanh hơn.
Thực tế là một biểu tượng là bất biến cho phép Ruby sử dụng cùng một đối tượng mỗi khi bạn tham chiếu đến biểu tượng, tiết kiệm bộ nhớ. Vì vậy, mỗi khi trình thông dịch đọc :my_key
nó có thể lấy nó từ bộ nhớ thay vì khởi tạo lại nó. Điều này ít tốn kém hơn so với việc khởi tạo một chuỗi mới mỗi lần.
Bạn có thể nhận được danh sách tất cả các ký hiệu đã được khởi tạo bằng lệnh Symbol.all_symbols
:
symbols_count = Symbol.all_symbols.count # all_symbols is an array with all
# instantiated symbols.
a = :one
puts a.object_id
# prints 167778
a = :two
puts a.object_id
# prints 167858
a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!
puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.
Đối với các phiên bản Ruby trước 2.2, một khi một biểu tượng được khởi tạo, bộ nhớ này sẽ không bao giờ trống nữa . Cách duy nhất để giải phóng bộ nhớ là khởi động lại ứng dụng. Vì vậy các ký hiệu cũng là một nguyên nhân chính gây ra hiện tượng rò rỉ bộ nhớ khi sử dụng không đúng cách. Cách đơn giản nhất để tạo rò rỉ bộ nhớ là sử dụng phương pháp to_sym
trên dữ liệu đầu vào của người dùng, vì dữ liệu này sẽ luôn thay đổi, một phần bộ nhớ mới sẽ được sử dụng mãi mãi trong phiên bản phần mềm. Ruby 2.2 đã giới thiệu trình thu gom rác biểu tượng , giúp giải phóng các biểu tượng được tạo động, vì vậy việc rò rỉ bộ nhớ được tạo ra bằng cách tạo biểu tượng động sẽ không còn là mối quan tâm nữa.
Trả lời câu hỏi của bạn:
Có đúng là tôi phải sử dụng một biểu tượng thay vì một chuỗi nếu có ít nhất hai chuỗi giống nhau trong ứng dụng hoặc tập lệnh của tôi không?
Nếu những gì bạn đang tìm kiếm là một số nhận dạng được sử dụng trong nội bộ mã của bạn, bạn nên sử dụng các ký hiệu. Nếu bạn đang in kết quả đầu ra, bạn nên sử dụng chuỗi, ngay cả khi nó xuất hiện nhiều lần, thậm chí phân bổ hai đối tượng khác nhau trong bộ nhớ.
Đây là lý do:
@AlanDert: nếu tôi sử dụng nhiều lần một cái gì đó như% input {type:: checkbox} trong mã haml, thì tôi nên sử dụng cái gì làm hộp kiểm?
Me: Vâng.
@AlanDert: Nhưng để in ra một biểu tượng trên trang html, nó phải được chuyển đổi thành chuỗi, phải không? lợi ích của việc sử dụng nó sau đó là gì?
Loại đầu vào là gì? Mã định danh của loại đầu vào bạn muốn sử dụng hoặc thứ gì đó bạn muốn hiển thị cho người dùng?
Đúng là một lúc nào đó nó sẽ trở thành mã HTML, nhưng tại thời điểm bạn đang viết dòng mã đó, nó có nghĩa là một mã định danh - nó xác định loại trường đầu vào bạn cần. Do đó, nó được sử dụng lặp đi lặp lại trong mã của bạn và luôn có cùng một "chuỗi" ký tự làm mã định danh và sẽ không tạo ra rò rỉ bộ nhớ.
Điều đó nói rằng, tại sao chúng ta không đánh giá dữ liệu để xem liệu các chuỗi có nhanh hơn không?
Đây là một điểm chuẩn đơn giản mà tôi đã tạo cho việc này:
require 'benchmark'
require 'haml'
str = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: "checkbox"}').render
end
end.total
sym = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: :checkbox}').render
end
end.total
puts "String: " + str.to_s
puts "Symbol: " + sym.to_s
Ba đầu ra:
# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68
Vì vậy, sử dụng smbols thực sự nhanh hơn một chút so với sử dụng chuỗi. Tại sao vậy? Nó phụ thuộc vào cách HAML được thực hiện. Tôi sẽ cần hack một chút mã HAML để xem, nhưng nếu bạn tiếp tục sử dụng các ký hiệu trong khái niệm định danh, ứng dụng của bạn sẽ nhanh hơn và đáng tin cậy hơn. Khi câu hỏi xuất hiện, hãy đánh giá tiêu chuẩn và nhận câu trả lời của bạn.
Nói một cách đơn giản, một biểu tượng là một cái tên, bao gồm các ký tự, nhưng bất biến. Ngược lại, một chuỗi là một vùng chứa có thứ tự cho các ký tự, mà nội dung của chúng được phép thay đổi.
Để so sánh hai chuỗi, chúng ta có thể cần phải xem xét mọi ký tự. Đối với hai chuỗi có độ dài N, điều này sẽ yêu cầu N + 1 so sánh (mà các nhà khoa học máy tính gọi là "O (N) time").
def string_comp str1, str2
return false if str1.length != str2.length
for i in 0...str1.length
return false if str1[i] != str2[i]
end
return true
end
string_comp "foo", "foo"
Nhưng vì mọi lần xuất hiện của: foo đều đề cập đến cùng một đối tượng, chúng ta có thể so sánh các ký hiệu bằng cách xem ID đối tượng. Chúng ta có thể làm điều này với một phép so sánh duy nhất (mà các nhà khoa học máy tính gọi là "O (1) time").
def symbol_comp sym1, sym2
sym1.object_id == sym2.object_id
end
symbol_comp :foo, :foo
Trong C ++, chúng ta có thể sử dụng "liệt kê" để biểu diễn họ của các hằng số có liên quan:
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;
BugStatus current_status = CLOSED;
Nhưng vì Ruby là một ngôn ngữ động, chúng tôi không lo lắng về việc khai báo loại BugStatus hoặc theo dõi các giá trị pháp lý. Thay vào đó, chúng tôi biểu diễn các giá trị liệt kê dưới dạng ký hiệu:
original_status = :open
current_status = :closed
3.Một biểu tượng Ruby là một tên không đổi, duy nhất
Trong Ruby, chúng ta có thể thay đổi nội dung của một chuỗi:
"foo"[0] = ?b # "boo"
Nhưng chúng tôi không thể thay đổi nội dung của một biểu tượng:
:foo[0] = ?b # Raises an error
Khi chuyển các đối số từ khóa cho một hàm Ruby, chúng tôi chỉ định các từ khóa bằng cách sử dụng các ký hiệu:
# Build a URL for 'bug' using Rails.
url_for :controller => 'bug',
:action => 'show',
:id => bug.id
Thông thường, chúng tôi sẽ sử dụng các ký hiệu để đại diện cho các khóa của bảng băm:
options = {}
options[:auto_save] = true
options[:show_comments] = false
Dưới đây là một tiêu chuẩn tốt về chuỗi và ký hiệu mà tôi tìm thấy tại codecademy:
require 'benchmark'
string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
string_time = Benchmark.realtime do
1000_000.times { string_AZ["r"] }
end
symbol_time = Benchmark.realtime do
1000_000.times { symbol_AZ[:r] }
end
puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."
Đầu ra là:
String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.
sử dụng các ký hiệu làm mã nhận dạng khóa băm
{key: "value"}
biểu tượng cho phép bạn gọi phương thức theo một thứ tự khác
ghi def (tệp :, data :, mode: "ascii") # đã xóa cho ngắn gọn kết thúc ghi (dữ liệu: 123, tệp: "test.txt")
đóng băng để giữ dưới dạng chuỗi và tiết kiệm bộ nhớ
label = 'My Label'.freeze
/
(saustrings
) khỏi liên kết. Đây là: www.reactive.io/tips/2009/01/11/the-difference-between-ruby- biểu tượng-và-chuỗi