Câu hỏi Cách hiểu biểu tượng trong Ruby


Mặc dù đọc "Tìm hiểu các biểu tượng Ruby", Tôi vẫn còn bối rối bởi sự biểu diễn của dữ liệu trong bộ nhớ khi nói đến việc sử dụng các biểu tượng. Nếu một biểu tượng, hai trong số chúng chứa trong các đối tượng khác nhau, tồn tại trong cùng một vị trí bộ nhớ, thì nó chứa chúng như thế nào khác nhau giá trị? Tôi đã mong đợi cùng một vị trí bộ nhớ để chứa cùng một giá trị.

Đây là trích dẫn từ liên kết:

Không giống như các chuỗi, 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

Tôi không hiểu cách nó quản lý để phân biệt các giá trị chứa trong cùng một vị trí bộ nhớ.

Xem xét ví dụ này:

patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }

patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094

patient1 và patient2 đều là băm, điều đó tốt. :ruby tuy nhiên là một biểu tượng. Nếu chúng tôi đã xuất ra những điều sau đây:

patient1.each_key {|key| puts key.to_s}

Sau đó, những gì sẽ được sản lượng? "red", hoặc là "programming"?

Quên băm trong một giây, tôi nghĩ một biểu tượng là một con trỏ cho một giá trị. Các câu hỏi tôi có là:

  • Tôi có thể gán một giá trị cho một biểu tượng không?
  • Là một biểu tượng chỉ là một con trỏ đến một biến với một giá trị trong nó?
  • Nếu các biểu tượng là toàn cầu, điều đó có nghĩa là một biểu tượng luôn luôn trỏ đến một điều?

76
2018-02-26 13:22


gốc


Nó sẽ xuất ra ": ruby", bởi vì bạn đang in một Symbol. Nếu bạn nói puts patient1[:ruby], nó sẽ in "đỏ", nếu bạn nói puts patient2[:ruby], nó sẽ in "lập trình". - R.O.S.S
Biểu tượng KHÔNG phải là con trỏ tới giá trị. Nội bộ một biểu tượng chỉ là một số nguyên. - akuhn


Các câu trả lời:


Xem xét điều này:

x = :sym
y = :sym
(x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true

x = "string"
y = "string"
(x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false

Vì vậy, tuy nhiên bạn tạo một đối tượng biểu tượng, miễn là nội dung của nó là như nhau, nó sẽ tham chiếu đến cùng một đối tượng trong bộ nhớ. Đây không phải là một vấn đề bởi vì một biểu tượng là một đối tượng bất biến. Các chuỗi có thể thay đổi.


(Để trả lời bình luận bên dưới)

Trong bài viết gốc, giá trị không được lưu trữ trong một biểu tượng, nó đang được lưu trữ trong một băm. Xem xét điều này:

hash1 = { "string" => "value"}
hash2 = { "string" => "value"}

Điều này tạo ra sáu đối tượng trong bộ nhớ - bốn đối tượng chuỗi và hai đối tượng băm.

hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}

Điều này chỉ tạo ra năm đối tượng trong bộ nhớ - một biểu tượng, hai chuỗi và hai đối tượng băm.


55
2018-02-26 13:35



Ví dụ trong liên kết, tuy nhiên, hiển thị các biểu tượng có chứa khác nhau các giá trị, nhưng biểu tượng có cùng tên và cùng một vị trí bộ nhớ. Khi chúng xuất, chúng có khác nhau giá trị, đó là phần tôi không nhận được. Chắc chắn họ nên chứa cùng một giá trị? - Kezzer
Tôi vừa thực hiện một chỉnh sửa để thử và giải thích làm thế nào tôi vẫn còn bối rối. Não của tôi không thể tính toán;) - Kezzer
Ký hiệu không chứa giá trị, chúng là giá trị. Dấu gạch ngang chứa các giá trị. - Mladen Jablanović
Đó là Hash (được tạo bởi {... => ...} trong mã của bạn) lưu trữ cặp khóa / giá trị, chứ không phải Symbolcủa chính họ. Các Symbols (ví dụ: :symbol hoặc là :sym hoặc là :ruby) là chìa khóa trong cặp. Chỉ là một phần của Hash họ có "chỉ" vào bất cứ điều gì không. - James A. Rosen
Biểu tượng đang được sử dụng làm khóa trong giá trị băm không phải là giá trị, đó là lý do tại sao chúng có thể khác nhau, nó tương tự như sử dụng câu lệnh key1 = 'ruby' và hash1 = {key1 => 'value' ...} hash2 = { key1 => 'value2' ...}. - Joshua Olson


