Track
/
Crystal
Crystal
/
Esercizi
/
Calcolatrice da cucina
Calcolatrice da cucina

Calcolatrice da cucina

Esercizio di apprendimento

Introduzione

Una tupla è una lista ordinata e finita di elementi, immutabile. Le tuple richiedono che tutte le posizioni abbiano un tipo fisso. Questo, a sua volta, significa che il compilatore sa quale tipo si trova in ogni posizione. I tipi usati in una tupla possono essere diversi in ogni posizione, ma devono essere noti in fase di compilazione.

Creare una tupla

A seconda che i tipi dei valori della tupla possano essere interpretati in fase di compilazione, la tupla può essere creata in modi diversi. Se i valori sono noti in fase di compilazione, la tupla può essere creata usando la sintassi letterale delle tuple, altrimenti occorre dichiararli esplicitamente. È anche importante che i tipi dei valori corrispondano ai tipi specificati nella tupla e che il numero di valori corrisponda al numero di tipi specificati. Ecco un esempio di definizione tramite la sintassi letterale delle tuple:

tuple = {1, "foo", 'c'} # Tuple(Int32, String, Char)

C'è anche la possibilità di creare una tupla usando la classe Tuple.

tuple = Tuple(Int32, String, Char).new(1, "foo", 'c')

In alternativa, puoi specificare esplicitamente il tipo della variabile a cui è assegnata la tupla.

tuple : Tuple(Int32, String, Char) = {1, "foo", 'c'}

Specificare esplicitamente il tipo della tupla può essere utile, dato che permette di definire che una posizione debba contenere un tipo unione. Questo significa che una posizione può contenere più tipi.

tuple : Tuple(Int32 | String, String, Char) = {1, "foo", 'c'}

Conversione

Creare una tupla da un array

Puoi creare una tupla da un array usando il metodo from della classe Tuple. Questo richiede che il tipo della tupla sia specificato.

array = [1, "foo", 'c']
tuple = Tuple(Int32, String, Char).from(array)

Conversione in array

Puoi convertire una tupla in un array usando il metodo to_a. Il tipo degli elementi dell'array risultante è l'unione dei tipi di ciascun campo della tupla.

tuple = {1, "foo", 'c'}
array = tuple.to_a
array # => [1, "foo", 'c']

Accedere agli elementi

Come gli array, le tuple hanno indici che partono da zero, quindi il primo elemento si trova all'indice 0. A differenza degli array, però, il tipo di ogni elemento è fisso e noto in fase di compilazione; quindi, quando si accede a una tupla tramite indice, il tipo dell'elemento è specifico per quella posizione. Per accedere a un elemento di una tupla, puoi usare l'operatore [].

array = [1, "foo", 'c']
array[0]         # => 1
typeof(array[0]) # => Int32 | String | Char

tuple = {1, "foo", 'c'}
tuple[0]         # => 1
typeof(tuple[0]) # => Int32

Un'altra differenza rispetto all'accesso agli elementi di un array è che, se l'indice è specificato, il compilatore controlla che rientri nei limiti della tupla. Questo significa che otterrai un errore in fase di compilazione invece di un errore a runtime.

tuple = {1, "foo", 'c'}
tuple[3]
# => Error: index out of bounds for Tuple(Int32, String, Char) (3 not in -3..2)

Se però l'indice è memorizzato in una variabile, il compilatore non potrà verificare in fase di compilazione se rientra nei limiti della tupla e segnalerà invece un errore a runtime.

Sottotupla

Puoi ottenere una sottotupla di una tupla usando l'operatore [] con un intervallo. Quello che viene restituito è una nuova tupla con gli elementi dell'intervallo specificato. L'intervallo deve essere fornito in fase di compilazione, altrimenti il compilatore non potrà conoscere i tipi degli elementi della sottotupla. Questo significa che l'intervallo deve essere un letterale di intervallo e non essere assegnato a una variabile.

tuple = {1, "foo", 'c'}
subtuple = tuple[0..1] # Tuple(Int32, String)

