Verifique se uma variável é uma string no Ruby

124

Existe algo mais idiomático do que o seguinte?

foo.class == String
davidchambers
fonte

Respostas:

205

Eu acho que você está procurando instance_of?. is_a?e kind_of?retornará true para instâncias de classes derivadas.

class X < String
end

foo = X.new

foo.is_a? String         # true
foo.kind_of? String      # true
foo.instance_of? String  # false
foo.instance_of? X       # true
Candide
fonte
9
Sem saber a intenção da pergunta, eu diria que para a maioria das situações de programação do mundo real, is_a?é realmente o idioma mais apropriado a ser usado (e muitas vezes uma verificação de digitação de pato como Andrew Grimm menciona é ainda melhor). Uma comparação estrita de classe geralmente é um cheiro de código. en.wikipedia.org/wiki/Liskov_substitution_principle
mahemoff 17/01
Rápido aparte: se você usar isso na lógica condicional, precisará usar parênteses; por exemplo, se foo.is_a (String) && ...?
dan
Como esperado, essa abordagem funcionará não apenas com String, mas também com Integere Float. Também funciona para Decimal? (as sublime texto intérprete destaca a sintaxe de forma diferente para Decimalo que me faz suspeitar)
stevec
29

Uma abordagem mais tipográfica seria dizer

foo.respond_to?(:to_str)

to_str indica que a classe de um objeto pode não ser um descendente real da String, mas o próprio objeto é muito parecido com uma string (string?).

Andrew Grimm
fonte
Legal. Neste caso acontece que eu sei que foovai ser tanto true, falseou uma cadeia de baunilha, mas é bom para aprender soluções mais gerais.
Davidchambers #
combine isso com uma chamada to_s depois de verificar se o objeto responde a ela e você recebe uma string!
Seanmakesgames
1
@seanmakesgames Você quis dizer to_str, ou to_s? Os dois são um pouco diferentes.
Andrew Grimm
stackoverflow.com/questions/11182052/… Re: comentário de andrew.
Seanmakesgames
23

Você pode fazer:

foo.instance_of?(String)

E o mais geral:

foo.kind_of?(String)
Federico Builes
fonte
4
O que torna kind_ofmais geral? Eles parecem ser sinónimo: is_a.
Davidchambers
2
@Davidchambers você está certo, 'kind_of?' é sinônimo de 'is_a?'.
213111111
@ Davidchambers: Você está certo, eu quis dizer, em instance_of?vez de is_a?.
Federico Builes
7
foo.instance_of? String

ou

foo.kind_of? String 

se você se importa apenas se for derivado de Stringalgum lugar na sua cadeia de herança

Mateus
fonte
4

Além das outras respostas, Class define o método === para testar se um objeto é uma instância dessa classe.

  • classe o.class de o.
  • o.instance_of? c determina se o.class == c
  • o.is_a? c É uma instância de c ou qualquer uma de suas subclasses?
  • o.kind_of? c sinônimo de * is_a? *
  • c === o para uma classe ou módulo, determine se * o.is_a? c * ( String === "s" retorna verdadeiro)
steenslag
fonte
-1

Eu acho que uma maneira melhor é criar alguns métodos predicados. Isso também salvará seu "Ponto Único de Controle".

class Object
 def is_string?
   false
 end
end

class String
 def is_string?
   true
 end
end

print "test".is_string? #=> true
print 1.is_string?      #=> false

A maneira mais digitação de pato;)

schlegel11
fonte
2
o que há de errado "string".is_a?(String)? Parece que você está reinventando a roda. Há também class, instance_of, kind_of, etc ... Bad idéia para monkey patch da Objectclasse, para não mencionar que é desnecessário.
Mohamad
Eu concordo totalmente com você :) Se seu foco é apenas nos tipos primitivos e você sabe que os requisitos do seu projeto relacionados a tipos primitivos nunca serão alterados (ok, geralmente é o caso;)) você está bem. Mas em um caso em que os requisitos mudam, é melhor ter um "Ponto Único de Controle". Por exemplo, no ambiente do seu projeto, você tem muitas verificações prévias (1000 e superiores). pre_check("test".is_string?) Agora, o requisito do seu projeto mudará e cada String com três caracteres ou mais não será mais definida como String (sei que é incomum;)) Agora você pode alterar seu próprio método facilmente.
precisa