Tôi đã có thể grock biểu tượng khi tôi nghĩ về nó như thế này. Một chuỗi Ruby là một đối tượng có một loạt các phương thức và thuộc tính. Mọi người thích sử dụng chuỗi cho khóa và khi chuỗi được sử dụng cho khóa thì tất cả các phương thức bổ sung đó không được sử dụng. Vì vậy, họ đã tạo ra các biểu tượng, đó là các đối tượng chuỗi với tất cả các chức năng đã bị loại bỏ, ngoại trừ cái cần thiết để nó trở thành một chìa khóa tốt.

Chỉ cần nghĩ về các biểu tượng như các chuỗi liên tục.


45
2018-02-26 14:40



Đọc qua các bài viết, điều này có lẽ có ý nghĩa nhất đối với tôi. : ruby ​​chỉ được lưu trữ ở đâu đó trong bộ nhớ, nếu tôi sử dụng "ruby" một nơi nào đó, sau đó "ruby" một lần nữa một nơi nào đó một lần nữa, nó chỉ là trùng lặp. Vì vậy, việc sử dụng các biểu tượng là một cách để giảm trùng lặp dữ liệu chung. Như bạn nói, các chuỗi liên tục. Tôi đoán có một số cơ chế cơ bản sẽ tìm thấy biểu tượng đó một lần nữa để sử dụng? - Kezzer
@Kezzer Câu trả lời này thực sự tốt và có vẻ phù hợp với tôi, nhưng nhận xét của bạn nói điều gì đó khác biệt và sai hoặc gây hiểu nhầm, nhận xét của bạn nói về sao chép dữ liệu bằng chuỗi và đó là lý do cho các ký hiệu, sai hoặc gây hiểu lầm. biểu tượng nhiều lần sẽ không sử dụng hết dung lượng bộ nhớ, nhưng bạn cũng có thể sử dụng nó cho nhiều chuỗi, ví dụ: một số ngôn ngữ lập trình nếu bạn viết "abc" và ở nơi khác "abc" trình biên dịch thấy nó là chuỗi giá trị giống nhau và lưu trữ nó ở cùng một nơi làm cho nó cùng một đối tượng, được gọi là chuỗi interning và c # thực hiện điều đó. - barlop


Biểu tượng :ruby không chứa "red" hoặc là "programming". Biểu tượng :ruby chỉ là biểu tượng :ruby. Nó là băm của bạn, patient1 và patient2 mỗi giá trị chứa các giá trị đó, trong mỗi trường hợp được trỏ đến bởi cùng một khóa.

Hãy suy nghĩ về nó theo cách này: Nếu bạn đi vào phòng khách vào buổi sáng Giáng sinh, và thấy hai hộp với một thẻ trên đó nói rằng "Kezzer" trên chúng. Trên có vớ trong đó, và cái kia có than. Bạn sẽ không bị lẫn lộn và hỏi làm thế nào "Kezzer" có thể chứa cả hai vớ và than đá, mặc dù nó là cùng tên. Bởi vì tên không chứa các món quà (crappy). Nó chỉ chỉ vào họ. Tương tự, :ruby không chứa các giá trị trong băm của bạn, nó chỉ trỏ vào chúng.


28
2018-02-26 14:37



Câu trả lời này có ý nghĩa hoàn chỉnh. - Vass
xin vui lòng đặt một số điều này vào tài liệu chính thức của ruby - dit
Điều này nghe có vẻ giống như một tổng hợp của băm và biểu tượng. Một biểu tượng không trỏ đến một giá trị, nếu bạn muốn nói nó khi nào trong một băm, tốt, điều đó có thể được tranh cãi, nhưng một biểu tượng không phải là một băm. Bạn có thể nói mystring = :steveT   biểu tượng không trỏ đến bất cứ điều gì. Khóa trong giá trị băm có giá trị được liên kết và khóa có thể là biểu tượng. Nhưng một biểu tượng không cần phải là một băm. - barlop


Bạn có thể giả sử rằng tuyên bố bạn đã thực hiện xác định giá trị của một Biểu tượng là một cái gì đó khác với nó là gì. Trong thực tế, một Symbol chỉ là một giá trị String "internalized" mà vẫn không đổi. Đó là bởi vì chúng được lưu trữ bằng cách sử dụng một định danh số nguyên đơn giản mà chúng thường được sử dụng vì nó hiệu quả hơn việc quản lý một số lượng lớn các chuỗi có độ dài biến đổi.

Lấy ví dụ của bạn:

patient1 = { :ruby => "red" }

