:testes
60
Casa do Código
Capítulo 4. Estruturas de dados
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
livros = Set.new [teste_e_design, web_design_responsivo]
for livro in livros do
p livro
end
p hash[:testes] # => ["Autor: Mauricio Aniche, Isbn: 123454,
Páginas: 247,
Categoria: :testes"]
Repare que duas instâncias
de livro compõem o Set. Isso ocorre porque para
a linguagem Ruby, estes dois objetos são diferentes. Podemos verificar isso invo-
cando e comparando o retorno do método object_id (que retorna um identifica-
dor único de cada objeto na memória) de cada um dos objetos:
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
p teste_e_design.object_id == web_design_responsivo.object_id
# => false
Para garantirmos que dois objetos são iguais por seus valores, devemos compará-
los utilizando o método eql?:
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
p teste_e_design.eql? web_design_responsivo
# => false
O retorna continua sendo false. Em nenhum momento definimos o método
eql?, na verdade ele foi um método herdado da classe Object, e que em sua imple-
mentação original compara os objetos através de seus object_id. No momento
em que decidirmos que o critério que define se um objeto é igual ao outro levará
61
4.7. Indo mais a fundo: O tipo Set
Casa do Código
outro valor em consideração, devemos sobrescrever o método eql? e fazermos a
comparação que julgamos ser a adequada:
# coding: utf-8
class Livro
attr_reader :isbn
def eql?(outro_livro)
@isbn == outro_livro.isbn
end
end
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "123454", 189, 70.9,
:web_design
p teste_e_design.eql? web_design_responsivo # => true
Sobrescrevemos o método eql? e definimos que se um outro livro tiver o
mesmo isbn que o livro que estamos comparando, eles são iguais. É importante
salientar que não estamos dizendo que eles são os mesmos objetos na memória.
==, equal? ou eql?
O método == retorna true apenas se os dois objetos envolvidos
na comparação forem a mesma instância, este é seu comportamento pa-
drão. Ele pode ser sobrescrito afim de efetuar a comparação de outras
maneiras.
O método equal? é similar ao ==, ele retorna true apenas se os
dois objetos envolvidos na comparação forem a mesma instância. As bi-
bliotecas existentes na linguagem, quando tem a necessidade de compa-
rar se dois objetos são a mesma instância usam o método equal?, por
esse motivo, não devemos sobrescrever este método, pois o efeito pode
ser bastante prejudicial.
Por fim o método eql? por padrão compara as instâncias dos objetos
também. Porém, este método deve ser sobrescrito quando desejamos
avaliar se dois objetos são iguais por seus valores, como fizemos com a
classe Livro.
62
Casa do Código
Capítulo 4. Estruturas de dados
Porém sobrescrever apenas o método eql? não é suficiente para evitarmos du-
plicidade de objetos do tipo Livro dentro de uma coleção do tipo Set. Ainda não
é suficiente, porque o Set internamente utiliza um Hash para guardar os valores e
uma coleção do tipo Hash é um conjunto de buckets (container) com um rótulo e
dentro uma determinada quantidade de objetos.
O rótulo destes buckets são na verdade o retorno do método hash de um de-
terminado objeto. No caso dos objetos do tipo Livro, o retorno do método hash
quase sempre será diferente. Isso porque todo objeto possui uma implementação
default do método hash que faz um cálculo com propriedades especificas do objeto
em questão.
Se quisermos evitar duplicidade dos objetos do tipo Livro dentro de um Set,
devemos fazer com que instâncias que possuem o mesmo isbn (que é nosso critério
de igualdade) tenham o mesmo retorno quando invocarmos o método hash:
# coding: utf-8
class Livro
def hash
@isbn.hash
end
end
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "123454", 189, 70.9,
:web_design
p teste_e_design.hash == web_design_responsivo.hash # => true
O que fizemos foi retornar o valor do método hash do atributo String isbn.
É
sempre importante tomarmos cuidados quando redefinimos o método hash prin-
cipalmente quando guardarmos vários objetos deste tipo dentro de Hash e Set. Se
o valor do hash for pouco variável, podemos ter várias colisões de hash, o que pode
ocasionar um busca muito mais lenta por esses elementos.
Agora podemos testar que caso instancias diferentes da classe Livro tenham o
mesmo isbn, eles não serão mais duplicadas dentro de um Set:
require 'set'
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
63
4.8. E agora?
Casa do Código
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "123454", 189, 70.9,