Apesar de ler " Understanding Ruby Symbols ", ainda estou confuso com a representação dos dados na memória quando se trata de usar símbolos. Se um símbolo, dois deles contidos em objetos diferentes, existe no mesmo local de memória, então como é que eles contêm valores diferentes ? Eu esperava que o mesmo local de memória contivesse o mesmo valor.
Esta é uma citação do link:
Ao contrário das strings, os símbolos com o mesmo nome são inicializados e existem na memória apenas uma vez durante uma sessão de ruby
Não entendo como consegue diferenciar os valores contidos em um mesmo local de memória.
Considere este exemplo:
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
e patient2
ambos são hashes, tudo bem. :ruby
no entanto, é um símbolo. Se tivéssemos de produzir o seguinte:
patient1.each_key {|key| puts key.to_s}
Então, qual será a saída? "red"
, ou "programming"
?
Esquecendo os hashes por um segundo, estou pensando que um símbolo é um ponteiro para um valor. As perguntas que tenho são:
- Posso atribuir um valor a um símbolo?
- Um símbolo é apenas um ponteiro para uma variável com um valor?
- Se os símbolos são globais, isso significa que um símbolo sempre aponta para uma coisa?
puts patient1[:ruby]
, ele imprimirá "vermelho", se você disserputs patient2[:ruby]
, ele imprimirá "programação".Respostas:
Considere isto:
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
Portanto, no entanto, você cria um objeto de símbolo, desde que seu conteúdo seja o mesmo, ele se referirá ao mesmo objeto na memória. Isso não é um problema porque um símbolo é um objeto imutável . Strings são mutáveis.
(Em resposta ao comentário abaixo)
No artigo original, o valor não está sendo armazenado em um símbolo, mas em um hash. Considere isto:
hash1 = { "string" => "value"} hash2 = { "string" => "value"}
Isso cria seis objetos na memória - quatro objetos string e dois objetos hash.
hash1 = { :symbol => "value"} hash2 = { :symbol => "value"}
Isso cria apenas cinco objetos na memória - um símbolo, duas strings e dois objetos hash.
fonte
Hash
(criado por {... => ...} em seu código) que armazena pares de chave / valor, não osSymbol
próprios s. OsSymbol
s (por exemplo,:symbol
ou:sym
ou:ruby
) são as chaves dos pares. Apenas como parte de umHash
"apontam" para alguma coisa.Eu era capaz de entender os símbolos quando pensava assim. Uma string Ruby é um objeto que possui vários métodos e propriedades. As pessoas gostam de usar strings para chaves, e quando a string é usada para uma chave, todos esses métodos extras não são usados. Então eles fizeram símbolos, que são objetos de string com todas as funcionalidades removidas, exceto o que é necessário para que seja uma boa chave.
Pense nos símbolos como strings constantes.
fonte
O símbolo
:ruby
não contém"red"
ou"programming"
. O símbolo:ruby
é apenas o símbolo:ruby
. São os seus hashes,patient1
epatient2
cada um contém esses valores, em cada caso apontado pela mesma chave.Pense da seguinte maneira: se você for à sala de estar na manhã de Natal e vir duas caixas com uma etiqueta que diz "Kezzer". On tem meias e o outro carvão. Você não vai ficar confuso e perguntar como "Kezzer" pode conter tanto meias quanto carvão, embora tenha o mesmo nome. Porque o nome não contém os presentes (ruins). Está apenas apontando para eles. Da mesma forma,
:ruby
não contém os valores em seu hash, apenas aponta para eles.fonte
mystring = :steveT
o símbolo não aponta para nada. Uma chave em um hash tem um valor associado e a chave pode ser um símbolo. Mas um símbolo não precisa estar em um hash.Você pode estar presumindo que a declaração que você fez define o valor de um símbolo para ser algo diferente do que é. Na verdade, um símbolo é apenas um valor String "internalizado" que permanece constante. É porque eles são armazenados usando um identificador de número inteiro simples que eles são frequentemente usados, pois é mais eficiente do que gerenciar um grande número de strings de comprimento variável.
Veja o caso do seu exemplo:
patient1 = { :ruby => "red" }
Isso deve ser lido como: "declare uma variável paciente1 e defina-a como um Hash, e neste armazenamento o valor 'vermelho' sob a chave (símbolo 'rubi')"
Outra maneira de escrever isso é:
patient1 = Hash.new patient1[:ruby] = 'red' puts patient1[:ruby] # 'red'
Como você está fazendo uma atribuição, não é surpreendente que o resultado que você recebe seja idêntico ao que você atribuiu em primeiro lugar.
O conceito de símbolo pode ser um pouco confuso, pois não é uma característica da maioria das outras linguagens.
Cada objeto String é distinto, mesmo se os valores forem idênticos:
[ "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
Cada símbolo com o mesmo valor refere-se ao mesmo objeto:
[ :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
A conversão de strings em símbolos mapeia valores idênticos para o mesmo símbolo único:
[ "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
Da mesma forma, a conversão de Símbolo em String cria uma string distinta sempre:
[ :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
Você pode pensar nos valores de símbolo como sendo extraídos de uma tabela de Hash interna e pode ver todos os valores que foram codificados para símbolos usando uma chamada de método simples:
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=, ...
Conforme você define novos símbolos pela notação de dois pontos ou usando .to_sym, esta tabela aumentará.
fonte
Os símbolos não são ponteiros. Eles não contêm valores. Os símbolos simplesmente são .
:ruby
é o símbolo:ruby
e isso é tudo. Não contém um valor, não faz nada, só existe como símbolo:ruby
. O símbolo:ruby
é um valor igual ao número 1. Não aponta para outro valor mais do que o número 1 faz.fonte
Nem, a saída será "ruby".
Você está confundindo símbolos e hashes. Eles não são relacionados, mas são úteis juntos. O símbolo em questão é
:ruby
; não tem nada a ver com os valores no hash, e sua representação interna inteira será sempre a mesma, e seu "valor" (quando convertido em uma string) sempre será "ruby".fonte
Em resumo
Os símbolos resolvem o problema de criar representações imutáveis legíveis por humanos que também têm o benefício de serem mais simples para o tempo de execução de pesquisar do que as strings. Pense nisso como um nome ou rótulo que pode ser reutilizado.
Por que: vermelho é melhor do que "vermelho"
Em linguagens orientadas a objetos dinâmicas, você cria estruturas de dados complexas e aninhadas com referências legíveis. O hash é um caso de uso comum que você mapeia valores para chaves exclusivas - exclusivas, pelo menos, para cada instância. Você não pode ter mais de uma chave "vermelha" por hash.
No entanto, seria mais eficiente do processador usar um índice numérico em vez de chaves de string. Assim, os símbolos foram introduzidos como um meio-termo entre velocidade e legibilidade. Os símbolos resolvem muito mais fácil do que a string equivalente. Por serem legíveis por humanos e fáceis para o tempo de execução, os símbolos são um complemento ideal para uma linguagem dinâmica.
Benefícios
Como os símbolos são imutáveis, eles podem ser compartilhados durante o tempo de execução. Se duas instâncias de hash têm uma necessidade lexicográfica ou semântica comum de um item vermelho, o símbolo: vermelho usaria aproximadamente metade da memória que a string "vermelha" teria exigido para dois hashes.
Uma vez que: red sempre resolve de volta para o mesmo local na memória, ele pode ser reutilizado em uma centena de instâncias de hash com quase nenhum aumento na memória, enquanto que usar "red" adicionará um custo de memória, já que cada instância de hash precisaria armazenar a string mutável em criação.
Não tenho certeza de como Ruby realmente implementa símbolos / string, mas claramente um símbolo oferece menos sobrecarga de implementação no tempo de execução, pois é uma representação fixa. Os símbolos de adição levam um caractere a menos para digitar do que uma string entre aspas e menos digitação é a eterna busca dos verdadeiros Rubistas.
Resumo
Com um símbolo como: vermelho, você obtém a legibilidade da representação de string com menos sobrecarga devido ao custo das operações de comparação de string e à necessidade de armazenar cada instância de string na memória.
fonte
Eu recomendaria ler o artigo da Wikipedia sobre tabelas hash - acho que vai ajudá-lo a ter uma noção do que
{:ruby => "red"}
realmente significa.Outro exercício que pode ajudá-lo a entender a situação: considere
{1 => "red"}
. Semanticamente, isso não significa "definir o valor de1
para"red"
", o que é impossível em Ruby. Em vez disso, significa "criar um objeto Hash e armazenar o valor"red"
da chave1
.fonte
Nenhum, é claro. A saída será
ruby
. Que, BTW, você poderia ter descoberto em menos tempo do que demorou para digitar a pergunta, simplesmente digitando no IRB.Por que teria que ser
red
ouprogramming
? Os símbolos sempre avaliam a si mesmos. O valor do símbolo:ruby
é o:ruby
próprio símbolo e a representação da string do símbolo:ruby
é o valor da string"ruby"
.[BTW:
puts
sempre converte seus argumentos em strings, de qualquer maneira. Não há necessidade de ligarto_s
.]fonte
Sou novo em Ruby, mas acho (espero?) Que seja uma maneira simples de ver ...
Um símbolo não é uma variável ou constante. Não representa ou aponta para um valor. Um símbolo é um valor.
Tudo o que existe é uma string sem a sobrecarga do objeto. O texto e apenas o texto.
Então, é isso:
"hellobuddy"
É o mesmo que este:
:hellobuddy
Exceto que você não pode fazer, por exemplo,: hellobuddy.upcase. É o valor da string e SOMENTE o valor da string.
Da mesma forma, este:
greeting =>"hellobuddy"
É o mesmo que este:
greeting => :hellobuddy
Mas, novamente, sem a sobrecarga do objeto string.
fonte
Uma maneira fácil de entender isso é pensar: "e se eu estivesse usando uma corda em vez de um símbolo?
patient1 = { "ruby" => "red" } patient2 = { "ruby" => "programming" }
Não é nada confuso, certo? Você está usando "ruby" como chave em um hash .
"ruby"
é uma string literal, então esse é o valor. O endereço de memória, ou ponteiro, não está disponível para você. Cada vez que você invoca"ruby"
, você está criando uma nova instância dele, ou seja, criando uma nova célula de memória contendo o mesmo valor -"ruby"
.O hash vai então "qual é o meu valor-chave? Ah, é
"ruby"
. Em seguida, mapeia esse valor para" vermelho "ou" programação ". Em outras palavras,:ruby
não desreferencia para"red"
ou"programming"
. O hash mapeia:ruby
para"red"
ou"programming"
.Compare isso se usarmos símbolos
patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" }
O valor de
:ruby
também é"ruby"
, efetivamente.Por quê? Porque os símbolos são essencialmente constantes de string . Constantes não têm várias instâncias. É o mesmo endereço de memória. E um endereço de memória tem um certo valor, uma vez desreferenciado. Para símbolos, o nome do ponteiro é o símbolo e o valor não referenciado é uma string, que corresponde ao nome do símbolo, neste caso
"ruby"
,.Quando em um hash, você não está usando o símbolo, o ponteiro, mas o valor diferido. Voce nao esta usando
:ruby
, mas"ruby"
. O hash então procura a chave"ruby"
, o valor é"red"
ou"programming"
, dependendo de como você definiu o hash.A mudança de paradigma e o conceito básico é que o valor de um símbolo é um conceito completamente separado de um valor mapeado por um hash, dada uma chave desse hash.
fonte