Điều này nên được đọc là: "khai báo một biến bệnh nhân1 và xác định nó là một Hash, và trong cửa hàng này giá trị 'đỏ' dưới khóa (biểu tượng 'ruby')"

Một cách viết khác là:

patient1 = Hash.new
patient1[:ruby] = 'red'

puts patient1[:ruby]
# 'red'

Khi bạn đang thực hiện một nhiệm vụ đó là hầu như không đáng ngạc nhiên rằng kết quả bạn nhận được là giống hệt với những gì bạn đã gán nó với ở nơi đầu tiên.

Khái niệm Biểu tượng có thể hơi khó hiểu vì nó không phải là một tính năng của hầu hết các ngôn ngữ khác.

Mỗi đối tượng String là khác biệt ngay cả khi các giá trị giống hệt nhau:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148099960
# "foo" 2148099940
# "foo" 2148099920
# "bar" 2148099900
# "bar" 2148099880
# "bar" 2148099860

Mỗi Biểu tượng có cùng giá trị đều đề cập đến cùng một đối tượng:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

Việc chuyển đổi chuỗi thành các ký hiệu ánh xạ các giá trị giống hệt nhau cho cùng một Biểu tượng duy nhất:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  v = v.to_sym
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

Tương tự như vậy, việc chuyển đổi từ Symbol thành String tạo ra một chuỗi riêng biệt mỗi lần:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  v = v.to_s
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148097820
# "foo" 2148097700
# "foo" 2148097580
# "bar" 2148097460
# "bar" 2148097340
# "bar" 2148097220

Bạn có thể nghĩ về các giá trị Symbol như được rút ra từ một bảng Hash bên trong và bạn có thể thấy tất cả các giá trị đã được mã hóa thành các Biểu tượng bằng cách sử dụng một cuộc gọi phương thức đơn giản:

Symbol.all_values

# => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :@seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...

Khi bạn xác định các ký hiệu mới bằng ký hiệu dấu hai chấm hoặc bằng cách sử dụng .to_sym, bảng này sẽ phát triển.


25
2018-02-26 15:34





Ký hiệu không phải là con trỏ. Chúng không chứa giá trị. Ký hiệu đơn giản . :ruby là biểu tượng :ruby và đó là tất cả để có nó. Nó không chứa một giá trị, nó không làm bất cứ điều gì, nó chỉ tồn tại như là biểu tượng :ruby. Biểu tượng :ruby là một giá trị giống như số 1. Nó không trỏ đến một giá trị nào khác hơn số 1.


14
2018-02-26 18:31



Great annalogy cho một số - jperelli
Nó giống như một băm? - Vass


patient1.each_key {|key| puts key.to_s}

Sau đó, những gì sẽ được sản lượng? "màu đỏ" hoặc   "lập trình"?

Không, nó sẽ xuất ra "ruby".

Bạn đang bối rối biểu tượng và băm. Chúng không liên quan, nhưng chúng hữu ích với nhau. Biểu tượng được đề cập là :ruby; nó không có gì để làm với các giá trị trong hàm băm, và biểu diễn số nguyên bên trong của nó sẽ luôn giống nhau và "giá trị" (khi được chuyển đổi thành chuỗi) sẽ luôn là "ruby".


12
2018-02-26 14:41





Nói ngắn gọn

Các ký hiệu giải quyết vấn đề tạo ra các biểu diễn có thể đọc được, có thể đọc được của con người cũng có lợi ích là đơn giản hơn cho thời gian chạy tra cứu hơn các chuỗi. Hãy nghĩ về nó như tên hoặc nhãn có thể được sử dụng lại.

Tại sao: đỏ tốt hơn "đỏ" 

Trong các ngôn ngữ hướng đối tượng động, bạn tạo các cấu trúc dữ liệu lồng nhau phức tạp với các tham chiếu có thể đọc được. Các băm là trường hợp sử dụng phổ biến nơi bạn ánh xạ các giá trị cho các khóa duy nhất - ít nhất, ít nhất là đối với mỗi cá thể. Bạn không thể có nhiều hơn một khóa "màu đỏ" cho mỗi băm.

Tuy nhiên nó sẽ có nhiều bộ vi xử lý hiệu quả hơn để sử dụng một chỉ mục số thay vì các phím chuỗi. Vì vậy, các biểu tượng được giới thiệu như là một sự thỏa hiệp giữa tốc độ và khả năng đọc. Biểu tượng giải quyết dễ dàng hơn nhiều so với chuỗi tương đương. Bằng cách là con người có thể đọc được và dễ dàng cho thời gian chạy để giải quyết các biểu tượng là một bổ sung lý tưởng cho một ngôn ngữ năng động.

Lợi ích

