Souza Lucas - Ruby: Aprenda a programar na linguagem mais divertida стр 20.

Шрифт
Фон

: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,

Ваша оценка очень важна

0
Шрифт
Фон

Помогите Вашим друзьям узнать о библиотеке