Khi tôi nói { :bla => 1, :bloop => 2 }
, chính xác những gì :
làm? Tôi đã đọc ở đâu đó về cách nó tương tự như một chuỗi, nhưng bằng cách nào đó là một biểu tượng.
Tôi không quá rõ ràng về khái niệm này, ai đó có thể khai sáng cho tôi không?
Khi tôi nói { :bla => 1, :bloop => 2 }
, chính xác những gì :
làm? Tôi đã đọc ở đâu đó về cách nó tương tự như một chuỗi, nhưng bằng cách nào đó là một biểu tượng.
Tôi không quá rõ ràng về khái niệm này, ai đó có thể khai sáng cho tôi không?
Câu trả lời:
:foo
là một biểu tượng có tên là "foo". Các biểu tượng có đặc điểm riêng biệt là bất kỳ hai biểu tượng nào được đặt tên giống nhau sẽ giống hệt nhau:
"foo".equal? "foo" # false
:foo.equal? :foo # true
Điều này làm cho việc so sánh hai biểu tượng thực sự nhanh chóng (vì chỉ có một so sánh con trỏ được tham gia, trái ngược với việc so sánh tất cả các ký tự giống như bạn trong một chuỗi), cộng với việc bạn sẽ không có hàng triệu bản sao của cùng một biểu tượng.
Ngoài ra, không giống như chuỗi, biểu tượng là bất biến.
"foo".equal? "foo"
sai? b) Bạn có thể đề cập đến một biểu tượng ở bất cứ đâu, về cơ bản làm cho chúng giống như các biến toàn cầu?
equal?
trong Ruby không so sánh danh tính. Mỗi chuỗi ký tự, như "foo"
, tạo ra một thể hiện chuỗi mới. Nó hoạt động theo cách đó bởi vì các chuỗi trong Ruby có thể thay đổi. 2. Biểu tượng là toàn cục, nhưng giống các hằng số toàn cầu hơn các biến toàn cục, vì các biểu tượng không có trạng thái. Do đó, việc sử dụng các ký hiệu không phải là một phản mẫu theo cách các biến toàn cục.
"foo" == "foo"
# => đúng
Chỉ để chứng minh một số điều được đề cập trong các câu trả lời:
require 'benchmark'
n = 1_000_000
print '"foo".equal? "foo" -> ', ("foo".equal? "foo"), "\n"
print '"foo" == "foo" -> ', ("foo" == "foo" ), "\n"
print ':foo.equal? :foo -> ', (:foo.equal? :foo ), "\n"
print ':foo == :foo -> ', (:foo == :foo ), "\n"
Benchmark.bm(10) do |b|
b.report('string') { n.times { "foo".equal? "foo" }}
b.report('str == str') { n.times { "foo" == "foo" }}
b.report('symbol') { n.times { :foo.equal? :foo }}
b.report('sym == sym') { n.times { :foo == :foo }}
end
Chạy nó đầu ra:
"foo".equal? "foo" -> false
"foo" == "foo" -> true
:foo.equal? :foo -> true
:foo == :foo -> true
Vì vậy, việc so sánh một chuỗi với một chuỗi sử dụng equal?
không thành công vì chúng là các đối tượng khác nhau, ngay cả khi chúng có cùng nội dung. ==
so sánh nội dung và kiểm tra tương đương với các biểu tượng nhanh hơn nhiều.
user system total real
string 0.370000 0.000000 0.370000 ( 0.371700)
str == str 0.330000 0.000000 0.330000 ( 0.326368)
symbol 0.170000 0.000000 0.170000 ( 0.174641)
sym == sym 0.180000 0.000000 0.180000 ( 0.179374)
Cả hai bài kiểm tra biểu tượng về cơ bản đều giống như tốc độ. Sau 1.000.000 lần lặp lại, chỉ có 0,004733 giây khác nhau, vì vậy tôi muốn nói rằng đó là một sự thay đổi giữa việc sử dụng.
==
kết quả nhanh hơn so .equal?
với cả so sánh chuỗi và ký hiệu. So sánh biểu tượng cho kết quả nhanh hơn 3 lần so với so sánh chuỗi.
Biểu tượng là một cách để thể hiện chuỗi và tên trong ruby.
Sự khác biệt chính giữa các ký hiệu và chuỗi là các ký hiệu cùng tên được khởi tạo và tồn tại trong bộ nhớ chỉ một lần trong một phiên của ruby.
Chúng rất hữu ích khi bạn cần sử dụng cùng một từ để thể hiện những thứ khác nhau
Có một số trích dẫn từ cuốn sách nổi tiếng Agile Web Development with Rails , có thể hữu ích để hiểu biểu tượng này :
Rails sử dụng các biểu tượng để xác định sự vật. Cụ thể, nó sử dụng chúng làm khóa khi đặt tên các tham số của phương thức và tìm kiếm mọi thứ trong băm.
redirect_to :action => "edit", :id => params[:id]
Bạn có thể nghĩ về các biểu tượng như các chuỗi ký tự được tạo thành các hằng số. Ngoài ra, bạn có thể coi dấu hai chấm có nghĩa là "vật được đặt tên", vì vậy: id là "vật có tên id".
Trong ruby, mỗi đối tượng có một mã định danh đối tượng duy nhất, nếu bạn viết puts "hello".object_id
vào irb của mình và nhấn return trong 2 lần khác nhau, bạn sẽ nhận được 2 giá trị trả về khác nhau, nhưng nếu bạn viết :hello.object_id
2 lần, bạn sẽ chỉ nhận được cùng một giá trị trả về. Điều đó nên đã giải thích sự khác biệt.
Nếu bạn sử dụng :foo => bar
, foo sẽ là một biểu tượng. Lợi ích cho các biểu tượng là chúng là duy nhất. Khi bạn gọi một mục trong hàm băm, bạn làm hash[:foo]
.
Các biểu tượng đòi hỏi ít bộ nhớ hơn các chuỗi, điều này cũng làm cho chúng hữu ích nếu bạn muốn làm cho chương trình của mình nhanh hơn một chút.
Tất cả những câu trả lời này đều bỏ qua một chi tiết trêu ngươi thêm .. nếu bạn xâu chuỗi ký hiệu: foo, bạn sẽ nhận được .. đoán xem .. chuỗi "foo". Vì thế
irb(main):025:0>
irb(main):026:0> :foo
=> :foo
irb(main):027:0> "#{:foo}"
=> "foo"
irb(main):028:0>
irb(main):029:0> 'foo' <=> :foo
=> nil
irb(main):030:0> 'foo' <=> :foo.to_s
=> 0
irb(main):031:0>
Do đó .. đối với các lập trình viên Perl .. đó là câu trả lời của Ruby cho 'từ trần'.
Nếu bạn quen thuộc với Java, bạn có thể biết rằng Chuỗi trong Java là bất biến. Các biểu tượng tương tự theo nghĩa đó trong Ruby. Chúng là bất biến, tức là, bất kỳ số lần xuất hiện nào của một biểu tượng cụ thể :symbol
sẽ ánh xạ tới chỉ một địa chỉ bộ nhớ. Và, do đó, nên sử dụng các ký hiệu bất cứ khi nào có thể vì nó tối ưu hóa việc sử dụng bộ nhớ.
NSString
. Sẽ "foo"
luôn luôn bằng nhau "foo"
, bởi vì các chuỗi bên trong giống nhau được chỉ vào. Câu trả lời vẫn sẽ gây nhầm lẫn.