So che vi sentite insoddisfatti… anch’io ho provato la stessa cosa. Ma non temete, vi accompagno io.

Storia personale che potreste anche non leggere

Durante la scrittura di un post sul Functional Programming in Swift mi sono reso contro che i lettori avrebbero dovuto disporre di una solida base di conoscenza rispetto alla programmazione generica (Generics) e ai protocolli (Protocols) per sopravvivere all’articolo.

Per scoprire risorse e materiale da suggerire ai miei lettori, ho cliccato praticamente tutti i link delle prime cinque pagine fornite dalla ricerca su Google. Ecco perché ho deciso infine di dover provvedere io stesso alla stesura di un articolo sulla programmazione generica in Swift. Posso immaginare, a giudicare dalle risorse disponibili, la fatica provata nel corso dello studio di questa specifica parte di linguaggio.

Prerequisiti

Per poter sfruttare al meglio il presente articolo, assicuratevi di avere familiarità con: protocolli, OOP, funzioni, estensioni. Se non disponete di tale dimestichezza, vi consiglio vivamente di ripassare tali concetti prima di intraprendere questo viaggio.

Il passato

Prima di partire, diamo un’occhiata al nostro passato, al modo in cui abbiamo imparato e subito il lavaggio del cervello. Immaginate di dover fare il print di ogni elemento all’interno di un array; probabilmente fareste in questo modo:

Ok, printiamo.

Il codice qui sopra è atroce, fa schifo. Ogni funzione prende un type specifico di un array e ripete, ripete, ripete.

Non potrebbe esserci una singola funzione che consente di inserire qualsiasi parametro il cui type è indefinito? Domanda retorica, certo che esiste. Se così non fosse, probabilmente non sarei qui a scrivere questo articolo.

Bad Ass Generics

Bene, prima di tutto, c’p una sola regola per rendere generica una funzione. Tutto quel che serve è inserire <anything> vicino al nome della funzione. Vediamo.

Fate attenzione per un secondo. Per chiarire: quando si inserisce un value, Swift determina automaticamente il tipo di value basandosi sull’input. Ad esempio, se si chiama

Il valore ora è String e può essere usato all’interno della funzione. Se si chiama…

Il valore ora è Bool. Spero che il concetto sia chiaro. Ovviamente non dovete chiamarlo anything come ho fatto io nell’esempio. Chiamatelo come volete.

Dalla teoria alla pratica

Bene, ora che sappiamo in cosa consistono i Generics, possiamo cominciare.

Quindi dobbiamo fare in questo modo…

Una funzione vale per tutto. Ecco perché chiamo i Generics bad ass. Se non avete familiarità con questo termine potete consultare Urban Dictionary.

Ora controlliamo la definizione ufficiale fornita da Apple:

Il codice generico ti consente di scrivere funzioni e type flessibili e riutilizzabili, soggetti ai requisiti che lo sviluppatore definisce. Puoi scrivere codice che eviti duplicazione ed esprima il suo scopo in maniera chiara. — Swift Programming Language

La libreria Swift che usate per interagire con array e dizionari contiene molto codice generico.

Le Struct incontrano i Generics

I generics non si applicano solo alle funzioni, ma anche alle class e alle struct. Immaginiamo di avere una struct chiamata Family, la cui proprietà array è members. Si può aggiungere o rimuovere un elemento a o dall’array.

La keyword mutating è necessaria se volete modificare la proprietà. Dal momento che aggiungete e rimuovete elementi a members si deve aggiungere mutating a quelle funzioni.

Altro problema

Se volete creare una famiglia il cui nome si trovi in Int, sarà necessario creare un’intera struct. Ecco a voi, dunque, la struct generica che permette di inserire qualsiasi cosa, in ogni caso. Analogamente alla funzione che abbiamo già utilizzato, basta inserire <anything> vicino al nome.

Ora creiamo un oggetto il cui type può essere o 1. Explicitly stated o 2. Inferred.

1. Explicitly Stated

Creiamo un oggetto usando la struct SavageFamily. Proprio come una funzione, bisogna aggiungere < > al nome. Ad esempio:

Abbiamo dichiarato che l’istanza myFam potrà interagire solo con String e Int. Il beneficio consiste nella mancanza di necessità di creare due struct separata al fine di produrre il risultato precedente.

2. Inferred

Quando si crea un object non vi è bisogno di specificare il suo type. Swift è abbastanza intelligente da capirlo da solo. Per esempio:

In modo analogo si applica alla struct generica. Quindi potete creare un oggetto generico come…

Apparentemente, friendFam può interagire solo con String e trueFam solo con Bool. Non c’è bisogno di inserire quei < > nella creazione di un oggetto con una struct generica.

Generic Extension

Si può aggiungere inoltre una estensione alla generi struct o class. Se non avete familiarità con le extention, date un’occhiata al mio video tutorial su YouTube.

Aggiungiamo una proprietà che prenda il primo elemento.

Ora si può usare liberamente la proprietà all’interno di un object.

Bene, avete fatto strada.

Type Constraint

Se ricordate la creazione della funzione generica…

…potevate aggiungere qualsiasi cosa, un oggetto e via di seguito. In ogni caso, se volessimo limitarlo ad un paio di type? Se limitassimo una funzione a determinate classi?

Appena dopo T possiamo specificare i type che vogliamo utilizzare. Creiamo una classe chiamata LOL.

Ok, ora creiamo una funzione generica che può prendere solo LOL.

Giusto per precisare, se mettiamo una subclass in questo modo,

Possiamo sempre aggiungere alla funzione, che può accettare valori il cui type è LOL.

Perché ChildLol() è stato automaticamente trasformato in Lol. Se non siete sicure sull’argomento type casting, consultate il mio tutorial.

E questo è quanto.

Risorse

Resource Code
The Resource Page for iOS Developers

***

Bob Lee è l’autore di questo articolo.

Articolo originale:Intro to Generics in Swift with Bob

 

NO COMMENTS

LEAVE A REPLY