Estou tentando entender a diferença entre esses quatro métodos. Eu sei por padrão que ==
chama o método equal?
que retorna true quando ambos os operandos se referem exatamente ao mesmo objeto.
===
por padrão também pede ==
que as chamadas equal?
... bem, por isso, se todos esses três métodos não são substituídos, então eu acho
===
, ==
e equal?
fazer exatamente a mesma coisa?
Agora vem eql?
. O que isso faz (por padrão)? Faz uma chamada para o hash / id do operando?
Por que Ruby tem tantos sinais de igualdade? Eles deveriam diferir na semântica?
ruby
comparison
operators
equality
denniss
fonte
fonte
"a" == "a"
,"a" === "a"
e"a".eql? "a"
. Mas isso é falso:"a".equal? "a"
(Minas é ruby 1.9.2-p180)a = Object.new; b = Object.new
, em seguida, todos==
,===
,.equal?
,.eql?
retornarátrue
para aa
vsa
e false paraa
vsb
.Respostas:
Vou citar fortemente a documentação do objeto aqui, porque acho que ela tem ótimas explicações. Convido você a ler e também a documentação desses métodos, pois eles são substituídos em outras classes, como String .
Nota lateral: se você quiser experimentar por conta própria em objetos diferentes, use algo como isto:
==
- "igualdade" genéricaEssa é a comparação mais comum e, portanto, o local mais fundamental onde você (como autor de uma classe) decide se dois objetos são "iguais" ou não.
===
- igualdade de casosIsso é incrivelmente útil. Exemplos de coisas que têm
===
implementações interessantes :Então você pode fazer coisas como:
Veja minha resposta aqui para um exemplo puro de como
case
+Regex
pode tornar o código muito mais limpo. E, é claro, fornecendo sua própria===
implementação, você pode obtercase
semânticas personalizadas .eql?
-Hash
igualdadePortanto, você pode substituir isso para seus próprios usos ou pode substituir
==
e usaralias :eql? :==
para que os dois métodos se comportem da mesma maneira.equal?
- comparação de identidadeEsta é efetivamente uma comparação de ponteiro.
fonte
Numeric
lida com uma maneira mais rigorosa do que==
. É realmente com o autor da classe.===
é raramente usado fora dascase
instruções.===
no significado de "correspondências" (aproximadamente). Como em "o regexp corresponde à string" ou "o intervalo corresponde (inclui) ao número".Adoro a resposta do jtbandes, mas como é bastante longo, adicionarei minha própria resposta compacta:
==
,===
,eql?
,equal?
São 4 comparadores, isto é. 4 maneiras de comparar 2 objetos, em Ruby.
Como, no Ruby, todos os comparadores (e a maioria dos operadores) são na verdade chamadas de método, você pode alterar, substituir e definir a semântica desses métodos de comparação. No entanto, é importante entender quando a linguagem interna do Ruby constrói o uso de qual comparador:
==
(comparação de valores) ORuby usa: == em qualquer lugar para comparar os valores de 2 objetos, por exemplo. Valores de hash:
===
(comparação de casos)Ruby usa: === no caso / quando constrói. Os seguintes trechos de código são logicamente idênticos:
eql?
(Comparação de teclas de hash)Ruby usa: eql? (em combinação com o método hash) para comparar as teclas hash. Na maioria das classes: eql? é idêntico a: ==.
Conhecimento sobre: eql? é importante apenas quando você deseja criar suas próprias classes especiais:
Nota: O conjunto de classe Ruby comumente usado também depende da comparação de chaves Hash.
equal?
(comparação de identidade de objeto)Ruby usa: equal? para verificar se dois objetos são idênticos. Este método (da classe BasicObject) não deve ser substituído.
fonte
eql?
é muito enganador.eql?
é uma comparação de igualdade consistente com a maneira como o hash é calculado, ou seja,a.eql?(b)
garante issoa.hash == b.hash
. Ele simplesmente não compara os códigos de hash.bar === foo
e nãofoo === bar
? Espero que o último esteja correto e seja importante, pois o compilador chama o lado esquerdo: === ''bar === foo
: Ruby usa o valor do caso no lado esquerdo e a variável do caso no lado direito. Isso pode ter a ver com evitar NPEs (Exceções de ponteiro nulo).Operadores de igualdade: == e! =
O operador ==, também conhecido como igualdade ou duplo igual, retornará true se os dois objetos forem iguais e false se não forem.
O operador! =, Também conhecido como desigualdade, é o oposto de ==. Retornará true se os dois objetos não forem iguais e false se forem iguais.
Observe que duas matrizes com os mesmos elementos em uma ordem diferente não são iguais, versões em maiúsculas e minúsculas da mesma letra não são iguais e assim por diante.
Ao comparar números de tipos diferentes (por exemplo, número inteiro e número flutuante), se o valor numérico for o mesmo, == retornará verdadeiro.
igual?
Diferente do operador == que testa se os dois operandos são iguais, o método equal verifica se os dois operandos se referem ao mesmo objeto. Esta é a forma mais estrita de igualdade em Ruby.
Exemplo: a = "zen" b = "zen"
No exemplo acima, temos duas cadeias com o mesmo valor. No entanto, eles são dois objetos distintos, com diferentes IDs de objeto. Portanto, o igual? O método retornará false.
Vamos tentar novamente, só que desta vez b será uma referência a. Observe que o ID do objeto é o mesmo para as duas variáveis, pois elas apontam para o mesmo objeto.
eql?
Na classe Hash, o eql? método é usado para testar chaves para igualdade. Alguns antecedentes são necessários para explicar isso. No contexto geral da computação, uma função hash pega uma string (ou um arquivo) de qualquer tamanho e gera uma string ou um número inteiro de tamanho fixo chamado hashcode, geralmente chamado apenas de hash. Alguns tipos de código de hash comumente usados são MD5, SHA-1 e CRC. Eles são usados em algoritmos de criptografia, indexação de banco de dados, verificação de integridade de arquivos etc. Algumas linguagens de programação, como Ruby, fornecem um tipo de coleção chamado tabela de hash. As tabelas de hash são coleções semelhantes a dicionários que armazenam dados em pares, consistindo em chaves exclusivas e seus valores correspondentes. Sob o capô, essas chaves são armazenadas como códigos de hash. As tabelas de hash são comumente referidas como apenas hashes. Observe como a palavra hashcan se refere a um hashcode ou a uma tabela de hash.
O Ruby fornece um método interno chamado hash para gerar códigos de hash. No exemplo abaixo, ele pega uma string e retorna um código hash. Observe como seqüências de caracteres com o mesmo valor sempre têm o mesmo código de hash, mesmo que sejam objetos distintos (com IDs de objeto diferentes).
O método hash é implementado no módulo Kernel, incluído na classe Object, que é a raiz padrão de todos os objetos Ruby. Algumas classes, como Symbol e Inteiro, usam a implementação padrão, outras como String e Hash fornecem suas próprias implementações.
No Ruby, quando armazenamos algo em um hash (coleção), o objeto fornecido como uma chave (por exemplo, string ou símbolo) é convertido e armazenado como um código de hash. Mais tarde, ao recuperar um elemento do hash (coleção), fornecemos um objeto como uma chave, que é convertida em um código de hash e comparada às chaves existentes. Se houver uma correspondência, o valor do item correspondente será retornado. A comparação é feita usando o eql? método sob o capô.
Na maioria dos casos, o eql? O método se comporta de maneira semelhante ao método ==. No entanto, existem algumas exceções. Por exemplo, eql? não realiza conversão implícita de tipo ao comparar um número inteiro a um número flutuante.
Operador de igualdade de caso: ===
Muitas das classes internas do Ruby, como String, Range e Regexp, fornecem suas próprias implementações do operador ===, também conhecido como igualdade entre maiúsculas e minúsculas, iguais a triplos ou três iguais. Como é implementado de maneira diferente em cada classe, ele se comportará de maneira diferente, dependendo do tipo de objeto em que foi chamado. Geralmente, ele retornará true se o objeto à direita "pertencer a" ou "for um membro" do objeto à esquerda. Por exemplo, ele pode ser usado para testar se um objeto é uma instância de uma classe (ou uma de suas subclasses).
O mesmo resultado pode ser alcançado com outros métodos que provavelmente são mais adequados para o trabalho. Geralmente, é melhor escrever um código que seja fácil de ler, sendo o mais explícito possível, sem sacrificar a eficiência e a concisão.
Observe que o último exemplo retornou false porque números inteiros como 2 são instâncias da classe Fixnum, que é uma subclasse da classe Integer. O ===, is_a? e instance_of? Os métodos retornam true se o objeto for uma instância da classe especificada ou de qualquer subclasse. O método instance_of é mais rígido e retornará true se o objeto for uma instância dessa classe exata, não uma subclasse.
O is_a? e tipo_de? métodos são implementados no módulo Kernel, que é misturado pela classe Object. Ambos são aliases para o mesmo método. Vamos verificar:
Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # Saída: => true
Implementação de intervalo de ===
Quando o operador === é chamado em um objeto de intervalo, ele retorna true se o valor à direita estiver dentro do intervalo à esquerda.
Lembre-se de que o operador === chama o método === do objeto à esquerda. Então (1..4) === 3 é equivalente a (1..4). === 3. Em outras palavras, a classe do operando esquerdo definirá qual implementação do método === será chamado, para que as posições do operando não sejam intercambiáveis.
Implementação Regexp de ===
Retorna true se a sequência à direita corresponder à expressão regular à esquerda. / zen / === "pratique zazen hoje" # Saída: => true # é o mesmo que "pratique zazen hoje" = ~ / zen /
Uso implícito do operador === nas instruções case / when
Este operador também é usado sob o capô nas instruções case / when. Esse é o seu uso mais comum.
No exemplo acima, se Ruby tivesse usado implicitamente o operador duplo igual (==), o intervalo 10..20 não seria considerado igual a um número inteiro como 15. Eles correspondem porque o operador triplo igual (===) é implicitamente usado em todas as declarações case / when. O código no exemplo acima é equivalente a:
Operadores de correspondência de padrões: = ~ e! ~
Os operadores = ~ (equal-til) e! ~ (Bang-til) são usados para comparar cadeias e símbolos com padrões regex.
A implementação do método = ~ nas classes String e Symbol espera uma expressão regular (uma instância da classe Regexp) como argumento.
A implementação na classe Regexp espera uma sequência ou um símbolo como argumento.
Em todas as implementações, quando a sequência ou o símbolo corresponde ao padrão Regexp, ele retorna um número inteiro que é a posição (índice) da correspondência. Se não houver correspondência, ele retornará nulo. Lembre-se de que, em Ruby, qualquer valor inteiro é "verdade" e nulo é "falso"; portanto, o operador = ~ pode ser usado nas instruções if e nos operadores ternários.
Os operadores de correspondência de padrões também são úteis para escrever instruções if mais curtas. Exemplo:
O operador! ~ É o oposto de = ~, retorna true quando não há correspondência e false se houver uma correspondência.
Mais informações estão disponíveis nesta postagem do blog .
fonte
:zen === "zen"
retorna falso #Ruby expõe vários métodos diferentes para lidar com a igualdade:
Continue lendo, clicando no link abaixo, isso me deu um entendimento claro e resumido.
Espero que ajude os outros.
fonte
=== # --- igualdade de casos
== # --- igualdade genérica
ambos funcionam da mesma forma, mas "===" até fazem declarações de caso
aqui a diferença
fonte
a==b
entãoa===b
. Masa===b
é muito mais poderoso.===
não é simétrico ea===b
significa uma coisa muito diferenteb===a
, e muito menosa==b
.Eu gostaria de expandir o
===
operador.===
não é um operador de igualdade!Não.
Vamos esclarecer esse ponto.
Você pode estar familiarizado
===
como um operador de igualdade em Javascript e PHP, mas isso não é um operador de igualdade em Ruby e tem semântica fundamentalmente diferente.Então o que
===
faz?===
é o operador de correspondência de padrões!===
corresponde a expressões regulares===
verifica a participação no intervalo===
verifica sendo instância de uma classe===
chama expressões lambda===
às vezes verifica a igualdade, mas principalmente nãoEntão, como essa loucura faz sentido?
Enumerable#grep
usa===
internamentecase when
declarações usam===
internamenterescue
usa===
internamenteÉ por isso que você pode usar expressões regulares e classes e intervalos e até expressões lambda em uma
case when
instrução.Alguns exemplos
Todos esses exemplos também funcionam com
pattern === value
, assim como com ogrep
métodofonte
Eu escrevi um teste simples para todas as opções acima.
fonte