Track
/
Elm
Elm
/
Esercizi
/
Il forziere del tesoro sicuro
Il forziere del tesoro sicuro

Il forziere del tesoro sicuro

Esercizio di apprendimento

Introduzione

Tipi opachi

Introduzione

I tipi opachi sono una tecnica di incapsulamento in Elm. Alcuni la chiamano anche occultamento delle informazioni, o occultamento dei dettagli di implementazione. Vengono anche usati comunemente per imporre la validazione, usando il pattern Analizza, non validare. Per esempio, potresti avere un tipo opaco EmailAddress, che può contenere solo indirizzi email validi (al contrario di una String, che può contenere qualsiasi cosa).

Creare un tipo opaco

I tipi personalizzati hanno una o più varianti, e il compilatore genera automaticamente una funzione per creare ogni variante, usando il nome della variante. Questi sono l'unico modo in cui si possono creare i tipi personalizzati. Il compilatore consente anche la destrutturazione di queste varianti.

type Maybe a
    = Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
    | Just a  --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'

Per impostazione predefinita, tutto questo è interno al file / modulo, e usiamo la parola chiave exposing per scegliere cosa esportare. Per creare un tipo opaco, ti basta scegliere di non esportare le varianti.

Quando lo fai, quasi sempre devi fornire un altro modo per creare e ottenere le varianti, esponendo funzioni personalizzate. Queste funzioni personalizzate ti permettono di applicare una certa logica quando crei e ottieni le varianti. Questo nasconde i dettagli di implementazione interni del modulo e significa che puoi cambiare i dettagli di implementazione quanto vuoi, purché le funzioni esposte rimangano le stesse.

Analizza, non validare

Probabilmente l'uso più comune dei tipi opachi è imporre la validazione, usando il pattern Analizza, non validare. In questo pattern, esponi una funzione che riceve un input con meno struttura / sicurezza di tipo di quanta ne vorresti, come una String, e poi lo analizzi per ottenere un tipo più strutturato, come EmailAddress, restituendo il tipo oppure un errore (di solito Maybe o Result).

Per esempio, nel codice qui sotto, per i moduli esterni è possibile creare un tipo EmailAddress solo usando la funzione parseEmailAddress, quindi quando lavori con il tipo EmailAddress hai la certezza che sia valido.

module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )

-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress = 
  EmailAddress String

-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =   
  if isValidEmailAddress candidateEmailAddress then
    Just (EmailAddress candidateEmailAddress)
  else
    Nothing

-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress  emailAdress ) =
  emailAdress

isValidEmailAddress: String -> bool
-- ... 

Istruzioni

In questo esercizio scriverai un SecureTreasureChest generico (e magico!), per custodire un tesoro. Gli studenti più attenti avranno notato che il precedente TreasureChest non era poi così sicuro! Se usavi la funzione getTreasure, dovevi fornire la password, ma potevi comunque destrutturare semplicemente il tipo TreasureChest per ottenere il tesoro, senza dover conoscere la password. Peggio ancora, potevi recuperare la password nello stesso modo! Risolviamo questo problema usando un tipo opaco.

1. Definisci il tipo opaco Password, usando il pattern «Parse, don't validate»

Definisci un tipo personalizzato Password con una sola variante.

La variante deve avere un valore String associato, per la password.

Devi esporre il tipo Password, ma non la variante. Questo rende Password un tipo opaco e significa che non puoi più usare la destrutturazione per ottenere la password. Non è possibile verificare se un tipo è opaco oppure no; nel codice di produzione useresti elm-review (uno strumento di analisi statica) per imporlo.

Definisci ed esponi una funzione createPassword, con un'annotazione di tipo, che prende una String e restituisce un Maybe Password.

Owasp raccomanda che le password siano lunghe almeno 8 caratteri, quindi usiamo il pattern Parse, don't validate per imporre questo invariante.

Se la password è più corta di 8 caratteri, createPassword deve restituire Nothing, altrimenti deve restituire Just Password.

2. Esponi SecureTreasureChest, ma non la sua variante

Devi esporre il tipo SecureTreasureChest, ma non la variante. Questo rende SecureTreasureChest un tipo opaco e significa che non puoi più usare la destrutturazione per ottenere la password o il tesoro.

3. Definisci la funzione createTreasure

Questa funzione deve prendere due parametri e avere un'annotazione di tipo.

  • un tipo generico (per il tesoro)
  • una Password (per la password)

La funzione deve restituire un SecureTreasureChest.

Esponi questa funzione, in modo che altri moduli possano creare istanze di SecureTreasureChest.

4. Definisci la funzione getTreasure

Questa funzione deve prendere due parametri e avere un'annotazione di tipo.

  • una String (per la password)
  • un tipo personalizzato generico SecureTreasureChest

Questa funzione deve confrontare il tentativo di password fornito con la Password contenuta nel SecureTreasureChest.

La funzione deve restituire un Maybe.

Se le password corrispondono, restituisci Just con il valore generico contenuto nel SecureTreasureChest (il tesoro!).

Se le password non corrispondono, restituisci Nothing.

Esponi questa funzione, in modo che altri moduli possano ottenere il tesoro da un SecureTreasureChest, a patto che forniscano la password corretta.

Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elm Exercism

Vuoi iniziare Il forziere del tesoro sicuro?

Iscriviti a Exercism per imparare e padroneggiare Elm con 28 concetti110 esercizi e il mentoring di persone reali, tutto gratis.