Pergunta

Existe uma maneira fácil de testar se um objeto é um imutável (números, zero) ou não (Array, Hash, objetos)? Em outras palavras, poderia ser alterado por efeitos colaterais de outro código?

Motivação: eu quero criar uma loja de valor com versão, mas alguns dos dados é matrizes. Algumas das matrizes irá armazenar objetos personalizados, e eu poderia inverter a relação armazenando o 'em' propriedade e procurando por ela. Mas eu também gostaria de ser capaz de armazenar matrizes de símbolos, outras matrizes, etc.

Foi útil?

Solução

Não há objetos primitivos em Ruby. Isso não pode, portanto, ser detectada de forma simples.

Você não pode simplesmente usar Marshal ou YAML para a sua loja de versão? Então você terá carregar e salvar de todos os tipos de objetos de graça. Por que reinventar a roda?

Eu não sei o que você quer alcançar exatamente, mas olhando para a fonte de YAML pode ser interessante ver como eles lidam com este problema. A implementação de codificação de Ruby YAML simplesmente implementa o método to_yaml para todas as classes relevantes. Consulte yaml / rubytypes.rb .

Outras dicas

Eu encontrei uma maneira ineficiente:

class Object
  def primitive?
    begin
      self.dup
      false
    rescue TypeError
      true
    end
  end
end

A idéia de mutabilidade não se aplica realmente em Ruby da mesma forma que em outras línguas. O único objeto imutável é uma congelada. Você pode até mesmo adicionar métodos e variáveis ??de instância para Fixnums. Por exemplo:

class Fixnum
  attr_accessor :name
end
1.name = "one"
2.name = "two"

Obviamente, a grande maioria das vezes, as pessoas não vai ser suficiente patológica para adicionar atributos para Fixnum, mas o ponto é, nenhum objeto descongelado é verdadeiramente imutável.

Se você pode vir até com uma lista canônico de classes que você deseja assumir são imutáveis, você poderia simplesmente passar e dar-lhes todo um método immutable?() que os retornos verdadeiros (e Object uma versão que retorna falsos). Mas, como wvanbergen disse, a melhor maneira de certificar-se de sua cópia de um objeto não muda é a profunda copiar-lo com Marshal.

Outra diferença: objetos nativamente imutáveis ??não podem ser congelados, mas eles ainda retornar false de congelados

5.freeze.frozen? == false

Congelar não levanta uma exceção (ao contrário dup) No entanto, não (permanente!) Modificar objetos mutáveis.

Eu descobri que eu posso (pelo menos em seu estado atual) organizar meu aplicativo para trabalhar com objetos congelados, e rubi vai me dar uma exceção se eu tentar modificá-los diretamente. No entanto congelar afeta apenas o primeiro nível do objeto , e arrays, etc. armazenados nele ainda pode ser modificado.

Isso só se aplica a 1.8 - 5.frozen? retornos verdadeiros em ruby1.9 (mas não em irb1.9)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top