Vì các ký hiệu là không thay đổi nên chúng có thể được chia sẻ trong suốt thời gian chạy. Nếu hai trường hợp băm có nhu cầu từ điển hoặc ngữ nghĩa chung cho một mục màu đỏ biểu tượng: màu đỏ sẽ sử dụng khoảng một nửa bộ nhớ mà chuỗi "màu đỏ" sẽ yêu cầu cho hai băm.

Vì màu đỏ luôn phân giải trở lại cùng một vị trí trong bộ nhớ, nó có thể được tái sử dụng trên một trăm trường hợp băm với hầu như không tăng bộ nhớ, trong khi sử dụng "đỏ" sẽ tăng thêm chi phí bộ nhớ vì mỗi thể hiện băm sẽ cần lưu trữ chuỗi có thể thay đổi sự sáng tạo.

Bạn không chắc chắn cách Ruby thực hiện các biểu tượng / chuỗi nhưng rõ ràng một biểu tượng cung cấp ít chi phí thực thi hơn trong thời gian chạy vì nó là một biểu diễn cố định. Biểu tượng cộng thêm một ký tự ít hơn so với chuỗi được trích dẫn và ít nhập là việc theo đuổi vĩnh cửu của những người theo chủ nghĩa thực sự.

Tóm lược

Với một biểu tượng như: đỏ, bạn sẽ có được khả năng đọc của biểu diễn chuỗi với chi phí thấp hơn do chi phí của các hoạt động so sánh chuỗi và sự cần thiết để lưu trữ mỗi thể hiện chuỗi trong bộ nhớ.


10
2017-09-03 22:10





patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }

patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094

patient1 và patient2 đều là băm, điều đó tốt. :ruby tuy nhiên là một biểu tượng. Nếu chúng tôi đã xuất ra những điều sau đây:

patient1.each_key {|key| puts key.to_s}

Sau đó, những gì sẽ được sản lượng? "đỏ" hoặc "lập trình"?

Không, tất nhiên. Đầu ra sẽ là ruby. Trong đó, BTW, bạn có thể đã phát hiện ra trong thời gian ít hơn nó đã cho bạn để gõ câu hỏi, bằng cách đơn giản gõ nó vào IRB thay thế.

Tại sao sẽ nó là red hoặc là programming? Ký hiệu luôn luôn tự đánh giá. Giá trị của biểu tượng :ruby là biểu tượng :ruby chính nó và biểu diễn chuỗi ký hiệu :ruby là giá trị chuỗi "ruby".

[BTW: puts luôn luôn chuyển đổi các đối số của nó thành chuỗi. Không cần phải gọi to_s trên đó.]


3
2018-02-26 14:29



Tôi không có IRB trên máy hiện tại, tôi sẽ không thể cài đặt nó vì thế, vì vậy tôi xin lỗi vì điều đó. - Kezzer
@ Kezzer: Đừng lo, tôi chỉ tò mò thôi. Đôi khi bạn chôn mình sâu vào một vấn đề mà bạn thậm chí không thể nhìn thấy những điều đơn giản nữa. Khi tôi về cơ bản cắt và dán câu hỏi của bạn vào IRB, tôi chỉ tự hỏi: "tại sao anh ta không tự mình làm điều đó?" Và đừng lo lắng, bạn không phải là người đầu tiên (bạn cũng sẽ không phải là người cuối cùng), những người hỏi "những gì in này" khi câu trả lời là "chỉ cần chạy nó!" BTW: đây là IRB tức thì của bạn, mọi lúc, mọi nơi, không cần cài đặt: TryRuby.Org Hoặc là Ruby-Versions.Net cung cấp cho bạn quyền truy cập SSH vào tất cả các phiên bản MRI từng được phát hành + YARV + JRuby + Rubinius + REE. - Jörg W Mittag
Cảm ơn, chỉ cần chơi đùa với nó ngay bây giờ. Tôi vẫn còn một chút bối rối mặc dù vậy đi qua nó một lần nữa. - Kezzer


Tôi khuyên bạn nên đọc Bài viết trên Wikipedia về các bảng băm - Tôi nghĩ nó sẽ giúp bạn hiểu được {:ruby => "red"} Thực sự có nghĩa là.

Một bài tập khác có thể giúp bạn hiểu về tình huống: xem xét {1 => "red"}. Về mặt ngữ nghĩa, điều này không có nghĩa là "đặt giá trị của 1 đến "red"", điều đó là không thể trong Ruby. Thay vào đó, nó có nghĩa là" tạo ra một Băm và lưu trữ giá trị "red" cho chìa khóa 1.


3
2018-02-26 17:11