i = 0..1
tuple[i]
# Error: Tuple#[](Range) can only be called with range literals known at compile-time

Quando usare una tupla

Le tuple sono utili quando vuoi raggruppare un numero fisso di valori i cui tipi sono noti in fase di compilazione. Questo perché le tuple richiedono meno memoria e sono più veloci degli array, grazie alla loro immutabilità. Un altro caso d'uso è restituire più valori da un metodo. È particolarmente utile se i valori hanno tipi diversi, dato che ogni posizione della tupla può avere un tipo diverso.

Non conviene usare le tuple quando serve una struttura dati che possa crescere o ridursi di dimensione o che debba essere modificata spesso.

I simboli sono identificatori con un nome che possono essere usati per riferirsi a un valore. I simboli si creano tramite un letterale simbolo, anteponendo un nome al carattere :, ad esempio :foo. Possono anche essere scritti tra virgolette, ad esempio :"foo", il che permette, per esempio, di usare spazi nel nome.

:foo           # => :foo
:"foo boo"     # => :"foo boo"
:foo == :"foo" # => true

I simboli sono usati in molti punti del linguaggio, ad esempio come chiavi nei namedtuple e per rappresentare i nomi di metodi e variabili.

I simboli in Crystal

I simboli in Crystal sono piuttosto diversi da quelli di Ruby. In Crystal un simbolo è un tipo di costante e quindi viene assegnato in fase di compilazione. Questo significa che i simboli non possono essere creati dinamicamente, cosa possibile invece in Ruby.

In Crystal i simboli sono rappresentati come Int32, il che li rende molto efficienti.

Conversione

I simboli possono essere convertiti in stringhe, ma non viceversa. Questo perché i simboli vengono creati in fase di compilazione e le stringhe a runtime.

:foo.to_s # => "foo"

Istruzioni

Mentre ti prepari a cuocere dei biscotti per i tuoi amici, hai scoperto di dover convertire alcune delle misure usate nella ricetta. Conoscendo solo il sistema metrico, devi trovare un modo per convertire in millilitri (mL) le comuni misure americane usate per i dolci, per semplificarti il lavoro.

Usa questa tabella di conversione per la tua soluzione:

Unità da convertire volume in millilitri (mL)
mL 1 1
US cup 1 240
US fluid ounce 1 30
US teaspoon 1 5
US tablespoon 1 15

Essendo un programmatore di talento in formazione, decidi di usare i millilitri come unità di transizione per facilitare la conversione da qualsiasi unità elencata a qualsiasi altra (anche a se stessa).

1. Ottenere la componente numerica da una coppia di volume

Implementa il metodo KitchenCalculator.get_volume. Data una coppia di volume sotto forma di tupla, deve restituire solo la componente numerica.

KitchenCalculator.get_volume({:cup, 2.0})
# => 2.0

2. Convertire la coppia di volume in millilitri

Implementa il metodo KitchenCalculator.to_milliliter. Data una coppia di volume sotto forma di tupla, deve convertire il volume in millilitri usando la tabella di conversione.

KitchenCalculator.to_milliliter({:cup, 2.5})
# => {:milliliter, 600.0}

3. Convertire in un'altra unità la coppia di volume in millilitri

Implementa il metodo KitchenCalculator.from_milliliter. Data una coppia di volume sotto forma di tupla e l'unità desiderata, deve convertire il volume nell'unità desiderata usando la tabella di conversione.

KitchenCalculator.from_milliliter({:milliliter, 1320.0}, :cup)
# => {:cup, 5.5}

4. Convertire da qualsiasi unità a qualsiasi unità

Implementa il metodo KitchenCalculator.convert. Data una coppia di volume sotto forma di tupla e l'unità desiderata, deve convertire il volume dato nell'unità desiderata.

KitchenCalculator.convert({:teaspoon, 9.0}, :tablespoon)
# => {:tablespoon, 3.0}
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Crystal Exercism

Vuoi iniziare Calcolatrice da cucina?

Iscriviti a Exercism per imparare e padroneggiare Crystal con 26 concetti142 esercizi e il mentoring di persone reali, tutto gratis.