Comparable

Vedi tutte le pagine e le modifiche recenti o scarica i sorgenti nella pagina


Su molti oggetti in ruby è possibile usare operatori di comparazione, ad esempio:

>> 5 <= 5.0
=> true
>> 4 > 4
=> false
>> "a" < "b" 
=> true

non è certo una cosa strana, è possibile farlo in quasi tutti i linguaggi.

In ruby però gli operatori sono dei metodi come tutti gli altri, ed è quindi possibile definirne di propri nelle proprie classi, ad esempio così:

>> class Person
>>  attr_reader :name
>>  def initialize(name)
?>   @name= name
>>  end
>>  def == other
?>   name == other.name
>>  end
>> end
=> nil

>> p1=Person.new "joe" 
=> #<Person:0xb7d2abac @name="joe">
>> p2=Person.new "joe" 
=> #<Person:0xb7d26854 @name="joe">
>> p1 == p2
=> true

ma facendo così abbiamo definito un solo metodo:

>> p1 < p2
NoMethodError: undefined method `<' for #<Person:0xb7d2abac @name="joe">
        from (irb):57
        from (null):0

e sarebbe una bella fatica dover implementare anche tutti gli altri metodi di comparazione.

Per fortuna esiste un Mixin chiamato Comparable che si preoccupa di definirli per noi. Tutto quello che dobbiamo fare è definire un operatore chiamato <=> (spesso chiamato spaceship operator, per la somiglianza con un disco volante).

Ovviamente questo operatore dovrà racchiudere in se l’idea di “minore o uguale o maggiore”, e quindi restituirà In pratica:
>> class Person
>>  include Comparable # includiamo il Mixin
>>  attr_reader :name
>>  def initialize(name)
?>   @name= name
>>  end

>>  # definiamo lo spaceship operator
>>  def <=> other
?>   name <=> other.name
>>  end
>> end
=> nil

notate come si possa facilmente riutilizzare uno starship operator esistente per implementarne di proprio. Verifichiamo che tutto funzioni:

>> p1=Person.new "joe" 
=> #<Person:0xb7cfac40 @name="joe">
>> p1=Person.new "john" 
=> #<Person:0xb7cf4084 @name="john">
>> p1=Person.new "joe" 
=> #<Person:0xb7ced450 @name="joe">
>> p2=Person.new "john" 
=> #<Person:0xb7ce8d4c @name="john">
>> p3=Person.new "james" 
=> #<Person:0xb7ce3860 @name="james">
>> p1 != p3
=> true
>> p1 < p3
=> false
>> p1 > p3
=> true
>> p2 >= p3
=> true

perfetto. Il modulo definisce anche un utile metodo beetween?(min,max) per stabilire se un oggetto è in un intervallo.

Infine, se usate degli oggetti Comparable in un Array o in un altro oggetto che includa Enumerable, potrete approfittare dei metodi min(), max() e sort, che ovviamente usano <=> per poter funzionare in modo corretto.

Leggi la documentazione di Comparable

Updated on February 17, 2009 17:17 by Ruby Fan (89.118.137.26)