blocchi in ruby

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


I blocchi sono forse il tratto più distintivo di ruby, ed una delle cose che lo rendono più potente e piacevole da usare.

Un blocco è una funzione anonima, spesso detta anche come Forma Lambda, ed in ruby è un’istanza della classe Proc.

Ma cos’è in realtà un blocco? si tratta, appunto, di uno spezzone di codice che può essere creato e passato da una parte all’altra.

Un uso elementare è quello che si può fare con gli iteratori:

 [1,2,3].each do |i|
  p i
 end
 1
 2
 3

In questo esempio, il codice nel blocco viene richiamato dal metodo each() per ogni elemento nell’array, ed il risultato è che il tutto funziona come un ciclo for (ed in effetti for..end in ruby funziona usando internamente each()).

Ma in realtà un blocco, essendo concettualmente molto semplice può essere usato in un numero di situazioni enormemente più grande. Ad esempio, in qualsiasi posto in cui ci sia bisogno di prendere una decisione.

Pensate a questo problema: stabilire il massimo tra gli elementi di un Array. Potete usare il metodo Enumerable#max in questo modo:

 [persona1,persona2,persona3].max #=> persona2

e le persone saranno ordinate secondo un qualche meccanismo di default o uno definito da voi (vedasi Comparable).

Ma se voleste ad esempio cambiare queste regole per una sola volta, senza voler cambiare l’intera classe, potreste fare:

 [persona1,persona2,persona3].max { |a,b|
   a.name <=> b.name
 }

I blocchi permettono di aggiungere logica solo dove ce ne sia bisogno.

Vediamo un altro esempio. Pensate di dover effettuare una trasformazione su una collezione di oggetti. In alcuni linguaggi fareste una cosa come questa:

 nuova= Collezione.new
 for elem in vecchia
  risultato=trasforma(elem)
  ...
  ...
  nuova.add(risultato)
 end

ma in ruby sappiamno come iterare su una collezione in modo generico, e sappiamo anche come passare un pezzetto di logica all’iteratore quindi possiamo scrivere:

 nuova= vecchia.map{|elem| trasforma(elem)}

Gli usi dei blocchi sono infiniti. Ad esempio, + possibile aggiungere logica ad un’operazione con le Regexp:

>> '1, 2 e 3'.gsub /[1-3]/ do |match|
?>   case match
>>    when '1'
>>     'uno'
>>    when '2'
>>    'due'
>>   when '3'
>>    'tre'
>>   end
>> end
=> "uno, due e tre" 

con una sola iterazione abbiamo fatto tutte e tre le trasformazioni, usando un’espressione regolare banale.

Un altro uso è quello relativo ad oggetti che hanno bisogno di essere gestiti in modo particolare, come i File o i Socket. Essi, infatti, hanno bisogno di essere chiusi una volta aperti per evitare di sprecare risorse.

Ma invece di fare una cosa come questa:

 begin 
  file= open('testo.txt')
  ..lavora con file...
 rescue SomeException
  ..
 ensure
  file.close
 end

possiamo passare un blocco, e lasciare che il metodo open si preoccupi di gestire le eccezioni al posto nostro:

 open('file.txt') do |f|
  ..lavora con f..
 end

Decisamente meglio!

Updated on December 02, 2005 18:44 by Gabriele Renzi (151.38.222.9)