<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Roberto Pauletto - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Impara a programmare gratuitamente! Tutorial di programmazione su Python, JavaScript, Linux e molto altro. ]]>
        </description>
        <link>https://www.freecodecamp.org/italian/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Roberto Pauletto - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/italian/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 09:46:50 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/italian/news/author/rob1458/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Una Guida Visuale ai Meccanismi Interni di Git — Oggetti, Branch e Come Creare un Repository Da Zero ]]>
                </title>
                <description>
                    <![CDATA[ Molti di noi usano git quotidianamente. Ma quanti di noi sanno cosa succede dietro le quinte? Per esempio, cosa succede quando usiamo git commit? Cosa viene conservato dopo ogni commit? Sono solo le differenze tra il commit attuale e quello precedente? In questo caso come sono codificate le differenze? Oppure ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/una-guida-visuale-ai-meccanismi-interni-di-git/</link>
                <guid isPermaLink="false">64c2c2c17194960696cf26d9</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 28 Aug 2023 08:59:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/07/A-Visual-Guide-to-Git-Internals-Book-Cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">A Visual Guide to Git Internals — Objects, Branches, and How to Create a Repo From Scratch</a>
      </p><p>Molti di noi usano <code>git</code> quotidianamente. Ma quanti di noi sanno cosa succede dietro le quinte?</p><p>Per esempio, cosa succede quando usiamo <code>git commit</code>? Cosa viene conservato dopo ogni commit? Sono solo le differenze tra il commit attuale e quello precedente? In questo caso come sono codificate le differenze? Oppure viene salvata un'istantanea del repository ogni volta? Cosa succede veramente quando usiamo <code>git init</code>?</p><p>Molti di coloro che usano <code>git</code> non conoscono le risposte alle domande poste qui sopra. Ma ha davvero importanza?</p><p>Innanzitutto, come professionisti, dovremmo impegnarci a capire gli strumenti che usiamo, specialmente così di frequente, come <code>git</code>.</p><p>Ma soprattutto, ho scoperto che capire come funziona effettivamente <code>git</code> è utile in molte situazioni, sia che si tratti di risolvere conflitti di merge, che si cerchi di eseguire un rebase interessante, o anche solo quando qualcosa va leggermente storto.</p><p>Potrai trarre vantaggio da questo post se hai già abbastanza esperienza con <code>git</code> per sentirti a tuo agio con comandi come <code>git pull</code> ,<code>git push</code> ,<code>git add</code> oppure <code>git commit</code>.</p><p>Ciononostante, inizieremo con uno sguardo d'insieme per essere sicuri di essere tutti allo stesso livello per quanto riguarda la conoscenza dei meccanismi di <code>git</code>, e in particolare con i termini che verranno usati in questo post.</p><p>Ho anche caricato su YouTube una serie che tratta degli argomenti trattati in questo post e che ti invito a guardare <a href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7" rel="noopener">qui</a>.</p><h2 id="cosa-aspettarsi-da-questo-tutorial">Cosa aspettarsi da questo tutorial</h2><p>Avremo una approfondita comprensione di ciò che accade dietro le quinte durante le operazioni che facciamo quasi quotidianamente con <code>git</code>.</p><p>Inizieremo trattando gli <strong>oggetti </strong>—  <strong>blob</strong>, <strong>tree</strong> <strong>(alberi)</strong> e <strong>commit</strong>. Discuteremo quindi brevemente dei <strong>branch</strong> e di come vengono implementati. Analizzeremo i dettagli della <strong>directory di lavoro</strong>, dell'<strong>area di stage</strong> e del <strong>repository</strong>.</p><p>Ci assicureremo anche di capire come questi termini si relazionano rispetto ai comandi <code>git</code> che conosciamo e utilizziamo per creare un nuovo repository.</p><p>Successivamente, creeremo un repository da zero , senza usare <code>git init</code>, <code>git add</code> o <code>git commit</code>. Questo ci consentirà di <strong>approfondire la nostra comprensione di ciò che avviene dietro le quinte </strong>quando lavoriamo con <code>git</code>.</p><p>Creeremo anche nuovi branch, ci sposteremo tra di essi e creeremo ulteriori commit, tutto senza usare <code>git branch</code> o <code>git checkout</code>.</p><p>Alla fine di questo post, <strong>ti sentirai di aver <em>capito</em> git</strong>. Sei pronto per farlo?😎</p><h2 id="oggetti-git-blob-alberi-tree-e-commit">Oggetti Git: blob, alberi (tree) e commit</h2><p>È molto utile pensare a <code>git</code> come alla gestione di un file system, e in particolare a "istantanee" di un file system in un dato momento.</p><p>Un file system inizia con una <em>directory radice</em> (root directory), nei sistemi basati su Unix, <code>/</code>, che in genere contiene altre directory (per esempio <code>/usr</code> o <code>/bin</code>). Queste directory possono contenere altre directory e/o file (per esempio <code>/usr/1.txt</code>).</p><p>In <code>git</code>, il contenuto dei file viene conservato in oggetti chiamati <strong><strong>blob</strong></strong> (binary large objects – grandi oggetti binari).</p><p>La differenza tra <strong><strong>blob</strong></strong> e file è che i file contengono anche metadati. Per esempio un file "ricorda" quando è stato creato, quindi se lo sposti in un'altra directory, la sua data di creazione rimane la stessa.</p><p>I<strong> b<strong>lob</strong></strong>, diversamente, hanno solo contenuto, flussi binari di dati. Un <strong>blob </strong>non registra la sua data di creazione, il suo nome o qualsiasi altra cosa diversa dal suo contenuto.</p><p>Ogni <strong><strong>blob</strong> </strong>in <code>git</code> viene identificato dal suo <a href="https://en.wikipedia.org/wiki/SHA-1" rel="noopener">hash SHA-1</a>. Gli hash SHA-1 sono di 20 byte e rappresentano in genere 40 caratteri in formato esadecimale. In questo post talvolta mostreremo solo i primi caratteri di questo hash.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-34.png" class="kg-image" alt="Blobs have SHA-1 hashes associated with them" width="600" height="400" loading="lazy"></figure><p>In <code>git</code>, l'equivalente di una directory è un <strong>albero</strong> (<strong><strong>tree</strong>)</strong>. Un albero in pratica è un elenco del contenuto di una directory, che può essere costituito da dei <strong>blob</strong> così come da altri <strong>alberi</strong>.</p><p>Anche gli <strong>alberi</strong> sono identificati dal loro hash SHA-1. Per riferirsi a questi oggetti, siano blob o alberi, si usa il loro hash SHA-1.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-35.png" class="kg-image" alt="A tree is a directory listing" width="600" height="400" loading="lazy"></figure><p>Osserva l'<strong>albero</strong> <strong><strong>CAFE7 </strong></strong>che &nbsp;contiene il &nbsp;<strong><strong>blob F92A0</strong></strong> che rappresenta <em><em>pic.png. </em></em>In un altro <strong>albero</strong>, quello stesso <strong><strong>blob </strong></strong>potrebbe avere un altro nome.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-36.png" class="kg-image" alt="A tree may contain sub-trees, as well as blobs" width="600" height="400" loading="lazy"></figure><p>Il diagramma qui sopra equivale a un file system con una directory radice che ha un file, <code>/test.js</code>, e una directory chiamata <code>/docs</code> nella quale ci sono due file: <code>/docs/pic.png</code> e <code>/docs/1.txt</code>.</p><p>Ora è tempo di prendere un'istantanea di quel file system e conservare tutti i file al momento esistenti, assieme al loro contenuto.</p><p>In <code>git</code>, un'istantanea è un <strong><strong>commit</strong></strong>. Un oggetto <strong><strong>commit</strong></strong> include un puntatore all'<strong>albero</strong> principale (la directory radice), e anche altri metadati come il l'esecutore del commit (<strong><strong>committer</strong></strong>), un <strong>messaggio </strong>di commit<strong>, </strong>e la <strong>marca temporale</strong> del commit.</p><p>In molti casi, un <strong><strong>commit</strong></strong> ha anche uno o più <strong><strong>commit</strong> </strong>genitori, vale a dire le istantanee precedenti. Naturalmente anche gli oggetti <strong><strong>commit</strong></strong> sono identificati dal loro hash SHA-1. Questi sono gli hash mostrati quando usiamo <code>git log</code>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-37.png" class="kg-image" alt="A commit is a snapshot in time. It refers to the root tree. As this is the first commit, it has no parent(s)." width="600" height="400" loading="lazy"></figure><p>Ogni <strong><strong>commit </strong></strong>contiene l'<em>intera istantanea, </em>non solo le differenze rispetto ai <strong>commit</strong> precedenti.</p><p>Come può funzionare? Non significa che dovremo conservare un gran volume di dati ad ogni commit?</p><p>Esaminiamo cosa succede se modifichiamo il contenuto di un file. Diciamo che vogliamo modificare <code>1.txt</code>, aggiungendo un punto esclamativo, cioè modifichiamo il contenuto da <code>HELLO WORLD</code> a <code>HELLO WORLD!</code>.</p><p>Bene, questa modifica significa avere un nuovo <strong>blob</strong>, con un nuovo hash SHA-1. Ha senso, visto che <code>sha1("HELLO WORLD")</code> è diverso da <code>sha1("HELLO WORLD!")</code>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-38.png" class="kg-image" alt="Changing the blob results in a new SHA-1" width="600" height="400" loading="lazy"></figure><p>Poiché abbiamo un nuovo hash, allora anche il contenuto dell'<strong>albero</strong> dovrebbe cambiare, dopo tutto il nostro <strong>albero</strong> non punta più al <strong><strong>blob 73D8A</strong></strong>, ma al <strong><strong>blob 62E7A</strong></strong> . Quando modifichiamo il contenuto di un <strong>albero </strong>cambiamo anche il suo hash.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-39.png" class="kg-image" alt="image-39" width="600" height="400" loading="lazy"><figcaption>L'albero che punta al blob modificato deve essere modificato a sua volta</figcaption></figure><p>Ora, visto che l'hash dell'<strong>albero</strong> è diverso, dobbiamo cambiare anche l'<strong>albero</strong> genitore, visto che non punta più all'<strong>albero<strong><strong><strong> CAFE7</strong></strong></strong></strong>, ma all'<strong>albero<strong><strong><strong> 24601</strong></strong></strong></strong>.<strong><strong><strong><strong> </strong></strong></strong></strong>Ne consegue che anche l'<strong>albero genitore</strong> avrà un nuovo hash.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-40.png" class="kg-image" alt="The root tree also changes, and so does its hash." width="600" height="400" loading="lazy"></figure><p>Siamo quasi pronti per creare un nuovo oggetto <strong><strong>commit</strong></strong>, e sembra che andremo a salvare un gran volume di dati, l'intero file system, ancora una volta! È davvero necessario?</p><p>In realtà, alcuni oggetti, <strong><strong>blob</strong></strong> nello specifico, non sono cambiati rispetto al commit precedente, il  <strong><strong>blob F92A0 </strong></strong>è rimasto invariato, e anche il &nbsp;<strong><strong>blob F00D1.</strong></strong></p><p>Ecco il trucco, fintanto che un oggetto non cambia, non lo salviamo nuovamente. In questo caso non dobbiamo salvare nuovamente i <strong><strong>blob F92A0 </strong></strong>e<strong><strong> blob F00D1</strong>. </strong>Dobbiamo solo riferirci a essi usando i loro valori di hash. Quindi possiamo creare il nostro oggetto <strong><strong>commit</strong></strong>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-41.png" class="kg-image" alt="image-41" width="600" height="400" loading="lazy"><figcaption>I blob che non cambiano sono referenziati tramite i loro valori hash</figcaption></figure><p>Visto che questo <strong><strong>commit</strong></strong> non è il primo <strong><strong>commit</strong></strong>, ha un genitore, il  <strong><strong>commit A1337</strong></strong>.</p><h4 id="per-ricapitolare-abbiamo-introdotto-tre-oggetti-git-"><strong>Per ricapitolare, abbiamo introdotto tre oggetti git:</strong></h4><ul><li><strong><strong>blob — </strong></strong>il contenuto di un file.</li><li><strong><strong>tree</strong> (albero) <strong> </strong></strong>— il contenuto di una directory (di <strong><strong>blob</strong></strong> e <strong>alberi</strong>).</li><li><strong><strong>commit </strong></strong>— un'istantanea dell'albero di lavoro.</li></ul><p>Prendiamo un attimo in considerazione gli hash di questi oggetti. Supponiamo che io abbia scritto la stringa <code>git is awesome!</code> e da essa abbia creato un <strong><strong>blob</strong>. </strong>Tu hai fatto lo stesso sul tuo sistema. Avremo lo stesso hash?</p><p>La risposta è  sì. Visto che i <strong><strong>blob</strong></strong> contengono gli stessi dati, avranno gli stessi valori di hash SHA-1.</p><p>Cosa succede se io creo un <strong>albero</strong> che fa riferimento al <strong><strong>blob </strong></strong> <code>git is awesome!</code>, e gli do nome e metadati specifici, e tu fai esattamente la stessa cosa sul tuo sistema. Avremo lo stesso hash?</p><p>Ancora una volta la risposta è sì. Visto che gli oggetti <strong>alberi</strong> sono uguali, avranno lo stesso hash.</p><p>Se creo un <strong><strong>commit</strong></strong> di quell'<strong>albero<strong> </strong></strong>con il messaggio di commit <code>Hello</code>, e tu fai lo stesso nel tuo file system. Avremo gli stessi hash?</p><p>In questo caso la risposta è negativa. Anche se i nostri oggetti <strong>commit</strong> fanno riferimento allo stesso <strong>albero</strong>, hanno dettagli di <strong>commit</strong> diversi, la marca temporale, l'esecutore del commit, e così via.</p><h2 id="branch-in-git">Branch in Git</h2><p><strong>Un<strong> branch</strong> (ramo) è semplicemente un riferimento nominativo a un <strong>commit</strong></strong>.</p><p>Possiamo sempre fare riferimento a un <strong>commit</strong> in git tramite il suo hash SHA-1, ma noi umani in genere preferiamo altri modi per denominare gli oggetti. Un <strong>branch</strong> è un modo di referenziare un <strong>commit</strong>, ma è semplicemente questo.</p><p>Nella maggior parte dei repository, la linea principale di sviluppo viene implementata in un branch chiamato <code>master</code>. È semplicemente un nome, creato quando usiamo <code>git init</code>, pertanto largamente usato. Tuttavia non riveste un significato particolare, e si potrebbe usare un qualsiasi altro nome ci vada a genio.</p><p>Tipicamente, il branch punta all'ultimo <strong>commit</strong> nella linea di sviluppo sulla quale stiamo attualmente lavorando.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-42.png" class="kg-image" alt="A branch is just a named reference to a commit" width="600" height="400" loading="lazy"></figure><p>Per creare un altro branch, in genere usiamo il comando <code>git branch</code>. Facendo questo creiamo in realtà un altro puntatore. Quindi se creiamo un branch chiamato <code>test</code>, usando il comando <code>git branch test</code>, stiamo in realtà creando un altro puntatore direzionato verso lo stesso <strong>commit</strong> del branch nel quale ci troviamo attualmente.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-43.png" class="kg-image" alt="image-43" width="600" height="400" loading="lazy"><figcaption>Usando <code>git branch</code> si crea un altro puntatore</figcaption></figure><p>Come fa <code>git</code> a sapere su quale branch ci troviamo attualmente? Mantiene un puntatore speciale, detto <code>HEAD</code>. In genere <code>HEAD</code> punta a un branch, che a sua volta punta a un <strong>commit</strong>. In alcuni casi, <code>HEAD</code> può anche puntare direttamente a un <strong>commit</strong>, ma non ci focalizzeremo su questo.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-44.png" class="kg-image" alt="image-44" width="600" height="400" loading="lazy"><figcaption><code>HEAD</code> punta al branch nel quale ci troviamo attualmente.</figcaption></figure><p>Per rendere attivo il branch <code>test</code>, possiamo usare il comando <code>git checkout test</code>. Possiamo già indovinare cosa fa questo comando in realtà: cambia semplicemente il puntamento di <code>HEAD</code> verso <code>test</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-45.png" class="kg-image" alt="image-45" width="600" height="400" loading="lazy"><figcaption><code>git checkout test</code> modfiica il puntamento di <code>HEAD</code></figcaption></figure><p>Possiamo anche usare &nbsp;<code>git checkout -b test</code> prima di creare il branch <code>test</code>, che equivale a eseguire <code>git checkout test</code>, per far puntare <code>HEAD</code> al nuovo branch.</p><p>Cosa succede se eseguiamo qualche modifica e creiamo un nuovo <strong>commit</strong> con <code>git commit</code>? A quale branch verrà aggiunto il nuovo &nbsp;<strong><strong>commit</strong></strong>?</p><p>La risposta è il branch <code>test</code>, visto che è il branch attivo (quello su cui punta <code>HEAD</code>). Successivamente, il puntatore di <code>test</code> verrà spostato verso il nuovo <strong>commit</strong> aggiunto. Nota che <code>HEAD</code> punta ancora a <code>test</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-46.png" class="kg-image" alt="image-46" width="600" height="400" loading="lazy"><figcaption>Ogni volta che usiamo <code>git commit</code>, il puntatore del branch si sposta verso il nuovo commit creato.</figcaption></figure><p>Quindi se riattiviamo <code>master</code> eseguendo <code>git checkout master</code>, facciamo in modo che <code>HEAD</code> punti nuovamente a <code>master</code> .</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-47.png" class="kg-image" alt="image-47" width="600" height="400" loading="lazy"></figure><p>Ora se creiamo un altro <strong><strong>commit</strong></strong>, verrà aggiunto al branch <code>master</code> (e il suo genitore sarà il <strong><strong>commit B2424</strong></strong>).</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-48.png" class="kg-image" alt="image-48" width="600" height="400" loading="lazy"></figure><h2 id="come-registrare-le-modifiche-in-git">Come registrare le modifiche in Git</h2><p>In genere, quando lavoriamo sul nostro codice, lo facciamo da <strong>una directory di lavoro</strong> (<strong>working dir</strong>). Una <strong>directory di lavoro</strong> o <strong>albero di lavoro</strong>, è una qualsiasi directory nel nostro file system che ha un <strong>repository</strong> associato. Contiene le cartelle e i file del nostro progetto, e una directory chiamata <code>.git</code>, che esamineremo più approfonditamente in seguito.</p><p>Dopo aver fatto alcune modifiche, vogliamo registrarle nel nostro <strong>repository</strong>. Un <strong>repository</strong> (<strong>repo</strong> in breve) è una collezione di <strong>commit</strong>, ciascuno dei quali rappresenta un archivio di quello che era l'<strong>albero di lavoro</strong> in una data precedente, sia sulla nostra macchina che su quella di qualcun altro.</p><p>Un <strong>r<strong>epository </strong></strong>include anche altre cose oltre ai nostri file che contengono il codice, come &nbsp;<code>HEAD</code>, branch, e così via.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-49.png" class="kg-image" alt="image-49" width="600" height="400" loading="lazy"></figure><p>A differenza di altri strumenti simili che potresti avere usato, <code>git</code> non inserisce le modifiche effettuate dall'<strong>albero di lavoro</strong> direttamente nel <strong>repository</strong>. Viceversa le modifiche sono prima registrate in qualcosa chiamato <strong>indice</strong> (<strong>index</strong>) o <strong>area di stage</strong> (<strong>staging area</strong>).</p><p>Entrambi questi termini fanno riferimento alla stessa cosa e sono spesso usati nella documentazione di <code>git</code>. Useremo questi termini in modo intercambiabile all'interno di questo post.</p><p>Quando attiviamo (<code>checkout</code>) un branch, <code>git</code> popola l'<strong>indice</strong> con tutti i contenuti dei file che erano presenti l'ultima volta nella nostra <strong>directory di lavoro</strong> e come apparivano quando sono stati originariamente verificati. Quando usiamo <code>git commit</code>, il <strong>commit</strong> viene creato in base allo stato dell'<strong>indice</strong>.</p><p>L'uso dell'<strong>indice</strong> ci consente di preparare con cura ogni commit. Per esempio potremmo avere due file con modifiche rispetto al nostro ultimo commit nella nostra <strong>directory di lavoro</strong>. Potremmo volere aggiungere solo uno di essi all'<strong>indice</strong> (usando <code>git add</code>), quindi usare <code>git commit</code> per registrare solo quelle modifiche.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-50.png" class="kg-image" alt="image-50" width="600" height="400" loading="lazy"></figure><p>I file nella nostra <strong>directory di lavoro</strong> possono trovarsi in uno di due stati: <strong>tracciato (tracked)</strong> o <strong>non tracciato (untracked)</strong>.</p><p>I file<strong> tracciati </strong>sono quelli che <code>git</code> conosce. Potrebbero trovarsi nell'ultima istantanea (<strong>commit) </strong>oppure essere stati portati nell<strong>'area di stage </strong>adesso.</p><p>I file<strong> non tracciati</strong>, sono tutto il resto, qualunque file o directory nella nostra <strong>directory di lavoro</strong> che non compariva nella nostra ultima istantanea (<strong>commit</strong>) e che non si trova attualmente nell<strong>'area di stage</strong>.</p><h2 id="come-creare-un-repository-nel-modo-convenzionale">Come creare un repository nel modo convenzionale</h2><p>Assicuriamoci di capire in che modo i termini che abbiamo introdotto si riferiscono al procedimento di creazione di un <strong>repository</strong>. Questa è solo una rapida panoramica di alto livello, prima di immergerci molto più a fondo in questo processo.</p><p><strong>Nota</strong>:  la maggior parte delle videate con i comandi di shell mostra i comandi UNIX. Fornirò comandi sia per Windows che per UNIX, con schermate da Windows, per coprire i sistemi operativi più diffusi. Quando i comandi saranno esattamente gli stessi, li fornirò solo una volta.</p><p>Inizializzeremo un nuovo <strong>repository</strong> usando <code>git init repo_1</code>, quindi ci sposteremo nella directory di quel repository usando <code>cd repo_1</code>. Digitando <code>tree /f .git</code> possiamo vedere che l'esecuzione di <code>git init</code> ha prodotto parecchie sottodirectory all'interno di <code>.git</code>. (L'opzione del comando tree &nbsp;<code>/f</code> include anche i file nel risultato dell'esecuzione del comando).</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-51.png" class="kg-image" alt="image-51" width="600" height="400" loading="lazy"></figure><p>Creiamo un file all'interno della directory <code>repo_1</code> (versione Windows):</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-52.png" class="kg-image" alt="image-52" width="600" height="400" loading="lazy"></figure><p>Sui sistemi Linux e macOS:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-53.png" class="kg-image" alt="image-53" width="600" height="400" loading="lazy"></figure><p>Questo file si trova all'interno della nostra <strong>directory di lavoro</strong>. Tuttavia, visto che non è ancora stato inserito nell'<strong>area di stage</strong>, attualmente risulta <strong>non tracciato</strong> (<strong>untracked</strong>). Verifichiamolo con il comando <code>git status</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-54.png" class="kg-image" alt="image-54" width="600" height="400" loading="lazy"><figcaption>Il nuovo file non è tracciato visto che non è stato ancora inserito nell'area di stage, e non era compreso in un precedente commit</figcaption></figure><p>Ora possiamo aggiungere questo file all'<strong>area di stage</strong> con il comando <code>git add new_file.txt</code>. Possiamo verificare che il file si trova nell'<strong>area di stage</strong> eseguendo <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-55.png" class="kg-image" alt="image-55" width="600" height="400" loading="lazy"><figcaption>Aggiunto un nuovo file nell'area di stage</figcaption></figure><p>Ora possiamo creare un <strong>commit</strong> con <code>git commit</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-56.png" class="kg-image" alt="image-56" width="600" height="400" loading="lazy"></figure><p>È cambiato qualcosa nella directory <code>.git</code>? Eseguiamo <code>tree /f .git</code> per verificare:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-57.png" class="kg-image" alt="image-57" width="600" height="400" loading="lazy"><figcaption>Sono cambiate molte cose all'interno di <code>.git</code></figcaption></figure><p>Sembra che siano cambiate parecchie cose. È ora di esaminare approfonditamente la struttura di <code>.git</code> e capire cosa succede dietro le quinte quando eseguiamo <code>git init</code>, <code>git add</code> oppure <code>git commit</code>.</p><h2 id="ora-di-andare-alle-fondamenta">Ora di andare alle fondamenta</h2><p>Fino ad ora abbiamo trattato alcuni degli aspetti base di Git, ora siamo pronti per andare davvero a fondo. </p><p>Per capire a fondo come funziona <code>git</code>, dovremo creare un <strong>repository</strong>, questa volta però lo faremo partendo da zero.</p><p>Non useremo <code>git init</code>, <code>git add</code> o <code>git commit</code>, il che ci consentirà di ottenere una migliore comprensione pratica del procedimento.</p><h2 id="come-impostare-git">Come impostare <code>.git</code></h2><p>Creiamo una nuova directory, portiamoci all'interno di essa ed eseguiamo <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-106.png" class="kg-image" alt="image-106" width="600" height="400" loading="lazy"></figure><p>Va bene, <code>git</code> non sembra contento visto che non ha trovato nessuna cartella <code>.git</code>. La cosa naturale da fare sarebbe semplicemente crearla, poi rieseguire <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-107.png" class="kg-image" alt="image-107" width="600" height="400" loading="lazy"></figure><p>Apparentemente, non è sufficiente creare una cartella <code>.git</code> . Ci serve qualche cosa da immettere in quella directory.</p><p><strong>Un<strong><strong><strong> repository </strong></strong></strong>git ha due componenti principali</strong>:</p><ol><li>Una collezione di oggetti — <strong><strong><strong><strong>blob</strong></strong></strong></strong>, <strong>alberi<strong><strong><strong>,</strong></strong></strong></strong> e <strong><strong><strong><strong>commit</strong></strong></strong></strong>.</li><li>Un sistema di denominazione di quegli oggetti, o <strong>riferimenti (references)</strong>.</li></ol><p>Un <strong><strong><strong><strong>repository</strong></strong></strong></strong> potrebbe anche contenere altre cose, come gli hook di git, ma come minimo deve includere oggetti e riferimenti.</p><p>Creiamo quindi una directory per gli oggetti, <code>.git\objects</code> e una per i riferimenti, &nbsp;<code>.git\refs</code> (sui sistemi UNIX <code>.git/objects</code> e <code>.git/refs</code>, rispettivamente).</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-108.png" class="kg-image" alt="image-108" width="600" height="400" loading="lazy"></figure><p>Un tipo di riferimento sono i branch. Internamente, <code>git</code> chiama i branch con il nome head. Quindi andremo a creare una directory apposita, <code>.git\refs\heads</code>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-109.png" class="kg-image" alt="image-109" width="600" height="400" loading="lazy"></figure><p>Lo stato non cambia ancora eseguendo <code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-110.png" class="kg-image" alt="image-110" width="600" height="400" loading="lazy"></figure><p>Come fa <code>git</code> a sapere dove iniziare a cercare un <strong>commit</strong> nel <strong>repository</strong>? Come spiegato in precedenza, cerca <code>HEAD</code>, che punta al branch attivo corrente (o <strong>commit</strong> in taluni casi).</p><p>Quindi dobbiamo creare <code>HEAD</code>, che è semplicemente un file che si trova in <code>./git/HEAD</code>. Per farlo eseguiamo:</p><p>Su Windows: <code>&gt; echo ref: refs/heads/master &gt; .git\HEAD</code></p><p>Su sistemi UNIX: <code>$ echo "ref: refs/heads/master" &gt; .git/HEAD</code></p><p>⭐ Adesso sappiamo come viene implementato <code>HEAD</code>, è semplicemente un file e il suo contenuto descrive verso quale oggetto puntare.</p><p>Dopo l'esecuzione dei comandi qui sopra, <code>git status</code> sembra cambiare idea:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-111.png" class="kg-image" alt="image-111" width="600" height="400" loading="lazy"><figcaption>HEAD è semplicemente un file</figcaption></figure><p>Ora <code>git</code> crede che siamo nel branch chiamato <code>master</code>, anche se non abbiamo creato questo branch. Come detto prima, &nbsp;<code>master</code> è solo un nome. Avremmo potuto far credere a &nbsp;<code>git</code> di essere su un branch chiamato <code>banana</code> se avessimo voluto:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-112.png" class="kg-image" alt="image-112" width="600" height="400" loading="lazy"><figcaption>🍌</figcaption></figure><p>Per il resto di questo post torneremo a <code>master</code>, semplicemente per conformarci alla normale convenzione.</p><p>Ora che la nostra directory <code>.git</code> è pronta, possiamo iniziare le operazioni per creare un <strong>commit</strong> (come già detto, senza usare <code>git add</code> oppure <code>git commit</code>).</p><h2 id="i-comandi-in-git-idraulica-vs-ceramica">I comandi in Git, idraulica vs. ceramica</h2><p>A questo punto sarebbe utile fare una distinzione tra due tipi di comando in <code>git</code>: idraulici e in ceramica. La definizione è presa in prestito da termini usati dagli idraulici quando si parla di tazza (già, questa — 🚽), che tradizionalmente è fatta di ceramica mentre l'infrastruttura (tubi e scarichi) costituisce l'idraulica.</p><p>Mantenendo l'analogia, possiamo dire che la ceramica fornisce all'utente un'interfaccia amichevole per accedere a tubature e scarichi. La maggior parte delle persone ha a che fare con la ceramica. Tuttavia, quando succede qualcosa di veramente brutto, e qualcuno vuole capirne il motivo, deve rimboccarsi le maniche e controllare le tubature e gli scarichi. (Nota: questi termini non sono miei, sono usati in modo estensivo in <code>git</code>).</p><p><code>git</code> usa questa terminologia come analogia per distinguere i comandi di basso livello che in genere gli utenti non usano direttamente (i comandi idraulici che agiscono su tubi e scarichi) dai comandi di alto livello più amichevoli per gli utenti (comandi in ceramica).</p><p>Fino a ora abbiamo avuto a che fare con i comandi in ceramica, <code>git init</code>, <code>git add</code> o <code>git commit</code>. Di seguito passeremo ai comandi idraulici.</p><h2 id="come-creare-oggetti-in-git">Come creare oggetti in Git</h2><p>Partiamo creando un oggetto e scrivendolo nel database degli oggetti di <code>git</code>, che si trova in <code>.git\objects</code>. Troveremo un valore di hash SHA-1 per un <strong><strong><strong><strong>blob</strong></strong></strong></strong> usando il nostro primo comando di basso livello (idraulico), <code>git hash-object</code>, in questo modo:</p><p>Su Windows:</p><p><code>&gt; echo git is awesome | git hash-object --stdin</code></p><p>Su sistemi UNIX:</p><p><code>$ echo "git is awesome" | git hash-object --stdin</code></p><p>Usando <code>--stdin</code> diciamo a <code>git hash-object</code> di prendere i suoi dati dallo standard input. Questo ci fornirà il relativo valore hash valido.</p><p>Per scrivere effettivamente quel <strong>blob</strong> nel database degli oggetti di <code>git</code> possiamo semplicemente aggiungere l'opzione <code>-w</code> a <code>git hash-object</code>. Successivamente possiamo verificare il contenuto della cartella <code>.git</code> e vedere cosa è cambiato.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-113.png" class="kg-image" alt="image-113" width="600" height="400" loading="lazy"><figcaption>Scrittura di un blob nel database degli oggetti</figcaption></figure><p>Adesso possiamo vedere che l'hash del nostro <strong>blob</strong> è <code>54f6...36</code>. Possiamo anche vedere che è stata creata una sottodirectory in <code>.git\objects</code> chiamata <code>54</code>, il file è stato chiamato <code>f6...36</code>.</p><p>Quindi <code>git</code> in realtà prende i primi due caratteri dell'hash SHA-1 e li usa come nome di una directory. I restanti caratteri dell'hash vengono usati come nome del file che contiene il <strong><strong><strong><strong>blob</strong></strong></strong></strong>.</p><p>Come mai? Immagina un repository piuttosto grande, uno che abbia 300.000 oggetti (<strong><strong><strong><strong>blob</strong></strong></strong></strong>, <strong>alberi</strong>, e <strong><strong><strong><strong>commit</strong></strong></strong></strong>) nel suo database. Può servire molto tempo per cercare un hash in una lista di 300.000 elementi. Per questo <code>git</code> divide semplicemente il problema per 256.</p><p>Per cercare l'hash qui sopra, <code>git</code> per prima cosa cerca una directory chiamata <code>54</code> all'interno di <code>.git\objects</code>, che potrebbe avere fino a 256 directory (da <code>00</code> a <code>FF</code>). Poi cerca in quella directory, restringendo la ricerca mano a mano che la stessa progredisce.</p><p>Torniamo al nostro procedimento per generare un <strong>commit</strong>. Ora che abbiamo creato un oggetto, di che tipo è? Possiamo usare un altro comando di basso livello, <code>git cat-file -t</code> (<code>-t</code> sta per “tipo”), per verificarlo:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-114.png" class="kg-image" alt="image-114" width="600" height="400" loading="lazy"></figure><p>Non c'è da sorprendersi, questo oggetto è un <strong><strong><strong><strong>blob</strong></strong></strong></strong>. Possiamo anche usare &nbsp;<code>git cat-file -p</code> (<code>-p</code> sta per “pretty-print” - bella stampa) per vederne il contenuto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-115.png" class="kg-image" alt="image-115" width="600" height="400" loading="lazy"></figure><p>Il procedimento di creazione di un <strong>blob</strong> in genere si verifica quando aggiungiamo qualcosa nell'<strong>area di stage</strong>, vale a dire quando usiamo <code>git add</code>.</p><p>Ricorda che <code>git</code> crea un <strong><strong><strong><strong>blob</strong></strong></strong></strong> dell'<em>intero</em> file portato in area di stage. Anche se viene modificato un solo carattere (come nell'esempio di prima quando abbiamo aggiunto un <code>!</code>), il file avrà un nuovo <strong><strong><strong><strong>blob </strong></strong></strong></strong>con un nuovo <strong><strong><strong><strong>hash</strong></strong></strong></strong>.</p><p>Vedremo modifiche se verifichiamo lo stato del repository usando <code>git status</code>?</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-116.png" class="kg-image" alt="image-116" width="600" height="400" loading="lazy"></figure><p>Apparentemente no. Aggiungere un oggetto <strong>blob</strong> al database interno di <code>git</code> non modifica lo stato, visto che <code>git</code> non sa in questa fase quali file siano tracciati o meno.</p><p>Dobbiamo tracciare questo file, aggiungendolo all'<strong>area di stage</strong>. A questo scopo possiamo usare il comando di basso livello <code>git update-index</code>, così: <code>git update-index --add --cacheinfo 100644 &lt;blob-hash&gt; &lt;nomefile&gt;</code>.</p><p>Nota: <code>cacheinfo</code> è un file in modalità 16-bit <a href="https://github.com/git/git/blob/master/Documentation/technical/index-format.txt" rel="noopener nofollow">conservato da git</a>, seguendo le direttive di <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html" rel="noopener nofollow">tipi e modalità POSIX</a>. Questo va oltre lo scopo di questo post.</p><p>Eseguendo il comando qui sopra otterremo una modifica nel contenuto di <code>.git</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-117.png" class="kg-image" alt="image-117" width="600" height="400" loading="lazy"></figure><p>Riesci a identificare le modifiche? È stato creato un nuovo file chiamato <code>index</code> . Eccolo, il famoso <strong><strong><strong><strong>ind</strong></strong></strong>ice</strong> (o <strong>area di stage</strong>), è praticamente un file che si trova nella directory <code>.git</code>.</p><p>Adesso che il nostro <strong><strong><strong><strong>blob</strong></strong></strong></strong> è stato aggiunto all'<strong>indice</strong>, ci aspettiamo che il risultato di <code>git status</code> sia diverso, come questo:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-118.png" class="kg-image" alt="image-118" width="600" height="400" loading="lazy"></figure><p>Interessante! Sono successe due cose.</p><p>La prima, possiamo vedere che <code>my_file.txt</code> è visualizzato in verde nella sezione <code>Changes to be committed</code> (modifiche da portare in commit). Questo perché l'<strong>indice</strong> ora contiene <code>my_file.txt</code>, in attesa di essere portato in un commit.</p><p>La seconda, osserviamo che <code>my_file.txt</code> viene visualizzato in rosso, poiché <code>git</code> crede che <code>my_file.txt</code> sia stato eliminato e il fatto che il file sia stato eliminato non è stato registrato in <strong>area di stage</strong>.</p><p>Questo succede in quanto abbiamo aggiunto un <strong>blob</strong> con il contenuto <code>git is awesome</code> al database degli oggetti, e abbiamo detto all'<strong>indice </strong>che <code>my_file.txt</code> ha il contenuto di quel &nbsp;<strong><strong><strong><strong>blob</strong></strong></strong></strong>, ma in realtà non abbiamo mai veramente creato quel file.</p><p>Possiamo facilmente risolvere prendendo il contenuto del <strong>blob</strong> e scrivendolo nel nostro file system, in un file chiamato <code>my_file.txt</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-119.png" class="kg-image" alt="image-119" width="600" height="400" loading="lazy"></figure><p>Ne consegue che <code>my_file.txt</code> non appare più in rosso nel risultato di &nbsp;<code>git status</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-120.png" class="kg-image" alt="image-120" width="600" height="400" loading="lazy"></figure><p>È ora di creare un oggetto <strong>commit </strong>dalla nostra <strong>area di stage</strong>. Come spiegato sopra, un oggetto <strong>commit</strong> ha un riferimento a un <strong>albero</strong>, quindi dobbiamo crearlo.</p><p>Lo possiamo fare con il comando <code>git write-tree</code>, che registra il contenuto dell'<strong>indice</strong> in un oggetto <strong>albero</strong>. Naturalmente possiamo usare <code>git cat-file -t</code> per verificare che in effetti si tratti di un <strong>albero<strong><strong><strong>:</strong></strong></strong></strong></p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-121.png" class="kg-image" alt="image-121" width="600" height="400" loading="lazy"><figcaption>Creazione di un oggetto albero nell'indice</figcaption></figure><p>Possiamo usare <code>git cat-file -p</code> per vedere il contenuto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-122.png" class="kg-image" alt="image-122" width="600" height="400" loading="lazy"></figure><p>Grande, abbiamo creato un <strong>albero</strong>, e ora ci serve creare un oggetto <strong>commit</strong> che faccia riferimento a questo <strong>albero</strong>. Per farlo possiamo usare <code>git commit-tree &lt;hash-albero&gt; -m &lt;messaggio_di_commit&gt;</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-123.png" class="kg-image" alt="image-123" width="600" height="400" loading="lazy"></figure><p>Ora dovresti essere a tuo agio con i comandi usati per verificare il tipo di oggetto creato, e per stamparne il contenuto:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-124.png" class="kg-image" alt="image-124" width="600" height="400" loading="lazy"><figcaption>Creazione di un oggetto commit</figcaption></figure><p>Osserva che questo <strong><strong><strong><strong>commit </strong></strong></strong></strong>non ha un <strong>genitore</strong>, visto che è il primo <strong><strong><strong><strong>commit</strong></strong></strong></strong>. Quando aggiungeremo un altro <strong>commit</strong>, dovremo dichiarare il suo <strong>genitore</strong>, lo faremo più tardi.</p><p>L'ultimo hash che abbiamo ottenuto, &nbsp;<code>80e...8f</code> è l'hash di un<strong> commit</strong>. Questi hash ci devono essere piuttosto familiari, ci abbiamo a che fare tutte le volte. Nota che un <strong>commit</strong> detiene un oggetto <strong>albero</strong>, con un proprio hash, che raramente specifichiamo esplicitamente.</p><p>Qualcosa è cambiato nel risultato di &nbsp;<code>git status</code>?</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-125.png" class="kg-image" alt="image-125" width="600" height="400" loading="lazy"></figure><p>Niente 🤔.</p><p>Come mai? Bene, per sapere che il nostro file è stato portato in commit, a <code>git</code> serve conoscere il nostro ultimo <strong>commit</strong>. Come ci riesce? Legge <code>HEAD</code>:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-126.png" class="kg-image" alt="image-126" width="600" height="400" loading="lazy"><figcaption>Stampare il contenuto di <code>HEAD</code> su Windows</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-127.png" class="kg-image" alt="image-127" width="600" height="400" loading="lazy"><figcaption>Stampare il contenuto di <code>HEAD</code> su sistemi UNIX</figcaption></figure><p><code>HEAD</code> punta a <code>master</code>, ma cos'è <code>master</code>? Non l'abbiamo ancora creato.</p><p>Come spiegato in precedenza, un branch è semplicemente un riferimento nominativo a un <strong>commit</strong>. In questo caso, vorremmo che <code>master</code> facesse riferimento al <strong>commit</strong> con hash <code>80e8ed4fb0bfc3e7ba88ec417ecf2f6e6324998f</code>.</p><p>Possiamo farlo creando semplicemente un file <code>master</code> in &nbsp;<code>\refs\heads</code>, con questo hash come contenuto, così:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-128.png" class="kg-image" alt="image-128" width="600" height="400" loading="lazy"></figure><p>⭐ Alla fine, un <strong>branch</strong> è semplicemente un file all'interno di <code>.git\refs\heads</code>, che contiene un hash del <strong><strong><strong><strong>commit </strong></strong></strong></strong>al quale si riferisce.</p><p>Ora, finalmente, <code>git status</code> e <code>git log</code> sembrano apprezzare i nostri sforzi:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-129.png" class="kg-image" alt="image-129" width="600" height="400" loading="lazy"></figure><p>Abbiamo creato con successo un <strong>commit</strong> senza usare i comandi di alto livello (quelli in ceramica)! Forte, non è vero? 🎉</p><h2 id="come-lavorare-con-i-branch-in-git-dietro-le-quinte">Come lavorare con i branch in Git: dietro le quinte</h2><p>Proprio come abbiamo creato un &nbsp;<strong><strong><strong><strong>repository</strong></strong></strong></strong> e un <strong><strong><strong><strong>commit </strong></strong></strong></strong>senza usare <code>git init</code>, <code>git add</code> o <code>git commit</code>, ora possiamo creare e spostarci tra i <strong>branch</strong> senza usare i comandi di primo livello (quelli in ceramica), <code>git branch</code> o <code>git checkout</code>.</p><p>È perfettamente legittimo che tu sia eccitato, lo sono anche io 🙂</p><p><strong>Iniziamo<strong><strong><strong>:</strong></strong></strong></strong></p><p>Finora abbiamo solo un <strong>branch</strong>, che si chiama <code>master</code>. Per crearne un altro che chiameremo <code>test</code> (l'equivalente di <code>git branch test</code>), dobbiamo semplicemente creare un file chiamato <code>test</code> all'interno di <code>.git\refs\heads</code>, e il contenuto di quel file sarà lo stesso hash del <strong>commit</strong> al quale <code>master</code> punta.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-130.png" class="kg-image" alt="image-130" width="600" height="400" loading="lazy"></figure><p>Se usiamo <code>git log</code>, possiamo vedere che questo è in effetti il caso, sia <code>master</code> che <code>test</code> puntano a questo <strong><strong><strong><strong>commit</strong></strong></strong></strong>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-131.png" class="kg-image" alt="image-131" width="600" height="400" loading="lazy"></figure><p>Ora spostiamoci nel nostro branch appena creato (l'equivalente di <code>git checkout test</code>). A questo scopo, dovremo modificare <code>HEAD</code> per farlo puntare al nostro nuovo branch:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-132.png" class="kg-image" alt="image-132" width="600" height="400" loading="lazy"><figcaption>Spostamento al branch <code>test</code> modificando <code>HEAD</code></figcaption></figure><p>Come possiamo vedere, sia <code>git status</code> che <code>git log</code> confermano che <code>HEAD</code> ora punta a &nbsp;<code>test</code>, che è, di conseguenza, il branch attivo.</p><p>Ora possiamo avvalerci dei comandi già usati per creare un altro file e aggiungerlo all'<strong>indice</strong>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-133.png" class="kg-image" alt="image-133" width="600" height="400" loading="lazy"></figure><p>Con i comandi qui sopra, abbiamo creato un file chiamato <code>test.txt</code>, che contiene la parola <code>Testing</code>, creato il <strong>blob</strong> corrispondente, e lo abbiamo aggiunto all'<strong>indice</strong>. Abbiamo anche creato un <strong>albero</strong> che rappresenta l'<strong>indice</strong>.</p><p>Adesso creiamo un commit che fa riferimento a questo <strong>albero</strong>. Questa volta, dovremmo anche specificare il <em>genitore</em> di questo <strong>commit</strong>, che sarà il <strong>commit</strong> precedente. Specifichiamo il genitore usando l'opzione <code>-p</code> per &nbsp;<code>git commit-tree</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-136.png" class="kg-image" alt="image-136" width="600" height="400" loading="lazy"></figure><p>Abbiamo appena creato un <strong>commit</strong>, con <strong>albero</strong> e un genitore, come possiamo vedere:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-139.png" class="kg-image" alt="image-139" width="600" height="400" loading="lazy"></figure><p>Il risultato di <code>git log</code> ci mostrerà il nuovo <strong><strong><strong><strong>commit</strong></strong></strong></strong>?</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-138.png" class="kg-image" alt="image-138" width="600" height="400" loading="lazy"></figure><p><code>git log</code> non ci mostra nulla di nuovo, come puoi vedere. Perché?🤔 Ricorda che <code>git log</code> traccia i <strong><strong><strong><strong>branch</strong></strong></strong></strong> per trovare commit rilevanti da mostrare. Adesso ci mostra <code>test</code> e il &nbsp;<strong><strong><strong><strong>commit</strong></strong></strong></strong> a cui punta, e ci mostra anche <code>master</code>, che punta allo stesso <strong><strong><strong><strong>commit</strong></strong></strong></strong>.</p><p>Esatto, dobbiamo modificare &nbsp;<code>test</code> per farlo puntare al nostro nuovo <strong><strong><strong><strong>commit</strong></strong></strong></strong>. Lo facciamo modificando semplicemente il contenuto di &nbsp;<code>.git\refs\heads\test</code>:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/12/image-140.png" class="kg-image" alt="image-140" width="600" height="400" loading="lazy"></figure><p>Ha funzionato! 🎉🥂</p><p><code>git log</code> passa per <code>HEAD</code>, che gli dice di andare al branch <code>test</code>, che a sua volta punta al <strong>commit</strong> <code>465...5e</code>, il quale fa riferimento nuovamente al suo <strong>commit</strong> genitore <code>80e...8f</code>.</p><p>Meraviglioso, non è vero? 😊</p><h2 id="riepilogo">Riepilogo</h2><p>Questo post ti ha introdotto ai meccanismi interni di git. Abbiamo iniziato trattando gli oggetti di base, <strong>blob</strong>, <strong>alberi</strong> e <strong>commit</strong>.</p><p>Abbiamo appreso che un <strong>blob</strong> conserva il contenuto di un file. Un <strong>albero</strong> è un elenco di directory contenente <strong>blob</strong> e/o sotto<strong>alberi</strong>. Un <strong>blob</strong> è un'istantanea della nostra directory di lavoro, con alcuni metadati come la marca temporale e il messaggio di commit.</p><p>Abbiamo quindi discusso dei <strong>branch</strong> e spiegato che non sono altro che un riferimento nominativo a un <strong>commit</strong>.</p><p>Abbiamo continuato descrivendo la <strong>directory di lavoro</strong>, una directory a cui è associato un repository, l'<strong>area di stage</strong> (<strong>indice</strong>) che contiene l'<strong>albero</strong> per il <strong>commit</strong> successivo e il <strong>repository</strong>, che è una raccolta di <strong>commit</strong>.</p><p>Abbiamo chiarito come questi termini si relazionano ai comandi <code>git</code> che conosciamo creando un nuovo repository ed eseguendo il commit di un file utilizzando i ben noti comandi <code>git init</code>, <code>git add</code> e <code>git commit</code>.</p><p>Quindi ci siamo immersi senza paura in git. Abbiamo smesso di usare comandi di alto livello (in ceramica) e siamo passati a comandi di basso livello (idraulici).</p><p>Usando <code>echo</code> e comandi di basso livello come <code>git hash-object</code>, siamo stati in grado di creare un <strong>blob</strong>, aggiungerlo all'<strong>indice</strong>, creare un <strong>albero</strong> dell<strong>'indice</strong> e creare un oggetto <strong>commit</strong> che punta a quell'albero.</p><p>Siamo stati anche in grado di creare e passare da un <strong>branch</strong> all'altro. Complimenti a quelli di voi che l'hanno provato da soli!👏</p><p>Spero che dopo aver seguito questo post sentirai di aver approfondito la tua conoscenza di ciò che accade dietro le quinte quando lavori con <code>git</code>.</p><p><strong>Grazie per aver letto</strong>! Se ti è piaciuto questo articolo, puoi leggere di più su questo argomento sul blog <a href="http://swimm.io/">swimm.io</a>.</p><p><em><em><a href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a>,</em> <em>Chief Technology Officer</em> per <em><a href="https://swimm.io/">Swimm</a>. </em>Esperto di c<em>yber training </em>e fondatore di<em> Checkpoint Security Academy. Au</em>tore di </em><a href="https://data.cyber.org.il/networks/networks.pdf" rel="noopener nofollow noopener noopener"><em><em>Computer Networks</em></em></a><em> (in Ebraico)<em>.</em></em></p><p><em><em>Visi</em>ta il mio <a href="https://www.youtube.com/watch?v=79jlgESHzKQ&amp;list=PL9lx0DXCC4BMS7dB7vsrKI5wzFyVIk2Kg">Canale YouTube</a></em></p><h2 id="risorse-addizionali">Risorse addizionali</h2><p>Molto è stato scritto e detto su <code>git</code>. In particolare, ho trovato utili queste risorse (in lingua inglese - n.d.t.):</p><ul><li><a href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7" rel="noopener">La playlist di YouTube Git Internals — di Brief</a></li><li><a href="https://www.youtube.com/watch?v=MYP56QJpDr4" rel="noopener">La lezione di Tim Berglund  “Git From the Bits Up”</a></li><li><a href="https://jwiegley.github.io/git-from-the-bottom-up/" rel="noopener">Git from the Bottom Up ,  di John Wiegley</a></li><li><a href="http://www.gelato.unsw.edu.au/archives/git/0512/13748.html" rel="noopener">as promised, docs: git for the confused</a></li><li><a href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects" rel="noopener">Git Internals — Git Objects , dal libro Pro Git book, di Scott Chacon e Ben Straub</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Il Manuale di Git Rebase – La Guida Definitiva per Rebase ]]>
                </title>
                <description>
                    <![CDATA[ Uno degli strumenti più potenti che uno sviluppatore può avere nella propria cassetta degli attrezzi è git rebase. Eppure è noto per essere complesso e frainteso. La verità è che se capisci cosa fa realmente, git rebase è uno strumento molto elegante e diretto per ottenere tante cose diverse in ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/il-manuale-di-git-rebase/</link>
                <guid isPermaLink="false">64bcd6310ec9a30673ad5b88</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Tue, 08 Aug 2023 14:23:08 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/07/The-Git-Rebase-Handbook-Book-Cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/git-rebase-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">https://www.freecodecamp.org/news/git-rebase-handbook/</a>
      </p><p>Uno degli strumenti più potenti che uno sviluppatore può avere nella propria cassetta degli attrezzi è <code>git rebase</code>. Eppure è noto per essere complesso e frainteso.</p><p>La verità è che se capisci cosa fa <em>realmente</em>, <code>git rebase</code> è uno strumento molto elegante e diretto per ottenere tante cose diverse in Git.</p><p>Nei post precedenti, hai capito <a href="https://www.freecodecamp.org/news/git-diff-and-patch/">come funziona git diff</a>, <a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">cosa sia un'azione di merge</a>, <a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">come git risolve i conflitti di merge</a>. In questo post, capirai cos'è il comando rebase di Git, perché è diverso da merge e come utilizzare <code>git rebase</code> con sicurezza 💪🏻</p><h2 id="prima-di-iniziare"><strong>Prima di iniziare</strong></h2><ol><li>Ho creato anche un video che tratta il contenuto di questo post. Se desideri guardarlo mentre stai leggendo, puoi trovarlo <a href="https://youtu.be/3VFsitGUB3s">qui</a>.</li><li>Se vuoi fare esperimenti con il repository che ho usato e provare da solo i comandi, puoi trovarlo <a href="https://github.com/Omerr/rebase_playground">qui</a>.</li><li>Sto lavorando a un libro su Git! Ti interessa leggere la versione iniziale e darmi un feedback? Mandami una email: <a href="https://www.freecodecamp.org/news/p/2e1fc200-f447-4f55-b0a3-73ef790a2190/gitting.things@gmail.com">gitting.things@gmail.com</a></li></ol><p>OK, sei pronto?</p><h2 id="breve-riepilogo-cos-e-git-merge-">Breve riepilogo <strong>- Cos'e Git Merge</strong>? 🤔</h2><p>Dietro le quinte, <code>git rebase</code> e <code>git merge</code> sono cose molto, molto diverse. Allora come mai la gente continua a confrontarli tutte le volte?</p><p>La ragione è il loro utilizzo. Quando si lavora con Git in genere si lavora su branch diversi, nei quali si introducono delle modifiche.</p><p>Nel <a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/#howgits3waymergealgorithmworks">tutorial precedente</a>, ho fornito un esempio dove John e Paul (dei Beatles) scrivevano a 4 mani una nuova canzone. Avevano iniziato entrambi dal branch <code>main</code> poi ognuno di loro ha preso una strada diversa, modificando le parole, quindi confermando le loro modifiche.</p><p>Poi entrambi volevano integrare i loro cambiamenti, il che è qualcosa che succede molto frequentemente quando lavori con Git.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/rebase_integrazione.png" class="kg-image" alt="rebase_integrazione" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/rebase_integrazione.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/rebase_integrazione.png 898w" sizes="(min-width: 720px) 720px" width="898" height="331" loading="lazy"><figcaption>Una cronologia divergente - <code>paul_branch</code> e <code>john_branch</code> divergono da <code>main</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ci sono due modi principali per integrare modifiche introdotte in branch diversi in Git, oppure, in altre parole, diversi commit e diverse cronologie di commit. Questi sono merge e rebase.</p><p><a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">In un tutorial precedente</a>, abbiamo imparato a conoscere <code>git merge</code> molto bene. Abbiamo visto come eseguire un merge, abbiamo creato il <strong>merge di un commit </strong> – dove il contenuto di questo commit è una combinazione di due branch, e aveva anche due genitori, uno in ciascun branch.</p><p>Quindi, diciamo che sei sul branch <code>john_branch</code> (ipotizzando la cronologia descritta nell'immagine qui sopra) ed esegui <code>git merge paul_branch</code>. Arriverai a questo stato – dove su <code>john_branch</code>, c'è un nuovo commit con due genitori. Il primo sarà il commit su <code>john_branch</code> dove <code>HEAD</code> stava puntando prima di eseguire il merge, in questo caso - "Commit 6". Il secondo sarà il commit puntato da <code>paul_branch</code>, "Commit 9".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/rebase_divergenze.jpg" class="kg-image" alt="rebase_divergenze" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/rebase_divergenze.jpg 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/rebase_divergenze.jpg 895w" sizes="(min-width: 720px) 720px" width="895" height="276" loading="lazy"><figcaption>Il risultato dell'esecuzione di <code>git merge paul_branch</code>: Un nuovo merge commit con due genitori (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Osserva nuovamente il grafico della cronologia: hai creato una cronologia <strong>divergente</strong>. Puoi in effetti vedere dove sono stati ramificati e integrati nuovamente.</p><p>Quindi quando usi <code>git merge</code>, non riscrivi la cronologia – piuttosto aggiungi un commit alla cronologia esistente. E, nello specifico, un commit che crea cronologie divergenti.</p><h2 id="in-che-modo-git-rebase-diverso-da-git-merge-">In che modo <code>git rebase</code> è diverso da <code>git merge</code>? 🤔</h2><p>Quando si usa <code>git rebase</code>, succede qualcosa di diverso. 🥁</p><p>Partiamo dal quadro generale: se sei su <code>paul_branch</code>, ed esegui <code>git rebase john_branch</code>, Git va all'antenato comune per i branch di John e Paul. Poi prende le modifiche introdotte nei commit del branch di Paul e applica dette modifiche al branch di John.</p><p>In questo caso usi <code>rebase</code> per prendere le modifiche effettuate e confermate (con commit) in un branch – quello di Paul (<code>paul_branch</code>) – e le replichi in un branch diverso – quello di John (<code>john_branch</code>).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/integrazione-con-rebase.jpg" class="kg-image" alt="integrazione-con-rebase" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/integrazione-con-rebase.jpg 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/integrazione-con-rebase.jpg 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/integrazione-con-rebase.jpg 1227w" sizes="(min-width: 720px) 720px" width="1227" height="348" loading="lazy"><figcaption>Il risultato dell'esecuzione di <code>git rebase john_branch</code>: i commit in <code>paul_branch</code> sono stati "replicati" in <code>john_branch</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Aspetta, cosa significa? 🤔</p><p>Ora analizziamo questo concetto un poco per volta, in modo che tu possa capire pienamente cosa sta succedendo sotto il cofano 😎</p><h2 id="cherry-pick-come-base-per-rebase"><code>cherry-pick</code> come base per rebase</h2><p>È utile pensare a rebase come all'esecuzione di <code>git cherry-pick</code> – un comando che prende un commit, calcola le differenze che questo introduce confrontando il commit del genitore con il commit stesso, e le replica nel branch corrente.</p><p>Facciamolo a mano.</p><p>Se diamo un'occhiata alle differenze introdotte da "Commit 5" eseguendo <code>git diff main &lt;SHA_DI_COMMIT_5&gt;</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-199.png" class="kg-image" alt="image-199" width="559" height="248" loading="lazy"><figcaption>Esecuzione di <code>git diff</code> per osservare le modifiche introdotte da "Commit 5" (Fonte: <a href="https://youtu.be/3VFsitGUB3sù">Brief</a>)</figcaption></figure><p>Se vuoi fare esperimenti con il repository che ho usato e provare da solo i comandi, puoi trovare il repository <a href="https://github.com/Omerr/rebase_playground">qui</a>.</p><p>Puoi notare in questo commit, che John ha iniziato a lavorare a una canzone chiamata "Lucy in the Sky with Diamonds":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-200.png" class="kg-image" alt="image-200" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-200.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-200.png 896w" sizes="(min-width: 720px) 720px" width="896" height="666" loading="lazy"><figcaption>Il risultato di git diff - le modifiche introdotte da "Commit 5" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ti ricordo che puoi usare anche il comando <code>git show</code> per ottenere lo stesso risultato:</p><pre><code>git show &lt;SHA_DI_COMMIT_5&gt;</code></pre><p>Ora se esegui il <code>cherry-pick</code> di questo commit, introdurrai questa specifica modifica, sul branch attivo. Prima portati su <code>main</code>:</p><p><code>git checkout main</code> (oppure <code>git switch main</code>)</p><p>Poi crea un altro branch, giusto per essere più chiari:</p><p><code>git checkout -b my_branch</code> (oppure <code>git switch -c my_branch</code>)</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-201-1.png" class="kg-image" alt="image-201-1" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-201-1.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-201-1.png 607w" width="607" height="164" loading="lazy"><figcaption>Creazione del branch <code>my_branch</code> che si dirama da <code>main</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Poi esegui il <code>cherry-pick</code> di questo commit:</p><pre><code>git cherry-pick &lt;SHA_DI_COMMIT_5&gt;</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-202.png" class="kg-image" alt="image-202" width="594" height="113" loading="lazy"><figcaption>Uso di <code>cherry-pick</code> per applicare le modifiche introdotte da "Commit 5" in <code>main</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Esamina questo log (risultato di <code>git lol</code>):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-205.png" class="kg-image" alt="image-205" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-205.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-205.png 781w" sizes="(min-width: 720px) 720px" width="781" height="141" loading="lazy"><figcaption>Il risultato di <code>git lol</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>(<code>git lol</code> è un alias che ho aggiunto a Git per vedere chiaramente in modo grafico la cronologia. Puoi trovare il comando che sostituisce <a href="https://gist.github.com/Omerr/8134a61b56ca82dd90e546e7ef04eb77">qui</a>).</p><p>Sembra che tu abbia fatto un <em>copia-incolla </em>di "Commit 5". Ricorda che sebbene abbia lo stesso messaggio di commit e introduca le stesse modifiche, e punti anche allo stesso albero di oggetti &nbsp;del "Commit 5" originale, in questo caso è comunque un oggetto commit diverso, visto che è stato creato con una diversa marca temporale.</p><p>Se osserviamo le modifiche usando <code>git show HEAD</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-204.png" class="kg-image" alt="image-204" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-204.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-204.png 862w" sizes="(min-width: 720px) 720px" width="862" height="643" loading="lazy"><figcaption>Il risultato di git show HEAD (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Sono le stesse di "Commit 5"'.</p><p>Naturalmente, se osservi il contenuto del file con un editor (diciamo usando il comando <code>nano lucy_in_the_sky_with_diamonds.md</code>), sarà nello stesso stato nel quale si trovava dopo il "Commit 5" originale.</p><p>Forte! 😎</p><p>OK, ora puoi eliminare il nuovo branch così che non appaia nella tua cronologia tutte le volte:</p><pre><code>git checkout main
git branch -D my_branch</code></pre><h2 id="andare-oltre-cherry-pick-come-usare-git-rebase"><strong>Andare oltre<strong> <code>cherry-pick</code> – </strong>Come usare<strong> <code>git rebase</code></strong></strong></h2><p>Puoi considerare <code>git rebase</code> come un modo per eseguire più <code>cherry-pick</code> uno dopo l'altro – vale a dire "replicare" diversi commit. Questa non è la sola cosa che puoi fare con &nbsp;<code>rebase</code>, ma è un buon punto di partenza per la nostra spiegazione.</p><p>È ora di giocare con <code>git rebase</code>! 👏🏻👏🏻</p><p>In precedenza, hai integrato &nbsp;<code>paul_branch</code> in <code>john_branch</code>. Cosa sarebbe successo se avessi <em>eseguito il</em> <em>rebase </em>di <code>paul_branch</code> su <code>john_branch</code>? Avresti ottenuto una cronlogia molto diversa.</p><p>In sostanza, sarebbe come se avessimo preso le modifiche introdotte nei commit su <code>paul_branch</code> e le avessimo replicate su <code>john_branch</code>. Il risultato sarebbe stato una cronologia <strong>lineare</strong>.</p><p>Per capire il processo, ti fornirò una visione ad alto livello, poi approfondiremo ogni passaggio. Il processo di rebase di un branch su un altro branch è il seguente:</p><ol><li>Trova l'antenato comune.</li><li>Identifica i commit da "replicare".</li><li>Per ogni commit <code>X</code>, calcola <code>diff(genitore(X), X)</code>, e conserva il risultato come <code>patch(X)</code>.</li><li>Sposta <code>HEAD</code> verso la nuova base.</li><li>Applica le patch generate in ordine sul branch di destinazione. Ogni volta, crea un nuovo oggetto commit con il nuovo stato.</li></ol><p>Il processo di creare nuovi commit con lo stesso insieme di modifiche di commit esistenti è detto "<strong>replica</strong>" di questi commit, un termine che abbiamo già usato.</p><h2 id="-ora-di-provare-rebase-">È ora di provare rebase🙌🏻</h2><p>Partiamo dal branch di Paul:</p><pre><code>git checkout paul_branch</code></pre><p>Questa è la cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-206.png" class="kg-image" alt="image-206" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-206.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-206.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-206.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-206.png 1642w" sizes="(min-width: 720px) 720px" width="1642" height="460" loading="lazy"><figcaption>Cronologia dei commit prima di eseguire <code>git rebase</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ora veniamo alla parte eccitante:</p><pre><code>git rebase john_branch</code></pre><p>Osserva la cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-207.png" class="kg-image" alt="image-207" width="477" height="268" loading="lazy"><figcaption>La cronologia dopo il rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p><code>gg</code> è un alias per uno strumento esterno che ho introdotto <a href="https://youtu.be/3VFsitGUB3s">nel video</a> (è il programma git-graph <a href="https://github.com/mlange-42/git-graph">che puoi trovare in questo repository</a> - n.d.t.).</p><p>Pertanto mentre con <code>git merge</code> hai aggiunto alla cronologia, con <code>git rebase</code> hai<strong> riscritto la cronologia</strong>. Hai creato oggetti commit <strong>nuovi</strong>. Inoltre il risultato è un grafico di cronologia lineare, non divergente.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-209.png" class="kg-image" alt="image-209" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-209.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-209.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-209.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-209.png 2353w" sizes="(min-width: 720px) 720px" width="2000" height="548" loading="lazy"><figcaption>La cronologia dopo il rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>In sostanza abbiamo "copiato" i commit che si trovavano in <code>paul_branch</code>, introdotti dopo "Commit 4", e "incollati" in <code>john_branch</code>.</p><p>Il comando è chiamato "rebase", in quanto modifica la base di commit del branch dal quale viene eseguito. Nel nostro caso, prima di eseguire <code>git rebase</code>, la base di <code>paul_branch</code> era "Commit 4" – visto che da lì è "nato" il branch (derivato da <code>main</code>). Con <code>rebase</code>, hai chiesto a Git di darti un'altra base, vale a dire: fai finta che <code>paul_branch</code> sia "nato" &nbsp;da "Commit 6".</p><p>Per fare questo Git ha preso quello che era il "Commit 7", e ha "replicato" le modifiche introdotte in questo commit in "Commit 6", poi ha creato un nuovo oggetto commit. Questo oggetto differisce dal "Commit 7" originale in tre aspetti:</p><ol><li>Ha una marca temporale diversa.</li><li>Ha un commit genitore diverso – "Commit 6" invece che "Commit 4".</li><li>L'<a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">albero di oggetti</a> a cui punta è diverso - visto che le modifiche sono state introdotte all'albero di oggetti puntato da "Commit 6", non a quello puntato da "Commit 4".</li></ol><p>Nota l'ultimo commit qui, "Commit 9'". L'istantanea che rappresenta (cioè l'<a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">albero</a> a cui punta) è esattamente la stessa che avresti se avessi integrato i due branch. Lo stato dei file nel tuo repository Git sarebbe stato <strong>uguale</strong> se avessi usato <code>git merge</code>. Solo che la cronologia è diversa, e l'oggetto commit naturalmente.</p><p>Ora puoi semplicemente usare:</p><pre><code>git checkout main
git merge paul_branch</code></pre><p>Hmm... Cosa succederebbe se eseguissi questo ultimo comando? 🤔 Esamina nuovamente la cronologia dei commit, dopo esserti portato in &nbsp;<code>main</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-210.png" class="kg-image" alt="image-210" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-210.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-210.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-210.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-210.png 2352w" sizes="(min-width: 720px) 720px" width="2000" height="697" loading="lazy"><figcaption>La cronologia dopo il rebase e l'entrata in main (Fonte <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Cosa comporta integrare <code>main</code> e <code>paul_branch</code>?</p><p>In effetti, Git può semplicemente eseguire un merge fast-forward, visto che la cronologia è perfettamente lineare (se ti serve una rinfrescata su cosa sia un merge fast-forward, dai un'occhiata a &nbsp;<a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/#timetogethandson">questo post</a>). Come risultato, <code>main</code> e <code>paul_branch</code> ora puntano allo stesso commit:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-211.png" class="kg-image" alt="image-211" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-211.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-211.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-211.png 1168w" sizes="(min-width: 720px) 720px" width="1168" height="619" loading="lazy"><figcaption>Il risultato di un merge fast-forward (Fonte <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><h2 id="rebase-avanzato-in-git-">Rebase avanzato in Git💪🏻</h2><p>Ora che conosci le basi di rebase, è ora di prendere in considerazione casi più avanzati, laddove torneranno utili opzioni addizionali e argomenti per il comando <code>rebase</code>.</p><p>Nell'esempio precedente, quando hai usato <code>rebase</code> senza opzioni aggiuntive, Git ha replicato tutti i commit a partire dall'antenato comune fino all'inizio del branch corrente.</p><p>Ma rebase è potentissimo, è un comando possente in grado di riscrivere la cronologia e può tornare utile se vuoi modificare la cronologia e generarne una tua propria.</p><p>Annulla l'ultimo merge facendo puntare nuovamente <code>main</code> a "Commit 4":</p><pre><code>git reset -–hard &lt;COMMIT 4_ORIGINALE&gt;</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-238.png" class="kg-image" alt="image-238" width="590" height="322" loading="lazy"><figcaption>Annullamento dell'ultima operazione di merge (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Annulla anche il rebase in questo modo:</p><pre><code>git checkout paul_branch
git reset -–hard &lt;COMMIT 9_ORIGINALE&gt;</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-239.png" class="kg-image" alt="image-239" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-239.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-239.png 694w" width="694" height="367" loading="lazy"><figcaption>Annullamento dell'operazione di rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Nota che ora la cronologia è esattamente quella che avevi in precedenza:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-240.png" class="kg-image" alt="Visualizing the history after &quot;undoing&quot; the rebase operation (Source: Brief)" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-240.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-240.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-240.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-240.png 2323w" sizes="(min-width: 720px) 720px" width="2000" height="567" loading="lazy"><figcaption>Visualizzazione della cronologia dopo l'annullamento dell'operazione di rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)è&nbsp;</figcaption></figure><p>Giusto per essere chiari, "Commit 9" non sparisce semplicemente quando non è raggiungibile dall'<code>HEAD</code> corrente. Viceversa è ancora conservato nel database degli oggetti. Visto che hai usato <code>git reset</code> per fare in modo che <code>HEAD</code> punti a questo commit, sei in grado di recuperarlo, assieme ai suoi commit genitori visto che anch'essi sono conservati nel database. Non male, non è vero? 😎</p><p>Adesso diamo un veloce sguardo alle modifiche introdotte da Paul:</p><pre><code>git show HEAD</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-241.png" class="kg-image" alt="image-241" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-241.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-241.png 814w" sizes="(min-width: 720px) 720px" width="814" height="658" loading="lazy"><figcaption><code>git show HEAD</code> mostra le modifiche introdotte da "Commit 9" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Proseguiamo a ritroso nel grafico dei commit:</p><pre><code>git show HEAD~</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-242.png" class="kg-image" alt="image-242" width="589" height="723" loading="lazy"><figcaption><code>git show HEAD~</code> (uguale a <code>git show HEAD~1</code>) mostra le modifiche introdotte da "Commit 8" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Andiamo indietro di un altro commit:</p><pre><code>git show HEAD~2</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-243.png" class="kg-image" alt="image-243" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-243.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-243.png 636w" width="636" height="663" loading="lazy"><figcaption><code>git show HEAD~2</code> mostra le modifiche introdotte da "Commit 7" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Quindi, queste modifiche sono buone, ma forse Paul non vuole questo tipo di cronologia. Piuttosto vuole che sembri che le modifiche introdotte in &nbsp;"Commit 7" e "Commit 8" appaiano come un singolo commit.</p><p>Per fare questo, puoi usare un rebase <strong>interattivo</strong>, aggiungendo l'opzione <code>-i</code> (oppure <code>--interactive</code>) al comando <code>rebase</code> :</p><pre><code>git rebase -i &lt;SHA_DI_COMMIT_4&gt;</code></pre><p>Oppure, visto che <code>main</code> sta puntando a &nbsp;"Commit 4", possiamo semplicemente eseguire:</p><pre><code>git rebase -i main</code></pre><p>Eseguendo questo comando, dici a Git di usare una nuova base, "Commit 4". Pertanto stai chiedendo a Git di tornare a tutti i commit che sono stati introdotti dopo "Commit 4", che sono raggiungibili dall' <code>HEAD</code> corrente, e di replicarli.</p><p>Per ogni commit che viene replicato, Git ci chiede come vogliamo agire:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-250.png" class="kg-image" alt="image-250" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-250.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-250.png 994w" sizes="(min-width: 720px) 720px" width="994" height="738" loading="lazy"><figcaption><code>git rebase -i main</code> ti chiede di selezionare cosa deve essere fatto con ciascun commit (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>In questo contesto, è utile pensare a un commit come a una modifica. Vale a dire, &nbsp;"Commit 7" come fosse "la modifica che 'Commit 7' ha introdotto sopra il suo genitore".</p><p>Una opzione è usare <code>pick</code>. Questo è il comportamento predefinito, che dice a Git di replicare le modifiche introdotte in questo commit. In questo caso, non devi fare nulla e scegliere (<code>pick</code>) &nbsp;per tutti i commit – otterrai la stessa cronologia e Git non dovrà neppure creare dei nuovi oggetti commit.</p><p>Un'altra opzione è <code>squash</code>. Un commit si definisce <em>squashed (accorpato) </em>quando ha tutto il suo contenuto inserito nel commit precedente. Nel nostro caso Paul vorrebbe accorpare &nbsp;"Commit 8" in "Commit 7":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-251.png" class="kg-image" alt="image-251" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-251.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-251.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-251.png 1020w" sizes="(min-width: 720px) 720px" width="1020" height="641" loading="lazy"><figcaption>L'accorpamento di "Commit 8" in "Commit 7" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Come puoi vedere, &nbsp;<code>git rebase -i</code> fornisce opzioni aggiuntive, ma non le esamineremo tutte in questo post. Se provi ad eseguire il rebase, ti verrà richiesto di indicare un messaggio per il nuovo commit che sarà creato (vale a dire quello che introdurrà le modifiche sia di "Commit 7" che di "Commit 8"):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-252.png" class="kg-image" alt="image-252" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-252.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-252.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-252.png 1004w" sizes="(min-width: 720px) 720px" width="1004" height="680" loading="lazy"><figcaption>Inserimento del messaggio di commit: <code>Commits 7+8</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Dai un'occhiata alla cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-253.png" class="kg-image" alt="image-253" width="556" height="268" loading="lazy"><figcaption>La cronologia dopo il rebase interattivo (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Esattamente quello che volevamo! Abbiamo su <code>paul_branch</code> "Commit 9" (ovviamente un oggetto diverso rispetto al "Commit 9" originale). Questo punta a "Commits 7+8", che è un singolo commit che contiene le modifiche dei "Commit 7" e "Commit 8" originali. Il genitore di questi commit è &nbsp;"Commit 4", a cui sta puntando <code>main</code>, che è il genitore di <code>john_branch</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-254-1.png" class="kg-image" alt="image-254-1" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-254-1.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-254-1.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-254-1.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-254-1.png 2219w" sizes="(min-width: 720px) 720px" width="2219" height="615" loading="lazy"><figcaption>La cronologia dopo il rebase interattivo - visualizzata (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Wow, forte, non è vero? 😎</p><p><code>git rebase</code> ti consente controllo illimitato sulla forma di qualsiasi branch. Puoi usarlo per riordinare i commit, oppure per rimuovere modifiche non corrette, o cambiare una modifica in retrospettiva. In alternativa, potresti spostare la base del tuo branch in un altro commit di tua scelta.</p><h2 id="come-usare-l-opzione-di-switch-onto-di-git-rebase"><strong>Come usare l'opzione di s<strong>witch <code>--onto</code> </strong>di<strong> <code>git rebase</code></strong></strong></h2><p>Consideriamo un altro esempio. Andiamo su <code>main</code> nuovamente:</p><pre><code>git checkout main</code></pre><p>Eliminiamo i puntatori a <code>paul_branch</code> e <code>john_branch</code> in modo che non compaiono più nel grafico della cronologia:</p><pre><code>git branch -D paul_branch
git branch -D john_branch</code></pre><p>Ora generiamo un nuovo branch da <code>main</code> e ci spostiamo su di esso:</p><pre><code>git checkout -b new_branch</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-255-1.png" class="kg-image" alt="image-255-1" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-255-1.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-255-1.png 634w" width="634" height="202" loading="lazy"><figcaption>Creazione di <code>new_branch</code> che si dirama da <code>main</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-256.png" class="kg-image" alt="image-256" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-256.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-256.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-256.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-256.png 1601w" sizes="(min-width: 720px) 720px" width="1601" height="814" loading="lazy"><figcaption>Una cronologia pulita per <code>new_branch</code> che si dirama da <code>main</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)&nbsp;</figcaption></figure><p>Ora facciamo qualche modifica ed eseguiamo il commit:</p><pre><code>nano code.py</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-257.png" class="kg-image" alt="image-257" width="588" height="328" loading="lazy"><figcaption>Aggiunta della funzione <code>new_branch</code> a <code>code.py</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><pre><code>git add code.py
git commit -m "Commit 10"</code></pre><p>Torniamo su <code>main</code>:</p><pre><code>git checkout main</code></pre><p>Poi introduciamo una modifica:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-258.png" class="kg-image" alt="image-258" width="588" height="331" loading="lazy"><figcaption>Aggiunta una docstring (stringa di documentazione in Python) all'inizio del file (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Adesso eseguiamo il commit queste modifiche:</p><pre><code>git add code.py
git commit -m "Commit 11"</code></pre><p>Poi effettuiamo un altro cambiamento:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-259.png" class="kg-image" alt="image-259" width="587" height="380" loading="lazy"><figcaption>Aggiunto <code>@Author</code> alla docstring (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Eseguiamo il commit anche di questa modifica:</p><pre><code>git add code.py
git commit -m "Commit 12"</code></pre><p>Aspetta, ora mi sono reso conto che avrei voluto apportare le modifiche introdotte nel "Commit 11" in <code>new_branch</code>. Che si può fare adesso? 🤔</p><p>Esaminiamo la cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-260.png" class="kg-image" alt="image-260" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-260.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-260.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-260.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-260.png 1613w" sizes="(min-width: 720px) 720px" width="1613" height="798" loading="lazy"><figcaption>La cronologia dopo l'introduzione di "Commit 12" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Quello che voglio è che invece di avere "Commit 10" situato solo sul branch &nbsp;<code>main</code>, sia anche in <code>new_branch</code>. Visivamente, vorrei spostarlo in fondo al grafico mostrato qui sotto:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-261.png" class="kg-image" alt="image-261" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-261.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-261.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-261.png 1578w" sizes="(min-width: 720px) 720px" width="1578" height="559" loading="lazy"><figcaption>Visivamente, vorrei che tu inglobassi (<code>git push</code>) il "Commit 10" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Riesci a vedere dove voglio arrivare? 😇</p><p>Bene, come sappiamo rebase ci consente in pratica di <em>replicare</em> le modifiche introdotte in <code>new_branch</code>, quelle del "Commit 10", &nbsp;come se in origine fossero state apportate in "Commit 11" invece che in "Commit 4".</p><p>Per fare questo, puoi usare altri argomenti di <code>git rebase</code>. Dovresti dire a Git che vuoi prendere tutta la cronologia introdotta tra l'antenato comune di <code>main</code> e <code>new_branch</code>, che sarebbe "Commit 4", e fare in modo che la nuova base per quella cronologia sia "Commit 11". Per farlo usa:</p><pre><code>git rebase -–onto &lt;SHA_DI_COMMIT_11&gt; main new_branch</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-262.png" class="kg-image" alt="image-262" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-262.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-262.png 812w" sizes="(min-width: 720px) 720px" width="812" height="565" loading="lazy"><figcaption>La cronologia prima e dopo il rebase, "Commit 10" è stato inserito in <code>new_branch</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)&nbsp;</figcaption></figure><p>Ora dai uno sguardo alla nostra meravigliosa cronologia! 😍</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-263.png" class="kg-image" alt="image-263" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-263.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-263.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-263.png 1579w" sizes="(min-width: 720px) 720px" width="1579" height="552" loading="lazy"><figcaption>La cronologia prima e dopo il rebase, "Commit 10" è stato inserito in <code>new_branch</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Consideriamo un altro caso.</p><p>Diciamo che ho iniziato a lavorare su un branch e per errore ho iniziato a lavorare da <code>feature_branch_1</code>, invece che da <code>main</code>.</p><p>Per emulare questa situazione crea <code>feature_branch_1</code>:</p><pre><code>git checkout main
git checkout -b feature_branch_1</code></pre><p>Poi elimina <code>new_branch</code> così che non appaia più nel grafico della cronologia:</p><pre><code>git branch -D new_branch</code></pre><p>Crea un semplice file Python chiamato <code>1.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-264.png" class="kg-image" alt="image-264" width="581" height="80" loading="lazy"><figcaption>Un nuovo file, <code>1.py</code>, con <code>print("Hello World!")</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Aggiungi a Git questo file ed esegui il commit:</p><pre><code>git add 1.py
git commit -m  "Commit 13"</code></pre><p>Ora esci (per errore) da <code>feature_branch_1</code> ed entra in un nuovo branch (<code>feature_branch_2</code>):</p><pre><code>git checkout -b feature_branch_2</code></pre><p>Poi crea un altro file, <code>2.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-265.png" class="kg-image" alt="image-265" width="561" height="90" loading="lazy"><figcaption>Creazione di <code>2.py</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Aggiungi anche questo file ed esegui il commit:</p><pre><code>git add 2.py
git commit -m  "Commit 14"</code></pre><p>Poi inserisci dell'altro codice a <code>2.py</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-266.png" class="kg-image" alt="image-266" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-266.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-266.png 995w" sizes="(min-width: 720px) 720px" width="995" height="134" loading="lazy"><figcaption>Modifica del file <code>2.py</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Fai il commit anche di queste modifiche:</p><pre><code>git add 2.py
git commit -m  "Commit 15"</code></pre><p>Fino ad ora dovresti avere questa cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-267.png" class="kg-image" alt="image-267" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-267.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-267.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-267.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-267.png 2050w" sizes="(min-width: 720px) 720px" width="2050" height="572" loading="lazy"><figcaption>La cronologia dopo l'introduzione di "Commit 15" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ritorna su <code>feature_branch_1</code> e modifica <code>1.py</code>:</p><pre><code>git checkout feature_branch_1</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-268.png" class="kg-image" alt="image-268" width="563" height="84" loading="lazy"><figcaption>Modifica di <code>1.py</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Fai il commit del file modificato:</p><pre><code>git add 1.py
git commit -m  "Commit 16"</code></pre><p>La tua cronologia dovrebbe essere questa:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-270.png" class="kg-image" alt="image-270" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-270.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-270.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-270.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-270.png 2080w" sizes="(min-width: 720px) 720px" width="2080" height="573" loading="lazy"><figcaption>La cronologia dopo l'introduzione di "Commit 16" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Diciamo che ora ti rendi conto di avere fatto un errore. In realtà avresti voluto far nascere <code>feature_branch_2</code> da <code>main</code>, invece che da <code>feature_branch_1</code>.</p><p>Come puoi rimediare? 🤔</p><p>Prova a pensarci tenendo conto del grafico della cronologia e di quello che hai imparato fino ad ora sull'opzione <code>--onto</code> per il comando <code>rebase</code> </p><p>Bene, vuoi "sostituire" il genitore del tuo primo commit su <code>feature_branch_2</code>, che è "Commit 14", in modo che sia alla sommità del branch <code>main</code> , in questo caso "Commit 12", invece che all'inizio di <code>feature_branch_1</code>, in questo caso "Commit 13". Pertanto, ancora una volta, andrai a creare una <em>nuova base, </em>questa volta per il primo commit su <code>feature_branch_2</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-271.png" class="kg-image" alt="image-271" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-271.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-271.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-271.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-271.png 2039w" sizes="(min-width: 720px) 720px" width="2039" height="570" loading="lazy"><figcaption>Vuoi spostare "Commit 14" e "Commit 15" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Come faresti?</p><p>Per prima cosa portati su <code>feature_branch_2</code>:</p><pre><code>git checkout feature_branch_2</code></pre><p>Da qui puoi usare:</p><pre><code>git rebase -–onto main &lt;SHA_DI_COMMIT_13&gt;</code></pre><p> Come risultato avrai <code>feature_branch_2</code> con base su <code>main</code> invece che su <code>feature_branch_1</code>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-272.png" class="kg-image" alt="image-272" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-272.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-272.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-272.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-272.png 2049w" sizes="(min-width: 720px) 720px" width="2049" height="567" loading="lazy"><figcaption>La cronologia dei commit dopo il rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>La sintassi del comando è:</p><pre><code>git rebase --onto &lt;nuovo_genitore&gt; &lt;vecchio_genitore&gt;</code></pre><h2 id="come-effettuare-il-rebase-su-un-singolo-branch"><strong>Come effettuare il rebase su un singolo branch</strong></h2><p>Puoi anche usare <code>git rebase</code> in relazione alla cronologia di un singolo branch.</p><p>Vediamo se mi puoi aiutare.</p><p>Diciamo che ho lavorato da <code>feature_branch_2</code>, e nello specifico ho modificato il file <code>code.py</code>. Ho iniziato modificando gli apici singoli che racchiudono le stringhe in apici doppi:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-273.png" class="kg-image" alt="image-273" width="588" height="382" loading="lazy"><figcaption>Modifica di <code>'</code> in <code>"</code> nel file <code>code.py</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Poi ho eseguito il commit delle modifiche:</p><pre><code>git add code.py
git commit -m "Commit 17"</code></pre><p>Quindi ho deciso di aggiungere una nuova funzione all'inizio del file:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-274.png" class="kg-image" alt="image-274" width="590" height="423" loading="lazy"><figcaption>Inserimento della funzione <code>another_feature</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ho nuovamente portato nell'area di stage <code>code.py</code> ed eseguito il commit:</p><pre><code>git add code.py
git commit -m "Commit 18"</code></pre><p>Ora mi sono reso conto che mi sono dimenticato di cambiare gli apici che racchiudono l'istruzione &nbsp;<code>__main__</code> da singoli a doppi (come potresti aver notato), pertanto ho fatto anche questo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-275.png" class="kg-image" alt="image-275" width="599" height="446" loading="lazy"><figcaption>Modificato <code>'__main__'</code> in <code>"__main__"</code> (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Naturalmente ho eseguito il commit anche di questa modifica:</p><pre><code>git add code.py
git commit -m "Commit 19"</code></pre><p>Ora esamina la cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-276.png" class="kg-image" alt="image-276" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-276.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-276.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-276.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-276.png 2055w" sizes="(min-width: 720px) 720px" width="2055" height="593" loading="lazy"><figcaption>La cronologia di commit dopo l'introduzione di "Commit 19" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Non è molto bella, giusto? Voglio dire, ho due commit (in relazione tra loro), "Commit 17" e "Commit 19" (sostituzione di <code>'</code> con &nbsp;<code>"</code>), ma sono separati l'uno dall'altro da un "Commit 18" che non ha niente a che vedere con quelli (ho aggiunto una nuova funzione). Cosa posso fare? 🤔 Puoi aiutarmi?</p><p>Andando a intuito, voglio modificare la cronologia qui:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-277.png" class="kg-image" alt="image-277" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-277.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-277.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-277.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-277.png 2058w" sizes="(min-width: 720px) 720px" width="2058" height="561" loading="lazy"><figcaption>Questi sono i commit che voglio modificare (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Quindi, cosa dovrei fare?</p><p>Hai ragione! 👏🏻</p><p>Posso eseguire il rebase della cronologia da &nbsp;"Commit 17" a "Commit 19", sopra il "Commit 15". Per fare questo:</p><pre><code>git rebase --interactive --onto &lt;SHA_DI_COMMIT_15&gt; &lt;SHA_DI_COMMIT_15&gt;</code></pre><p>Nota che ho specificato "Commit 15" come inizio del gruppo di commit, escludendo questo commit. Non ho avuto bisogno di specificare &nbsp;<code>HEAD</code> come ultimo parametro.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-279.png" class="kg-image" alt="image-279" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-279.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-279.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-279.png 1023w" sizes="(min-width: 720px) 720px" width="1023" height="391" loading="lazy"><figcaption>Uso di <code>rebase --onto</code> su un singolo branch (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Dopo aver seguito il tuo consiglio ed eseguito il comando <code>rebase</code> &nbsp;(grazie! 😇) mi viene presentata la seguente schermata:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-280.png" class="kg-image" alt="image-280" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-280.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-280.png 904w" sizes="(min-width: 720px) 720px" width="904" height="638" loading="lazy"><figcaption>Rebase interattivo (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Quindi cosa dovrei fare? Voglio inserire "Commit 19" <em>prima di</em> "Commit 18", in modo che venga appena dopo "Commit 17". Posso proseguire e accorparli, in questo modo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-281.png" class="kg-image" alt="image-281" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-281.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-281.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-281.png 1010w" sizes="(min-width: 720px) 720px" width="1010" height="396" loading="lazy"><figcaption>Rebase interattivo - modifica dell'ordine dei commit e accorpamento (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ora quando mi viene richiesto di inserire un messaggio per il commit, posso indicare &nbsp;"Commit 17+19":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-282.png" class="kg-image" alt="image-282" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-282.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-282.png 799w" sizes="(min-width: 720px) 720px" width="799" height="393" loading="lazy"><figcaption>Inserimento di un messaggio per il nuovo commit (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ora guardiamo la nostra stupenda cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-283.png" class="kg-image" alt="image-283" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-283.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-283.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-283.png 1030w" sizes="(min-width: 720px) 720px" width="1030" height="493" loading="lazy"><figcaption>La cronologia risultante (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Grazie ancora! 🙌🏻</p><h2 id="altri-casi-d-uso-per-rebase-altri-esercizi">Altri casi d'uso per rebase + altri esercizi</h2><p>A questo punto, spero tu sia a tuo agio con la sintassi di rebase. Il modo migliore per comprenderla veramente è considerare varie situazioni e cercare di risolverle da solo.</p><p>Per quanto riguarda i casi d'uso che andrò a presentare, ti suggerisco vivamente di interrompere la lettura dopo che ho introdotto ciascun caso e cercare di risolverlo autonomamente.</p><h3 id="come-escludere-commit">Come escludere commit</h3><p>Ipotizziamo che in un altro repository tu abbia questa cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-284.png" class="kg-image" alt="image-284" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-284.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-284.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-284.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-284.png 2000w" sizes="(min-width: 720px) 720px" width="2000" height="438" loading="lazy"><figcaption>Un'altra cronologia di commit (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Prima di iniziare a sperimentare, inserisci un etichetta (tag) per "Commit F", in modo che tu possa poi tornarci più tardi:</p><pre><code>git tag original_commit_f</code></pre><p>In realtà non vuoi includere le modifiche in "Commit C" e "Commit D". Potresti usare un rebase interattivo come prima ed eliminare quelle modifiche, oppure potresti nuovamente usare &nbsp;<code>git rebase -–onto</code>. In che modo useresti l'opzione <code>--onto</code> per "rimuovere" quei due commit?</p><p>Puoi portare la base di &nbsp;<code>HEAD</code> sopra a &nbsp;"Commit B", dove il vecchio genitore era in realtà "Commit D", e ora dovrebbe essere "Commit B". Esamina nuovamente la cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-284--1-.png" class="kg-image" alt="image-284--1-" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-284--1-.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-284--1-.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-284--1-.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-284--1-.png 2000w" sizes="(min-width: 720px) 720px" width="2000" height="438" loading="lazy"><figcaption>Di nuovo la cronologia (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Effettuare il rebase in modo che "Commit B" costituisca la base di "Commit E", significa "spostare" sia "Commit E" che "Commit F", e dargli un'altra <em>base </em>– "Commit B". Puoi comporre da solo il comando per fare questo?</p><pre><code>git rebase --onto &lt;SHA_DI_COMMIT_B&gt; &lt;SHA_OF_COMMIT_D&gt; HEAD</code></pre><p>Nota che usando la sintassi qui sopra non viene spostato <code>main</code> per puntare al nuovo commit, pertanto il risultato è un <code>HEAD</code> staccato. Se usi <code>gg</code> (git-graph) o un altro strumento che visualizza la cronologia raggiungibile dai branch potresti essere confuso:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-285.png" class="kg-image" alt="image-285" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-285.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-285.png 859w" sizes="(min-width: 720px) 720px" width="859" height="462" loading="lazy"><figcaption>Il rebase con <code>--onto</code> risulta in un <code>HEAD</code> staccato (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Tuttavia se usi semplicemente <code>git log</code> (oppure il mio alias <code>git lol</code>), vedrai la cronologia desiderata:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-286--1-.png" class="kg-image" alt="image-286--1-" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-286--1-.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-286--1-.png 740w" sizes="(min-width: 720px) 720px" width="740" height="136" loading="lazy"><figcaption>La cronologia risultante (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Non so tu come la pensi, ma questo tipo di cose mi fanno davvero felice. 😊😇</p><p>A proposito, potresti omettere <code>HEAD</code> dal comando precedente poiché questo è il valore predefinito per il terzo parametro. Quindi usando solo:</p><pre><code>git rebase --onto &lt;SHA_DI_COMMIT_B&gt; &lt;SHA_DI_COMMIT_D&gt;</code></pre><p>otterresti lo stesso risultato. L'ultimo parametro in effetti dice a Git dove si trova la fine della sequenza corrente di commit per i quali effettuare il rebase. Quindi la sintassi <code>git rebase --onto</code> con tre argomenti è:</p><pre><code>git rebase --onto &lt;nuovo_genitore&gt; &lt;vecchio_genitore&gt; &lt;fino_a&gt;</code></pre><h3 id="come-spostare-commit-tra-branch">Come spostare commit tra branch</h3><p>Diciamo di avere la stessa cronologia di prima, alla quale torniamo usando il tag applicato nella sezione precedente:</p><pre><code>git checkout original_commit_f</code></pre><p>Ora voglio che solo "Commit E", sia in un branch basato su "Commit B". Vale a dire, voglio avere un nuovo branch, che si dirama da "Commit B", con solo "Commit E".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-287.png" class="kg-image" alt="image-287" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-287.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-287.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-287.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-287.png 2000w" sizes="(min-width: 720px) 720px" width="2000" height="590" loading="lazy"><figcaption>La cronologia corrente, considerando "Commit E" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)&nbsp;</figcaption></figure><p>Quindi, cosa significa questo in termini di rebase? Osserva l'immagine qui sopra. Quale commit (o quali) dovrebbero essere oggetto di rebase, e quale commit dovrebbe costituire la nuova base?</p><p>So che posso contare su di te qui 😉</p><p>Quello che voglio è prendere "Commit E", e solo questo commit, e modificare la sua base in &nbsp;"Commit B". In altre parole, <em>replicare</em> le modifiche introdotte in "Commit E" su "Commit B".</p><p>Puoi applicare questa logica alla sintassi di <code>git rebase</code>?</p><p>Eccola (questa volta scrivo <code>&lt;COMMIT_B&gt;</code> invece di <code>&lt;SHA_DI_COMMIT_B&gt;</code>, per brevità):</p><pre><code>git rebase –-onto &lt;COMMIT_B&gt; &lt;COMMIT_D&gt; &lt;COMMIT_E&gt;</code></pre><p>Ora la cronologia risulta questa:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-288.png" class="kg-image" alt="image-288" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-288.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-288.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-288.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-288.png 2000w" sizes="(min-width: 720px) 720px" width="2000" height="572" loading="lazy"><figcaption>La cronologia dopo il rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Meraviglioso!</p><h2 id="una-nota-sui-conflitti">Una nota sui conflitti</h2><p>Nota che quando esegui un rebase, potresti imbatterti in conflitti, come se stessi facendo un'azione di integrazione con merge. Potresti avere conflitti perché quando si esegue il rebase, stai cercando di applicare modifiche su una base diversa, nella quale forse le modifiche non si applicano.</p><p>Per esempio prendi di nuovo il repository precedente e in particolare esamina le modifiche introdotte nel "Commit 12", puntato da <code>main</code>:</p><pre><code>git show main</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-289.png" class="kg-image" alt="image-289" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-289.png 600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-289.png 714w" width="714" height="453" loading="lazy"><figcaption>Le modifiche introdotte da "Commit 12" (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ho già trattato il formato di <code>git diff</code> in dettaglio <a href="https://www.freecodecamp.org/news/git-diff-and-patch/">in un post precedente</a>, ma come veloce ripasso questo commit dice a Git di aggiungere una riga dopo le due righe:</p><pre><code>```
This is a sample file</code></pre><p>e prima di queste tre righe:</p><pre><code>```
def new_feature():
  print('new feature')</code></pre><p>Supponiamo che tu stia tentando di effettuare un rebase di "Commit 12" su un altro commit. Se, per qualche motivo, queste righe non esistono come nella patch sul commit <em>verso il quale</em> stai effettuando il rebase, allora avrai un conflitto. Per saperne di più sui conflitti e su come risolverli, consulta <a href="https://www.freecodecamp.org/news/the-definitive-guide-to-git-merge/">questa guida</a>.</p><h2 id="la-prospettiva-dal-quadro-generale">La prospettiva dal quadro generale</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/tabella-merge-rebase.png" class="kg-image" alt="tabella-merge-rebase" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/tabella-merge-rebase.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/tabella-merge-rebase.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/tabella-merge-rebase.png 1526w" sizes="(min-width: 720px) 720px" width="1526" height="526" loading="lazy"><figcaption>Confronto fra rebase e merge (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>All'inizio di questa guida, ho iniziato citando le similitudini tra <code>git merge</code> e <code>git rebase</code>: entrambi sono usati per integrare modifiche introdotte in diverse cronologie.</p><p>Tuttavia, come ora sai, le modalità con le quali operano sono molto diverse. Con merge l'integrazione ha come risultato cronologie divergenti, con rebase la cronologia risultante è lineare. I conflitti sono possibili in entrambi i casi. C'è un'ulteriore colonna nella tabella qui sopra (la terza) che richiede una particolare attenzione.</p><p>Ora che sai cos'è <code>git rebase</code> e come usare il rebase interattivo oppure &nbsp;<code>rebase --onto</code>, spero che tu sia d'accordo con me nell'affermare che <code>git rebase</code> sia uno strumento potentissimo. Tuttavia ha un grosso inconveniente se confrontato con l'integrazione via merge.</p><p>Git rebase modifica la cronologia.</p><p>Ciò significa che <strong>non</strong> dovresti effettuare il rebase di commit che si trovano al di fuori della tua copia locale del repository, sul quali altre persone potrebbero aver basato i loro commit.</p><p>In altre parole, se i commit in oggetto sono solo quelli che tu hai creato localmente, vai pure avanti, usa rebase, scatenati.</p><p>Ma se i commit sono stati portati sul repository remoto, si può generare un grosso problema, visto che qualcun altro potrebbe fare affidamento su questi commit, che tu più tardi hai sovrascritto, pertanto tu e gli altri avrete versioni diverse del repository.</p><p>Questo è improbabile avvenga con <code>merge</code> in quanto, come abbiamo visto, non modifica la cronologia.</p><p>Considera ad esempio l'ultimo caso nel quale abbiamo effettuato un rebase che ha generato questa cronologia:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/image-288--1-.png" class="kg-image" alt="image-288--1-" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/image-288--1-.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/image-288--1-.png 1000w, https://www.freecodecamp.org/italian/news/content/images/size/w1600/2023/07/image-288--1-.png 1600w, https://www.freecodecamp.org/italian/news/content/images/2023/07/image-288--1-.png 2000w" sizes="(min-width: 720px) 720px" width="2000" height="572" loading="lazy"><figcaption>La cronologia dopo il rebase (Fonte: <a href="https://youtu.be/3VFsitGUB3s">Brief</a>)</figcaption></figure><p>Ora, supponi che io abbia già portato questo branch nel repository remoto con <code>git push</code>, e dopo aver fatto questo, un altro sviluppatore abbia scaricato il repository derivandolo da "Commit C". L'altro sviluppatore non sa che, nel frattempo, io avevo effettuato localmente il rebase del mio branch e l'avevo successivamente inviato nuovamente al repository remoto.</p><p>Ne deriva un'inconsistenza: l'altro sviluppatore lavora da un commit che non è più disponibile sulla mia copia del repository.</p><p>Non approfondirò le conseguenze esatte di quanto esposto qui sopra in questa guida, visto che il mio messaggio principale è che dovresti evitare assolutamente queste situazioni. Se ti interessa sapere cosa sarebbe veramente accaduto, ti lascio un link a un'utile risorsa qui sotto. Per ora riepiloghiamo quanto abbiamo trattato.</p><h2 id="riepilogo">Riepilogo</h2><p>In questo tutorial, hai appreso il comando <code>git rebase</code>, uno strumento potentissimo per riscrivere la cronologia in Git. Hai preso in considerazione alcune situazioni dove <code>git rebase</code> può essere di aiuto, e come usarlo con uno, due o tre parametri, con e senza l'opzione <code>--onto</code>.</p><p>Spero di essere stato in grado di convincerti che <code>git rebase</code> è potente, tuttavia è piuttosto semplice una volta che hai capito il concetto. È uno strumento per "copiare-incollare" i commit (o più precisamente, le modifiche), ed è utile da avere a tua disposizione.</p><h2 id="riferimenti-aggiuntivi">Riferimenti aggiuntivi </h2><ul><li><a href="https://www.youtube.com/playlist?list=PL9lx0DXCC4BNUby5H58y6s2TQVLadV8v7" rel="noopener">Git Internals YouTube playlist — by Brief</a> (il mio canale YouTube).</li><li><a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/">Un mio post precedente sui meccanismi interni di Git.</a></li><li><a href="https://medium.com/@Omer_Rosenbaum/git-undo-how-to-rewrite-git-history-with-confidence-d4452e2969c2">Un mio tutorial su Git UNDO - riscrivere la cronologia con Git</a>.</li><li><a href="https://git-scm.com/book/en/v2/Git-Branching-Rebasing">Documentazione di Git su rebase</a></li><li><a href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/7-branching-and-the-power-of-rebase.html">Branch e la potenza di rebase</a></li><li><a href="https://jwiegley.github.io/git-from-the-bottom-up/1-Repository/8-interactive-rebasing.html">Rebase interattivo</a></li><li><a href="https://womanonrails.com/git-rebase-onto">Git rebase --onto</a></li></ul><h2 id="notizie-sull-autore">Notizie sull'autore</h2><p><a href="https://www.linkedin.com/in/omer-rosenbaum-034a08b9/">Omer Rosenbaum</a> è Chief Technology Officer per <a href="https://swimm.io/">Swimm</a> . È l'autore &nbsp;del <a href="https://youtube.com/@BriefVid">canale YouTube Brief</a>. È anche un esperto di cyber training e fondatore della Checkpoint Security Academy. È l'autore di <a href="https://data.cyber.org.il/networks/networks.pdf" rel="noopener nofollow noopener noopener">Computer Networks (in Ebraico)</a>. Lo puoi trovare su <a href="https://twitter.com/Omer_Ros">Twitter</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Imparare JavaScript per Principianti – Il Manuale delle Basi di JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ L'obiettivo di questo manuale è di introdurti rapidamente alle basi di JavaScript in modo che tu possa iniziare a programmare applicazioni. Invece di coprire tutte le teorie e i concetti di JavaScript, ti insegnerò solo gli elementi costitutivi più importanti del linguaggio. Tratteremo cose come variabili, tipi di dato, funzioni, ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/imparare-javascript-per-principianti-il-manuale-delle-basi-di-javascript/</link>
                <guid isPermaLink="false">64aadb5caedaa5069ba9716c</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Tue, 25 Jul 2023 09:09:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/07/book-cover.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/learn-javascript-for-beginners/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Learn JavaScript for Beginners – JS Basics Handbook</a>
      </p><p>L'obiettivo di questo manuale è di introdurti rapidamente alle basi di JavaScript in modo che tu possa iniziare a programmare applicazioni.</p><p>Invece di coprire tutte le teorie e i concetti di JavaScript, ti insegnerò solo gli elementi costitutivi più importanti del linguaggio. Tratteremo cose come variabili, tipi di dato, funzioni, oggetti, e array. Imparerai anche come combinarli tra loro per creare un programma, piccolo ma solido.</p><p>Tralasceremo anche HTML, CSS e l'utilizzo di JavaScript nel browser. Questo tutorial si concentra solo su JavaScript come linguaggio di programmazione e utilizza il terminale per eseguire il codice.</p><p>Questo tutorial ha anche degli esercizi alla fine di alcuni capitoli che ti danno il tempo di mettere in pratica ciò che hai imparato e "assorbire" i nuovi concetti.</p><p>Questo manuale è completamente gratuito proprio qui in questa pagina web. Se desideri <a href="https://codewithnathan.com/js-course">la versione PDF ed EPUB di questo tutorial</a> (in lingua inglese - n.d.t.), puoi pagare una piccola somma. Contribuirai a supportarmi nella creazione di un tutorial JavaScript approfondito che ti aiuterà a creare un'applicazione web completa.</p><h2 id="sommario"><strong>Sommario</strong></h2><!--kg-card-begin: markdown--><ul>
<li><a href="#1-introduzione-a-javascript">1 - Introduzione a Javascript</a>
<ul>
<li><a href="#1-1-perche-imparare-javascript">1.1 - Perché imparare Javascript?</a></li>
<li><a href="#1-2-javascript-vs-java">1.2 - Javascript vs. Java</a></li>
</ul>
</li>
<li><a href="#2-come-preparare-il-tuo-computer">2 - Come preparare il tuo computer</a>
<ul>
<li><a href="#2-1-come-installare-vscode">2.1 - Come installare VSCode</a></li>
<li><a href="#2-2-come-installare-node-js">2.2 - Come installare Node.js</a></li>
</ul>
</li>
<li><a href="#3-breve-introduzione-alla-console">3 - Breve introduzione alla console</a></li>
<li><a href="#4-e-ora-di-dire-hello-world">4 - È ora di dire Hello World!</a></li>
<li><a href="#5-struttura-del-codice">5 - Struttura del codice</a>
<ul>
<li><a href="#5-1-istruzioni">5.1 - Istruzioni</a></li>
<li><a href="#5-2-commenti">5.2 - Commenti</a></li>
<li><a href="#5-3-flusso-di-esecuzione">5.3 - Flusso di esecuzione</a></li>
<li><a href="#5-4-esercizio-nr-1">5-4 - Esercizio nr. 1</a></li>
</ul>
</li>
<li><a href="#6-variabili">6 - Variabili</a>
<ul>
<li><a href="#6-1-denominazione">6.1 - Denominazione</a></li>
<li><a href="#6-2-il-tipo-di-variabile-const">6.2 - Il tipo di variabile const</a></li>
<li><a href="#6-3-il-tipo-di-variabile-var">6.3 - Il tipo di variabile var</a></li>
<li><a href="#6-4-esercizio-nr-2">6.4 - Esercizio nr. 2</a></li>
</ul>
</li>
<li><a href="#7-tipi-di-dato-base">7 - Tipi di dato base</a>
<ul>
<li><a href="#7-1-stringhe">7.1 - Stringhe</a></li>
<li><a href="#7-2-numeri-interi-e-con-virgola-mobile">7.2 - Numeri (interi e con virgola mobile)</a></li>
<li><a href="#7-3-booleani">7.3 - Booleani</a></li>
<li><a href="#7-4-undefined">7.4 - undefined</a></li>
<li><a href="#7-5-null">7.5 - null</a></li>
</ul>
</li>
<li><a href="#8-conversione-di-tipo-e-coercizione-di-tipo">8 - Conversione di tipo e coercizione di tipo </a>
<ul>
<li><a href="#8-1-coercizione-di-tipo">8.1 - Coercizione di tipo</a>
<ul>
<li><a href="#8-1-1-regole-della-coercizione-di-tipo">8.1.1 - Regole della coercizione di tipo</a></li>
<li><a href="#8-1-2-perche-dovresti-evitare-la-coercizione-di-tipo">8.1.2 - Perchè dovresti evitare la coercizione di tipo</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#9-operatori">9 - Operatori </a>
<ul>
<li><a href="#9-1-operatori-aritmetici">9.1 - Operatori aritmetici</a></li>
<li><a href="#9-2-operatori-di-assegnazione">9.2 - Operatori di assegnazione</a></li>
<li><a href="#9-3-operatori-di-confronto">9.3 - Operatori di confronto</a></li>
<li><a href="#9-4-operatori-logici">9.4 - Operatori logici</a></li>
<li><a href="#9-5-operatore-typeof">9.5 - Operatore typeof</a></li>
<li><a href="#9-6-esercizio-nr-3">9.6 - Esercizio nr. 3</a></li>
</ul>
</li>
<li><a href="#10-array">10 - Array </a>
<ul>
<li><a href="#10-1-posizione-dell-indice">10.1 - Posizione dell'indice</a></li>
<li><a href="#10-2-metodi-speciali-di-manipolazione">10.2 - Metodi speciali di manipolazione</a></li>
<li><a href="#10-3-esercizio-nr-4">10.3 - Esercizio nr. 4</a></li>
</ul>
</li>
<li><a href="#11-flussi-di-controllo-condizionali">11 - Flussi di controllo (condizionali) </a>
<ul>
<li><a href="#11-1-istruzione-if-else">11.1 - Istruzione if...else</a></li>
<li><a href="#11-2-istruzione-switch-case">11.2 - Istruzione switch...case</a></li>
<li><a href="#11-3-corpo-dell-istruzione-switch-case">11.3 - Corpo dell'istruzione switch...case</a></li>
<li><a href="#11-4-casi-d-uso-dell-istruzione-switch-case">11.4 - Casi d'uso dell'istruzione switch...case</a></li>
<li><a href="#11-5-esercizio-nr-5">11.5 - Esercizio nr. 5</a></li>
</ul>
</li>
<li><a href="#12-flussi-di-controllo-cicli">12 - Flussi di controllo (cicli) </a>
<ul>
<li><a href="#12-1-istruzione-for">12.1 - Istruzione for</a></li>
<li><a href="#12-2-quando-usare-un-ciclo-for">12.2 - Quando usare un ciclo for</a></li>
<li><a href="#12-3-istruzione-while">12.3 - Istruzione while</a></li>
<li><a href="#12-4-quando-usare-un-ciclo-while">12.4 - Quando usare un ciclo while</a></li>
<li><a href="#12-5-esercizio-nr-6">12.5 - Esercizio nr. 6</a></li>
</ul>
</li>
<li><a href="#13-funzioni">13 - Funzioni</a>
<ul>
<li><a href="#13-1-come-creare-la-tua-funzione">13.1 - Come creare la tua funzione</a></li>
<li><a href="#13-2-parametri-e-argomenti-della-funzione">13.2 - Parametri e argomenti della funzione</a></li>
<li><a href="#13-3-parametri-predefiniti">13.3 - Parametri predefiniti</a></li>
<li><a href="#13-4-parametri-predefiniti-e-null">13.4 - Parametri predefiniti e null</a></li>
<li><a href="#13-5-istruzione-return">13.5 - Istruzione return</a></li>
<li><a href="#13-6-ambito-di-una-variabile">13.6 - Ambito di una variabile</a></li>
<li><a href="#13-7-parametro-rest">13.7 - Parametro rest</a></li>
<li><a href="#13-8-funzione-freccia">13.8 - Funzione freccia</a></li>
<li><a href="#13-9-funzioni-freccia-su-singola-riga-o-pi%C3%B9-righe">13.9 - Funzioni freccia su singola riga o più righe</a></li>
<li><a href="#13-10-funzione-freccia-senza-parentesi-tonde">13.10 - Funzione freccia senza parentesi tonde</a></li>
<li><a href="#13-11-la-funzione-freccia-non-ha-associazione-con-arguments">13.11 - La funzione freccia non ha associazione con arguments</a></li>
<li><a href="#13-12-convertire-facilmente-una-funzione-normale-in-funzione-freccia">13.12 - Convertire facilmente una funzione normale in funzione freccia</a></li>
<li><a href="#13-13-esercizio-nr-7">13.13 - Esercizio nr. 7</a></li>
</ul>
</li>
<li><a href="#14-oggetti">14 - Oggetti</a>
<ul>
<li><a href="#14-1-accedere-ai-valori">14.1 - Accedere ai valori</a></li>
<li><a href="#14-2-aggiungere-una-nuova-proprieta">14.2 - Aggiungere una nuova proprietà</a></li>
<li><a href="#14-3-modificare-una-proprieta">14.3 - Modificare una proprietà</a></li>
<li><a href="#14-4-eliminare-una-proprieta">14.4 - Eliminare una proprietà</a></li>
<li><a href="#14-5-verificare-se-esiste-una-proprieta">14.5 - Verificare se esiste una proprietà</a></li>
<li><a href="#14-6-esercizio-nr-8">14.6 - Esercizio nr. 8</a></li>
</ul>
</li>
<li><a href="#15-esercizio-finale-sviluppare-un-registratore-di-cassa">15 - Esercizio finale: sviluppare un registratore di cassa</a></li>
<li><a href="#16-conclusione">16 - Conclusione</a></li>
<li><a href="#17-soluzioni">17 - Soluzioni</a></li>
</ul>
<!--kg-card-end: markdown--><h2 id="1-introduzione-a-javascript"><strong>1 - Introduzione a Javascript</strong></h2><p>JavaScript è stato creato intorno all'aprile 1995 da Brendan Eich. A quel tempo, stava lavorando allo sviluppo di un browser per un'azienda chiamata Netscape. Gli fu detto che aveva solo 10 giorni per progettare e codificare un prototipo funzionante di un linguaggio di programmazione che potesse essere eseguito nel browser.</p><p>Aveva bisogno di creare un linguaggio che piacesse ai programmatori non professionisti, come Microsoft Visual Basic.</p><p>Il motivo per cui gli furono concessi solo 10 giorni era che Netscape aveva bisogno di rilasciare il suo browser, che all'epoca era in competizione con Microsoft.</p><p>All'inizio, JavaScript non era così potente come lo è oggi, poiché originariamente era stato progettato per aggiungere interazione e animazione alle pagine web. È stato dal 2005, quando sono stati rilasciati jQuery e AJAX, che JavaScript ha iniziato a essere utilizzato in ogni sito web.</p><p>Semplicemente non esisteva una facile alternativa a jQuery e AJAX per la manipolazione del DOM e l'invio di richieste asincrone. Inoltre, un'attiva comunità di sviluppatori JavaScript ha continuato ad aggiungere nuove funzionalità alla libreria.</p><p>Poi Google ha lanciato il suo moderno browser Chrome e Facebook ha iniziato a portare più persone online. JavaScript ha iniziato a crescere per soddisfare le ambizioni di queste gigantesche società di Internet.</p><p>I browser hanno iniziato a sviluppare API che potevi usare in JavaScript per recuperare informazioni come indirizzi IP e posizioni geografiche dal browser, fornendo maggiori risorse alle società Internet per localizzare le funzionalità dei loro siti web.</p><p>Poi è avvenuta un'altra innovazione che ha reso JavaScript ancora più potente.</p><p>Un ambiente lato server chiamato Node.js fu rilasciato nel 2009, consentendo l'esecuzione di JavaScript lato server come PHP, Java, Python, Ruby e molti altri linguaggi. Ha inoltre consentito ai programmatori di sviluppare applicazioni web full-stack utilizzando solo JavaScript.</p><p>Oggi, JavaScript è un linguaggio che può alimentare le applicazioni Web, desktop e mobili.</p><p>Ecco una citazione da Tim O'Reilly, il fondatore di O'Reilly Media:</p><blockquote><em>Imparare JavaScript significava voler dire che non eri uno sviluppatore serio. Oggi non imparare JavaScript significa la stessa cosa<em>.</em></em></blockquote><p>Imparare JavaScript è ora fondamentale per chi voglia diventare uno sviluppatore web.</p><!--kg-card-begin: markdown--><p><a name="1-1-perche-imparare-javascript"></a></p>
<h3 id="11perchimpararejavascript">1.1 - Perché imparare JavaScript?</h3>
<!--kg-card-end: markdown--><p>Ci sono 4 buone ragioni per le quali hai bisogno di imparare e comprendere a fondo JavaScript:</p><ol><li>JavaScript è il solo linguaggio che funziona all'interno del browser</li><li>È abbastanza facile da imparare (ma difficile da padroneggiare)</li><li>È un linguaggio essenziale per sviluppare applicazioni web</li><li>Ci sono parecchie opportunità di carriera per gli sviluppatori JavaScript</li></ol><p>Imparare JavaScript apre grandi opportunità laddove potrai essere uno sviluppatore frontend, backend, o per piattaforme mobili.</p><p>Praticamente, imparare JavaScript apre la porta ad avanzamenti di carriera in campo informatico.</p><h3 id="1-2-javascript-vs-java"><strong>1.2 - JavaScript vs Java</strong></h3><p>All'inizio, JavaScript era in realtà chiamato LiveScript. È stato rinominato in JavaScript perché Java era un linguaggio di programmazione molto popolare.</p><p>Poiché la maggior parte degli sviluppatori di software aveva già familiarità con Java, si pensava che il nome JavaScript aiutasse a commercializzare JavaScript come un ottimo linguaggio di programmazione e attirasse l'interesse degli sviluppatori in quel momento.</p><p>Giusto per essere chiari, JavaScript e Java sono due linguaggi di programmazione completamente diversi. Non è necessario conoscere Java per imparare JavaScript (o viceversa). :)</p><h2 id="2-come-preparare-il-tuo-computer"><strong>2 - Come preparare il tuo computer</strong></h2><p>Per scrivere un programma usando JavaScript, devi installare 2 strumenti gratuiti che sono disponibili su tutti i sistemi operativi.</p><p>Il primo strumento da installare è Visual Studio Code</p><h3 id="2-1-come-installare-vscode"><strong>2.1 - Come installare VSCode</strong></h3><p><a href="https://code.visualstudio.com/download">Visual Studio Code</a> o VSCode in breve, è un programma di editor testi creato allo scopo di scrivere del codice. Oltre a essere gratuito, VSCode è open source e disponibile su tutti i maggiori sistemi operativi.</p><p>Puoi usare VSCode su Windows, macOS e Linux, quindi se non hai un editor testi nel tuo computer adatto per la programmazione, consiglio di installare VSCode.</p><p>Ora che hai un editor testi per scrivere codice JavaScript, ti serve un software per eseguire il codice. Andremo a installare Node.js.</p><h3 id="2-2-come-installare-node-js"><strong>2.2 - Come installare Node.js</strong></h3><p>Per eseguire JavaScript al di fuori del browser, devi installare Node.js, che è essenzialmente un esecutore di codice JavaScript.</p><p>Vai semplicemente al sito di <a href="https://nodejs.org/en/download">Node.js</a> &nbsp;e scarica l'ultima versione di tipo LTS (supporto di lunga durata) adatta al tuo computer. Una volta scaricato, installalo nel tuo sistema.</p><p>Devi eseguire Node.js usando la console, quindi apri il tuo prompt dei comandi (windows) o il tuo terminale (macOS/Linux) ed esegui il seguente comando:</p><pre><code class="language-sh">node -v
</code></pre><p>Questo comando stamperà nella console la versione del tuo Node.js appena installato.</p><h2 id="3-breve-introduzione-alla-console"><strong>3 - Breve introduzione alla console</strong></h2><p>La console è un'interfaccia basata su testo che puoi utilizzare per digitare ed eseguire comandi sul tuo computer. Su Windows, si chiama Prompt dei Comandi. Su macOS e Linux è nota come Terminale.</p><p>Non utilizzerai tutti i comandi disponibili all'interno della console. In effetti, devi solo conoscere 7 comandi di base che ti consentono di eseguire il codice JavaScript.</p><p>Innanzitutto, apri il programma della console sul tuo computer e, per i sistemi Linux e macOs digita il comando pwd:</p><pre><code class="language-sh">pwd
</code></pre><p>Questo è il comando che usi per trovare in quale directory il tuo terminale si trova attualmente. &nbsp;<code>pwd</code> sta per "print working directory" (stampa directory di lavoro).</p><p>Su Windows il comando da utilizzare per trovare la directory di lavoro è cd:</p><pre><code class="language-dos">cd</code></pre><p>Per cambiare la directory di lavoro devi digitare il comando <code>cd</code> seguito dal percorso della directory.</p><p>Ecco un esempio per spostarsi su una directory figlia (scendere di un livello):</p><pre><code class="language-sh">cd nome_directory/nome_sotto_directory
</code></pre><p>Per spostarsi alla directory genitore, (risalire di un livello) aggiungi &nbsp;<code>..</code> al comando <code>cd</code>:</p><pre><code class="language-sh">cd ..
</code></pre><p>Per risalire più di un livello di directory usa &nbsp;<code>../..</code></p><p>Per pulire la tua console dai comandi e dai risultati degli stessi, per i sistemi Linux e macOs usa il comando <code>clear</code>:</p><pre><code class="language-sh">clear
</code></pre><p>Per il Prompt dei Comandi di Windows digita il comando <code>cls</code>:</p><pre><code class="language-dos">cls
</code></pre><p>Per stampare l'elenco di file e directory nella directory corrente, per i sistemi Linux e macOs esegui il comando <code>ls</code>:</p><pre><code class="language-sh">ls
</code></pre><p>Per il Prompt dei Comandi di Windows digita <code>dir</code>:</p><pre><code class="language-dos">dir
</code></pre><p>Per creare un nuovo file, per Linux e macOS usa il comando <code>touch</code> seguito dal nome del file e dall'estensione:</p><pre><code class="language-sh">touch index.js
</code></pre><p>per il Prompt dei Comandi di Windows usa il comando <code>type</code> in questo modo:</p><pre><code class="language-dos">type nul &gt; index.js
</code></pre><p>I comandi qui sopra creano un nuovo file JavaScript vuoto chiamato <code>index.js</code> nella tua directory di lavoro corrente.</p><p>Per creare una nuova directory, per i sistemi Linux e macOs usa il comando <code>mkdir</code> seguito dal nome della directory:</p><pre><code class="language-sh">mkdir mio_progetto
</code></pre><p>Per il Prompt dei Comandi di Windows digita il comando <code>md</code> seguito dal nome della directory:</p><pre><code class="language-dos">md mio_progetto
</code></pre><p>Per eseguire JavaScript usando Node.js, digita <code>node</code> seguito dal nome del file, in questo modo:</p><pre><code class="language-sh">node index.js
</code></pre><p>Vedrai un eventuale risultato dell'elaborazione del codice nella stessa console.</p><p>Ci sono molte cose che puoi fare con la console ma per eseguire solo codice JavaScript questi 7 comandi dovrebbero essere sufficienti .</p><p>Andiamo ora a eseguire il tuo primo programma JavaScript!</p><!--kg-card-begin: markdown--><p><a name="4-e-ora-di-dire-hello-world"></a></p>
<h2 id="4oradidirehelloworld">4 - È ora di dire Hello World!</h2>
<!--kg-card-end: markdown--><p>È ora di eseguire il tuo primo programma JavaScript usando Node.</p><p>Dalla console, crea un nuovo file JavaScript chiamato <code>index.js</code>.</p><pre><code class="language-sh"># Per sistemi Linux e MacOs
touch index.js
</code></pre><pre><code class="language-dos">rem Per sistemi Windows
type &gt; nul index.js
</code></pre><p>Poi apri il file usando VSCode (<code>code index.js</code> ) e inserisci al suo interno la seguente riga di codice:</p><pre><code class="language-js">console.log("Hello World!");
</code></pre><p>Ritorna alla console, ed esegui questo script con Node:</p><pre><code class="language-sh">node index.js
</code></pre><p>Nella console dovrebbe essere eseguito il file <code>index.js</code>, che stamperà "Hello World!".</p><p>Hai appena eseguito il tuo primo programma JavaScript usando Node.js. Eccellente!</p><p>Quando esegui il comando <code>node index.js</code> il programma Node.js inizia a leggere lo script riga per riga, dall'inizio alla fine.</p><p>Il programma <code>node</code> vede che hai scritto <code>console.log</code> seguito da parentesi <code>()</code>, quindi sa che gli stai chiedendo di stampare qualcosa. Il programma quindi legge ciò che hai inserito tra parentesi e lo stampa sulla console.</p><p>Nel tuo VSCode o in un altro programma di editor di testo, dovresti vedere diverse parti del tuo codice evidenziate con colori diversi. Questa è una funzionalità dell'editor di testo chiamata <em>colorazione della sintassi</em> ed è davvero utile per aiutarti a distinguere le diverse parti del codice.</p><p>La parola <code>log</code> è una funzione, quindi viene presentata in un colore, mentre le parole tra parentesi hanno un altro colore.</p><p>Una funzione è semplicemente un pezzo di codice utilizzato per eseguire un determinato compito. La funzione <code>log()</code> viene utilizzata per "stampare" qualsiasi cosa tu inserisca tra parentesi.</p><p>D'altra parte, la parola chiave <code>console</code> è un oggetto, ovvero una entità autonoma che dà accesso a determinate funzionalità.</p><p>Impareremo di più su funzioni e oggetti in seguito. Per ora, ricorda solo che l'istruzione <code>console.log()</code> viene utilizzata per stampare cose sulla console.</p><p>Successivamente, inizieremo con l'apprendimento della struttura del codice JavaScript.</p><h2 id="5-struttura-del-codice"><strong>5 - Struttura del codice</strong></h2><p>Un programma per computer è costituito da una serie di pezzi di codice scritti in un file di testo. Questi file di testo vengono quindi eseguiti tramite un software progettato appositamente per l'esecuzione del codice. Il software Node.js che hai scaricato in precedenza è lo strumento che elabora il codice JavaScript.</p><p>Prima di proseguire, cerchiamo di capire la struttura del codice.</p><h3 id="5-1-istruzioni"><strong>5.1 - Istruzioni</strong></h3><p>Un'istruzione è un singolo comando che il computer deve eseguire. Pensala come una frase, ma per i computer. Possiamo terminare un'istruzione utilizzando un punto e virgola <code>;</code> proprio come possiamo terminare una frase usando un punto <code>.</code></p><p>Puoi scrivere più istruzioni in una singola riga, ma la convenzione è di scrivere un'istruzione per riga:</p><pre><code class="language-js">// Questo è difficile da leggere
console.log("Hello World!"); console.log("Sto imparando JavaScript");

// Adesso è meglio
console.log("Hello World!");
console.log("Sto imparando JavaScript");
</code></pre><p>Ogni istruzione è l'espressione di un'azione che deve essere eseguita dal software che esegue il codice.</p><h3 id="5-2-commenti"><strong>5.2 - Commenti</strong></h3><p>In programmazione, i commenti sono testi che usiamo per comunicare il contesto del codice scritto nel file.</p><p>Per scrivere un commento in JavaScript, devi aggiungere due barre <code>//</code> prima del testo del commento, come mostrato di seguito:</p><pre><code class="language-js">// Questo è un commento
// Anche questo è un commento

// Qui sotto si stampano due righe di istruzioni
console.log("Hello World!");
console.log("Sto imparando JavaScript");
</code></pre><p>I commenti vengono ignorati dall'elaboratore del linguaggio, pertanto è possibile utilizzare i commenti per disabilitare parte del codice senza doverlo eliminare.</p><p>Il codice seguente mostra come disabilitare la seconda istruzione di stampa:</p><pre><code class="language-js">console.log("Hello World!");
// console.log("Sto imparando JavaScript");
</code></pre><h3 id="5-3-flusso-di-esecuzione"><strong>5.3 - Flusso di esecuzione</strong></h3><p>Un elaboratore di linguaggio come Node.js esegue le istruzioni con un approccio dall'alto verso il basso. L'istruzione scritta nella prima riga verrà eseguita prima di quella della seconda riga, quindi proseguirà fino all'ultima riga:</p><pre><code class="language-js">console.log("Hello World!");
console.log("Sto imparando JavaScript");

// Stampa di numeri
console.log(1);
console.log(2);
console.log(3);
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">Hello World!
Sto imparando JavaScript
1
2
3
</code></pre><p>Se vuoi stampare i numeri prima del testo, devi spostare le corrispondenti righe con le istruzioni &nbsp;<code>console.log()</code> all'inizio.</p><h3 id="5-4-esercizio-nr-1"><strong>5.4 - Esercizio nr. 1</strong></h3><p>Cerca di stampare il tuo nome, età, occupazione sulla console.</p><p>Il risultato dovrebbe assomigliare a questo:</p><pre><code class="language-txt">Mario Rossi
19
Studente
</code></pre><p>Ora che hai appreso la struttura base del codice di JavaScript continuiamo imparando le variabili.</p><h2 id="6-variabili"><strong>6 - Variabili</strong></h2><p>Prima di spiegare cos'è una variabile, modifica il codice che hai scritto nel file <code>index.js</code> come segue:</p><pre><code class="language-js">let message = "Hello World!"
console.log(message)
</code></pre><p>Quindi esegui il codice utilizzando il comando <code>node index.js</code>. Vedrai lo stesso risultato di quando hai scritto il messaggio "Hello World!" direttamente all'interno della funzione <code>console.log()</code>. Come può essere?</p><p>Questo perché &nbsp;<code>message</code> scritto nel codice sopra è una <em>variabile</em>.</p><p>Nella programmazione, una variabile è semplicemente un nome che dai a un valore in modo che tu possa accedere a quel valore in un secondo momento. Puoi pensare a una variabile come a un'etichetta che può essere associata a un determinato valore, quindi puoi fare riferimento al valore usando l'etichetta.</p><p>Per dichiarare una variabile, devi digitare la parola chiave <code>let</code> seguita dal nome della variabile.</p><p>La prima riga del codice indica a JavaScript di associare la variabile <code>message</code> al valore "Hello World!":</p><pre><code class="language-js">let message = "Hello World!"
</code></pre><p>Nella seconda riga, viene indicato a JavaScript di stampare il valore di <code>message</code>, ed è esattamente quello che fa.</p><p>Puoi modificare il valore della tua variabile assegnandole un altro valore come segue:</p><pre><code class="language-js">message = "Hello World!"
print(message)
message = "Bel tempo oggi!"
print(message)
</code></pre><p>Esegui il file e vedrai due righe stampate come risultato:</p><pre><code class="language-txt">Hello World!
Bel tempo oggi!
</code></pre><p>Le variabili vengono utilizzate per fare riferimento ai dati in modo da poter utilizzare gli stessi dati più volte nel programma.</p><p>Successivamente, vedremo alcune regole per la denominazione delle variabili.</p><h3 id="6-1-denominazione"><strong>6.1 - Denominazione</strong></h3><p>JavaScript ha alcune regole di denominazione che devi conoscere per evitare errori di denominazione.</p><p>I nomi delle variabili possono contenere solo lettere dell'alfabeto, numeri e trattini bassi (<code>_</code>). Ciò significa che puoi denominare la tua variabile <code>message</code>,<code> message_1</code>, <code>message_2</code>.</p><p>Il primo carattere del nome della variabile non deve essere un numero. <code>message_1</code> va bene. <code>1_message</code> no.</p><p>Non puoi utilizzare parole chiave riservate come <code>console</code> perché vengono utilizzate da JavaScript per eseguire determinate operazioni. Ci sono molte altre parole chiave usate da JavaScript che imparerai nei seguenti capitoli come <code>if</code>, <code>for</code> e <code>while</code>.</p><p>I nomi delle variabili fanno distinzione tra maiuscole e minuscole, il che significa che <code>Message</code>, <code>MESSAGE</code> e <code>message</code> possono essere utilizzati per creare tre diverse variabili. Ma ovviamente, non consiglio di usare nomi simili in quanto crea confusione.</p><p>A volte è necessaria più di una parola per dichiarare il nome di una variabile. JavaScript ha due convenzioni di denominazione utilizzate da tutti gli sviluppatori:</p><ol><li><code>camelCase</code></li><li><code>snake_case</code></li></ol><p><em>Il camel case</em> è una convenzione di denominazione che usa la lettera maiuscola per il primo carattere della parola successiva. Ecco un esempio:</p><pre><code class="language-js">let laMiaStupendaVariabile
</code></pre><p>La convenzione di denominazione <em>snake case</em> usa un trattino basso per separare le parole. Ecco un esempio:</p><pre><code class="language-js">let la_mia_stupenda_variabile
</code></pre><p>Entrambe sono convenzioni di denominazione accettabili, ma dovresti adottarne solo una nel tuo codice per evitare confusione.</p><h3 id="6-2-il-tipo-di-variabile-const"><strong>6.2 - Il tipo di variabile <code>const</code></strong></h3><p>Ci sono situazioni nelle quali è necessario memorizzare un valore che non cambia mai in una variabile.</p><p>Il tipo di variabile <code>const</code> è una variabile che non cambia il suo valore finché il programma è in esecuzione. L'eventuale successiva modifica del valore di una costante produrrà un errore.</p><p>In JavaScript, una variabile costante viene dichiarata utilizzando la parola chiave <code>const</code>.</p><p>Quanto segue mostra come dichiarare 2 costanti in JavaScript:</p><pre><code class="language-js">const FILE_SIZE_LIMIT = 2000
const MAX_SPEED = 300
</code></pre><p>La convenzione di denominazione per una costante consiste nell'usare tutte lettere maiuscole, sebbene si possano anche utilizzare lettere minuscole. Il maiuscolo è solo uno standard per far risaltare maggiormente le costanti.</p><!--kg-card-begin: markdown--><p><a name="6-3-il-tipo-di-variabile-var"></a></p>
<h3 id="63iltipodivariabilevar">6.3 - Il tipo di variabile <code>var</code></h3>
<!--kg-card-end: markdown--><p>La parola chiave <code>var</code> viene utilizzata per dichiarare variabili con ambito globale. Questa era l'unica parola chiave che potevi utilizzare per dichiarare le variabili prima che JavaScript rilasciasse le nuove <code>let</code> e <code>const</code> nel 2015.</p><p>Attualmente, dovresti evitare di usare <code>var</code> se puoi, poiché <code>var</code> può introdurre bug che puoi evitare usando al suo posto <code>let</code>.</p><p>Per mostrarti cosa intendo, considera il seguente esempio:</p><pre><code class="language-js">if(true) {
    var name = "Nathan";
}

console.log(name)
</code></pre><p>Il codice qui sopra stamperà correttamente la variabile <code>name</code>, ma in realtà non dovrebbe perché la variabile <code>name</code> è dichiarata all'interno del blocco <code>if</code>.</p><p>Questo perché qualsiasi variabile dichiarata utilizzando &nbsp;<code>var</code> è accessibile ovunque. &nbsp;L'ambito di tale variabile è globale.</p><p>Al contrario, la parola chiave <code>let</code> ha un ambito di blocco, il che significa che la variabile è accessibile solo dal blocco nel quale è stata definita e da tutti i suoi blocchi figli.</p><p>Ma perché preoccuparsi di definire l'ambito della variabile? Questo perché quando si hanno centinaia o migliaia di righe di codice, può diventare frustrante tracciare un errore che si verifica a causa di variabili globali.</p><p>C'è un principio nello sviluppo del software chiamato "principio di minima esposizione", il che significa che non esponi alcuna parte del tuo programma che non sia necessaria.</p><p>Attribuire un ambito di blocco a una variabile garantisce che la stessa sia esposta e accessibile solo nelle parti del tuo codice che richiedono la variabile.</p><p>Una variabile dichiarata utilizzando <code>let</code> è identica a una variabile dichiarata utilizzando <code>var</code> ad eccezione del livello di ambito.</p><pre><code class="language-js">if(true) {
    let name = "Nathan";
}

console.log(name)  // Error: name is not defined (errore: name non è definito)
</code></pre><p>Ciò significa anche che ora hai &nbsp;<code>var</code>, <code>let</code> e <code>const</code> per dichiarare una variabile. Quale usare?</p><p>In generale, puoi prima dichiarare una variabile con <code>const</code>. Quando scrivi il codice dell'applicazione e ti rendi conto che è necessario modificare l'assegnazione della variabile, puoi modificare la dichiarazione in <code>let</code>.</p><p>Se sai fin dall'inizio che il valore della variabile cambierà, puoi usare <code>let</code> immediatamente. Basta non usare <code>var</code> oggi o qualcuno potrebbe arrabbiarsi con te.</p><h3 id="6-4-esercizio-nr-2"><strong>6.4 - Esercizio nr. 2</strong></h3><p>Scrivi un programma con tre variabili, ciascuna con il seguente valore:</p><ol><li>La prima variabile (<code>nome</code>) contiene il tuo nome</li><li>La seconda variabile (<code>eta</code>) contiene la tua età</li><li>La terza variabile (<code>occupazione</code>) contiene la tua occupazione</li></ol><p>Poi stampa le variabili usando il metodo <code>console.log()</code>. Ecco un esempio del risultato:</p><pre><code class="language-txt">Mario Rossi
Studente
19
</code></pre><p>Il modo in cui usi le variabili per creare un programma che faccia quello che desideri è una delle abilità più importanti che puoi avere come programmatore.</p><p>Ma prima di saperne di più su come utilizzare le variabili, impariamo a conoscere i tipi di dato in JavaScript.</p><h2 id="7-tipi-di-dato-base">7 - Tipi di Dato Base</h2><p>I tipi di dato sono semplicemente definizioni per diversi tipi di dato noti a un linguaggio di programmazione.</p><p>Un tipo di dato contiene specifiche su ciò che puoi e non puoi fare con quel dato.</p><p>Per mostrarti un semplice esempio, sono sicuro che sei d'accordo sul fatto che 2 + 2 = 4, giusto?</p><p>Bene, anche JavaScript la pensa allo stesso modo:</p><pre><code class="language-js">console.log(2 + 2);

// Risultato: 4
</code></pre><p>Ma cosa succede se cerchi di aggiungere delle lettere a un numero, come mostrato qui sotto?</p><pre><code class="language-js">console.log(2 + "ABC");
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">2ABC
</code></pre><p>Aggiungere lettere e numeri insieme farà sì che JavaScript concateni o unisca i valori.</p><p>In questa sezione, imparerai i tipi di dato base che JavaScript conosce:</p><ul><li>String (Stringa)</li><li>Number (Numero)</li><li>Boolean (Booleano)</li><li>Null</li><li>Undefined</li></ul><p>Vedrai anche come i vari tipi di dato si comportano con gli operatori come &nbsp;<code>+</code>, mostrato nell'esempio qui sopra.</p><p>Iniziamo con le stringhe.</p><h3 id="7-1-stringhe"><strong>7.1 - Stringhe</strong></h3><p>Una stringa è semplicemente un tipo di dato definito da una serie di caratteri.</p><p>Hai visto un esempio di stringa precedentemente quando hai chiamato la funzione <code>console.log()</code> per stampare un messaggio:</p><pre><code class="language-js">let message = "Hello, Sunshine!";
console.log(message); // Hello, Sunshine!
</code></pre><p>Una stringa deve essere racchiusa tra apici. Puoi usare apici singoli o doppi, ma devono corrispondere.</p><p>Otterrai un errore quando usi apici differenti come in questo caso:</p><pre><code class="language-js">let message = "Hello'; 
// Invalid or unexpected token (token non valido o inatteso)
</code></pre><p>Puoi unire due o più stringhe in una con il simbolo di addizione <code>+</code>. Non dimenticare di aggiungere uno spazio dopo la stringa iniziale oppure avrai una stringa non divisa da spazi!</p><pre><code class="language-js">let message = "Hello " + "and " + "Goodbye!";
console.log(message);

// Risultato: Hello and Goodbye!
</code></pre><p>Quando stampi il valore di una variabile, puoi anche aggiungere direttamente stringhe nella funzione <code>console.log()</code> in questo modo:</p><pre><code class="language-js">let message = "Ciao, Dave!";

console.log("Il messaggio è: " + message);

// Risultato: Il messaggio è: Ciao, Dave!
</code></pre><p>Questo è particolarmente utile quando hai più stringhe da stampare con una sola istruzione console.log, così:</p><pre><code class="language-js">let name = "John";
let topic = "JavaScript";

console.log(name + " sta imparando " + topic + " oggi");

// Risultato: John sta imparando JavaScript oggi
</code></pre><p>Puoi anche usare il formato template di stringa, che ti consente di incorporare il contenuto di una variabile direttamente all'interno della stringa, in questo modo:</p><pre><code class="language-js">let name = "John";
let topic = "JavaScript";

console.log(`${name} sta imparando ${topic} oggi`);

// Risultato: John sta imparando JavaScript oggi
</code></pre><p>Per utilizzare il formato template di stringa, è necessario utilizzare il carattere backtick (<code>`</code>) per racchiudere la stringa anziché le virgolette.</p><p>La variabile è incorporata nella stringa utilizzando il simbolo del dollaro e le parentesi graffe, così: <code>${variabile}</code>.</p><p>In questo modo, JavaScript sa che stai facendo riferimento a una variabile all'interno della stringa.</p><p>Quando si hanno più stringhe da stampare su una singola riga, il formato template di stringa è più conveniente perché non è necessario interrompere la stringa con virgolette e concatenazioni.</p><p>Le stringhe possono anche rappresentare numeri. Racchiudi i numeri tra virgolette come segue:</p><pre><code class="language-js">let score = "10" + "30";
console.log(score);

// Risultato: 1030
</code></pre><p>Quando unisci due numeri in formato stringa con il simbolo <code>+</code>, JavaScript unirà i due numeri invece che eseguire l'operazione aritmetica dell'addizione.</p><p>Ecco come funzionano le stringhe in JavaScript. Ora vediamo i numeri.</p><!--kg-card-begin: markdown--><p><a name="7-2-numeri-interi-e-con-virgola-mobile"></a></p>
<h3 id="72numeriinterieconvirgolamobile">7.2 - Numeri (interi e con virgola mobile)</h3>
<!--kg-card-end: markdown--><p>Il tipo di dato Number rappresenta diversi tipi di numero, che, in JavaScript possono essere:</p><ul><li>Interi (integer)</li><li>Con virgola mobile (float)</li></ul><p>Un intero è un numero senza parte decimale e frazioni. Di seguito due esempi di interi, &nbsp;<code>x</code> e <code>y</code>:</p><pre><code class="language-js">let x = 1;
let y = 2;

console.log(x + y);

// Risultato: 3
</code></pre><p>I numeri con virgola mobile, d'altro canto, rappresentano numeri con cifre decimali, come questi:</p><pre><code class="language-js">let f = 1.2;
let z = 2.35;

console.log(f + z);

// Risultato: 3.55
</code></pre><p>Per creare un numero con virgola mobile, devi scrivere il numero usando il separatore <code>.</code> per definire la parte decimale.</p><p>Con i tipi number, puoi eseguire operazioni aritmetiche come addizione <code>+</code>, sottrazione <code>-</code>, divisione <code>/</code> e moltiplicazione <code>*</code> , proprio come se stessi usando una calcolatrice.</p><h3 id="7-3-booleani"><strong>7.3 - Booleani</strong></h3><p>Il booleano è un tipo che rappresenta i valori &nbsp;vero (<code>true</code> ) e falso (<code>false</code>).</p><p>Puoi pensare a un booleano come a un interruttore della luce che può trovarsi solo in una delle due posizioni: acceso o spento.</p><p>Così è con i valori booleani nei linguaggi di programmazione. Vengono utilizzati quando JavaScript deve prendere una decisione: andare a sinistra o a destra? Giusto o sbagliato?<br>Ecco come creare valori booleani in JavaScript:</p><pre><code class="language-js">let on = true;
let off = false;
</code></pre><p>Questo tipo di dati è usato frequentemente quando devi prendere una decisione usando un controllo di flusso. Vedrai come i valori booleani sono molto utili per lo sviluppo di un programma più tardi nel <a href="#9-operatori">capitolo 9</a>.</p><h3 id="7-4-undefined"><strong>7.4 - Undefined</strong></h3><p>Undefined è un tipo di dato usato per rappresentare una variabile alla quale non è stato assegnato ancora alcun valore.</p><p>Ogni volta che dichiari una variabile senza assegnarle un valore, il valore <code>undefined</code> le viene assegnato. Per esempio:</p><pre><code class="language-js">let first_name;

console.log(first_name); // undefined
</code></pre><p>Puoi anche assegnare &nbsp;<code>undefined</code> esplicitamente a una variabile in questo modo:</p><pre><code class="language-js">let last_name = undefined;
</code></pre><p>In genere questo non è raccomandato in quanto JavaScript dispone di un altro valore, detto <code>null</code>, che viene usato per contrassegnare una variabile che non ha valore.</p><h3 id="7-5-null"><strong>7.5 - Null</strong></h3><p>Il valore <code>null</code> è un tipo speciale di dato che rappresenta un valore vuoto o sconosciuto. Ecco come assegni null a una variabile:</p><pre><code class="language-js">let first_name = null;
</code></pre><p>Il codice qui sopra indica che il valore di <code>first_name</code> è vuoto o sconosciuto.</p><p>A questo punto, potresti pensare, qual è la differenza tra <code>undefined</code> e <code>null</code>? Sembra che abbiano uno scopo simile.</p><p>Hai ragione. Sia <code>undefined</code> che <code>null</code> sono valori che non rappresentano nulla e altri linguaggi di programmazione di solito ne hanno solo uno, ovvero <code>null</code>.</p><p>In JavaScript, il valore <code>undefined</code> è riservato come valore predefinito quando viene dichiarata una variabile, mentre <code>null</code> significa che assegni intenzionalmente un valore "vuoto" per la variabile.</p><p>Questa leggera differenza sarà evidenziata in seguito quando imparerai a conoscere le funzioni nel <a href="#13-funzioni">capitolo 13</a>.</p><p>Per ora, tieni presente che JavaScript tratta <code>undefined</code> come valore vuoto "predefinito" e <code>null</code> come valore vuoto "intenzionale".</p><h2 id="8-conversione-di-tipo-e-coercizione-di-tipo"><strong>8 - Conversione di tipo e coercizione di tipo</strong></h2><p>A volte, potresti voler convertire un tipo di dato in un altro in modo che il programma funzioni come previsto.</p><p>Ad esempio, supponi di dover convertire una stringa in un numero intero in modo da poter eseguire un'addizione tra numeri.</p><p>Se hai uno dei numeri come stringa, JavaScript li unisce invece di aggiungerli:</p><pre><code class="language-js">let x = "7";
let y = 5;

console.log(x + y); // 75
</code></pre><p>Per aggiungere i due numeri propriamente, devi convertire il valore della variabile <code>x</code> in un intero.</p><p>La modifica di un tipo di dato in un altro è anche nota come conversione di tipo (type casting). Ci sono tre funzioni che sono frequentemente usate per eseguire le conversioni di tipo:</p><ul><li><code>Number()</code></li><li><code>String()</code></li><li><code>Boolean()</code></li></ul><p>Come si evince dal loro nome (in inglese - n.d.t.) queste funzioni di conversione di tipo tentano di convertire un qualsiasi valore specificato all'interno delle parentesi nel tipo con lo stesso nome della funzione.</p><p>Per convertire una stringa in un intero puoi usare la funzione <code>int()</code>:</p><pre><code class="language-js">let x = "7";
let y = 5;

// Converte x in un intero
x = Number(x);

console.log(x + y); // 12
</code></pre><p>La funzione &nbsp;<code>String()</code> converte un valore di un altro tipo in stringa. Se chiami <code>String(true)</code>, otterrai il valore di ritorno 'true'.</p><p>Passare un valore dello stesso tipo a queste funzioni non ha effetto e si otterrà lo stesso valore in ritorno.</p><h3 id="8-1-coercizione-di-tipo"><strong>8.1 - Coercizione di tipo</strong></h3><p>In JavaScript, la coercizione di tipo è un processo in cui un valore di un tipo viene implicitamente convertito in un altro tipo.</p><p>Questo viene fatto automaticamente da JavaScript in modo che il tuo codice non causi un errore. Ma come vedrai in questa sezione, la coercizione di tipo può effettivamente causare un comportamento indesiderato nel programma.</p><p>Consideriamo cosa succede quando esegui un'addizione tra un numero e una stringa in JavaScript:</p><pre><code class="language-js">console.log(1 + "1");
</code></pre><p>Come hai visto in precedenza, JavaScript considererà il numero come una stringa e unirà i due valori come "11" invece di sommarli (1 + 1 = 2)</p><p>Devi sapere che altri linguaggi di programmazione non rispondono allo stesso modo.</p><p>Linguaggi come Ruby o Python risponderanno interrompendo il programma e fornendo un errore come feedback. Risponderanno con qualcosa del tipo "Impossibile eseguire l'addizione tra un numero e una stringa".</p><p>Ma JavaScript lo vedrà e dirà: "Non posso eseguire l'operazione che hai richiesto <strong>così com'è</strong>, ma posso farlo se il numero 1 viene convertito in una stringa, <strong>quindi lo farò</strong>."</p><p>E questa è esattamente la coercizione di tipo. JavaScript rileva che non sa come eseguire il tuo codice, ma non interrompe il programma e risponde con un errore.</p><p>Viceversa, cambierà il tipo di dato di uno dei valori senza dirtelo.</p><p>Sebbene la coercizione di tipo non causi errori, il risultato è in realtà qualcosa che non vuoi neanche tu.</p><!--kg-card-begin: markdown--><h4 id="811regoledellacoercizioneditipo">8.1.1 - Regole della coercizione di tipo</h4>
<!--kg-card-end: markdown--><p>Le regole della coercizione di tipo non sono mai state dichiarate chiaramente da nessuna parte, ma ho trovato alcune regole provando io stesso vari pezzi di codice stupidi.</p><p>Sembra che JavaScript converta per prima cosa i tipi di dati in stringa quando trova diversi tipi di dato:</p><pre><code class="language-js">1 + "1" // "11"
[1 ,2] + "1" // "1,21"
true + "1" // "true1"
</code></pre><p>Ma l'ordine dei valori ha importanza quando hai un oggetto. Se l'oggetto viene prima sarà sempre ritornato un <code>1</code> numerico:</p><pre><code class="language-js">{ a: 1 } + "1" // 1
"1" + { a: 1 } // "1[object Object]"
true + { a: 1 } // "true[object Object]"
{ a: 1 } + 1 // 1
</code></pre><p>JavaScript può calcolare tra tipi booleani e numerici in quanto i valori booleani sono <code>true</code> e <code>false</code> che implicitamente corrispondono ai valori numerici di <code>1</code> e <code>0</code>:</p><pre><code class="language-js">true + 1 // 1+1 = 2
false + 1 // 0+1 = 1
[1,2] + 1 // "1,21"
</code></pre><p>La coercizione di tipo viene sempre effettuata <strong>implicitamente</strong>. Quando assegni il valore in fase di dichiarazione della variabile, il tipo della variabile non verrà mai modificato al di fuori dell'operazione:</p><pre><code class="language-js">let myNumber = 1;
console.log(myNumber + "1"); // stampa 11
console.log(myNumber); // stampa sempre il numero 1 e non la stringa
</code></pre><p>Puoi provare a cercare qualche altro caso di tua iniziativa, ma spero che tu abbia compreso cos'è la coercizione di tipo e come funziona adesso.</p><!--kg-card-begin: markdown--><p><a name="8-1-2-perche-dovresti-evitare-la-coercizione-di-tipo"></a></p>
<h4 id="812perchdovrestievitarelacoercizioneditipo">8.1.2 - Perché dovresti evitare la coercizione di tipo</h4>
<!--kg-card-end: markdown--><p>Gli sviluppatori JavaScript sono generalmente divisi in due fazioni quando si parla di coercizione di tipo:</p><ul><li>Quelli che pensano che sia una funzionalità</li><li>Quelli che pensano che sia un bug</li></ul><p>Se me lo chiedi, ti consiglierei di evitare sempre di usare la coercizione di tipo nel tuo codice.</p><p>Il motivo è che non ho mai trovato un problema in cui è richiesta la coercizione di tipo per la soluzione, e quando devo convertire un tipo in un altro, è sempre meglio farlo in modo esplicito:</p><pre><code class="language-js">let price = "50";
let tax = 5;

let totalPrice = Number(price) + Number(tax);

console.log(totalPrice);
</code></pre><p>L'uso di funzioni di conversione di tipo esplicite come <code>Number()</code> e <code>String()</code> renderà il tuo codice chiaro e trasparente. Non è necessario indovinare il tipo di dati corretto richiesto nel programma.</p><p>La coercizione di tipo è una delle caratteristiche uniche di JavaScript che può confondere i principianti, quindi è bene chiarirlo presto.</p><p>Successivamente impareremo gli operatori JavaScript.</p><h2 id="9-operatori"><strong>9 - Operatori</strong></h2><p>Come suggerisce il nome, gli operatori sono simboli che puoi utilizzare per eseguire operazioni sui tuoi dati.</p><p>Hai visto alcuni esempi di utilizzo dell'operatore più <code>+</code> per unire più stringhe e sommare due numeri insieme. Naturalmente, JavaScript ha più di un operatore, come scoprirai in questo capitolo.</p><p>Poiché in precedenza hai appreso i tipi di dati e la conversione di tipo, imparare gli operatori dovrebbe essere relativamente semplice.</p><h3 id="9-1-operatori-aritmetici"><strong>9.1 - Operatori Aritmetici</strong></h3><p>Gli operatori aritmetici sono usati per eseguire operazioni matematiche come addizioni e sottrazioni.</p><p>Questi operatori sono frequentemente usati con tipi di dato numerico. Ecco un esempio:</p><pre><code class="language-js">console.log(10 - 3); // 7
console.log(2 + 4); // 6
</code></pre><p>Ci sono in totale 8 operatori aritmetici in JavaScript:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>NOME</th>
<th>ESEMPIO OPERAZIONE</th>
<th>SIGNIFICATO</th>
</tr>
</thead>
<tbody>
<tr>
<td>Addizione</td>
<td><code>x + y</code></td>
<td>Ritorna la somma dei due operandi</td>
</tr>
<tr>
<td>Sottrazione</td>
<td><code>x - y</code></td>
<td>Ritorna la differenza tra i due operandi</td>
</tr>
<tr>
<td>Moltiplicazione</td>
<td><code>x * y</code></td>
<td>Ritorna il prodotto dei due operandi</td>
</tr>
<tr>
<td>Elevamento a potenza</td>
<td><code>x ** y</code></td>
<td>Ritorna il valore dell'operando di sinistra elevato alla potenza dell'operando di destra</td>
</tr>
<tr>
<td>Divisione</td>
<td><code>x / y</code></td>
<td>Ritorna il valore dell'operando di sinistra diviso per l'operando di destra</td>
</tr>
<tr>
<td>Resto</td>
<td><code>x % y</code></td>
<td>Ritorna il resto del valore della divisione tra l'operando di sinistra e l'operando di destra</td>
</tr>
<tr>
<td>Incremento</td>
<td><code>x++</code></td>
<td>Ritorna l'operando più uno</td>
</tr>
<tr>
<td>Decremento</td>
<td><code>x--</code></td>
<td>Ritorna l'operando meno uno</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Questi operatori sono piuttosto semplici, quindi puoi provarli da solo.</p><p>Come hai visto nella sezione precedente, l'operatore <code>+</code> può essere utilizzato anche sui dati di tipo <code>String</code> per unire più stringhe in una sola:</p><pre><code class="language-js">let message = "Ciao " + "umano!";
console.log(message); // Ciao umano!
</code></pre><p>Quando aggiungi un numero e una stringa, JavaScript eseguirà una coercizione di tipo e tratterà il valore numerico come un valore stringa:</p><pre><code class="language-js">let sum = "Ciao " + 89;
console.log(sum); // Ciao 89
</code></pre><p>L'utilizzo di qualsiasi altro operatore aritmetico con le stringhe farà sì che JavaScript restituisca un valore <code><a href="https://it.wikipedia.org/wiki/NaN">NaN</a></code>.</p><h3 id="9-2-operatori-di-assegnazione"><strong>9.2 - Operatori di assegnazione</strong></h3><p>L'operatore successivo da apprendere è l'operatore di assegnazione, rappresentato dal segno di uguale <code>=</code>.</p><p>In JavaScript, l'operatore di assegnazione viene utilizzato per assegnare dati o un valore a una variabile.</p><p>Hai già visto alcuni esempi di utilizzo dell'operatore di assegnazione, quindi ecco un promemoria:</p><pre><code class="language-js">// Assegna il valore stringa 'Hello' alla variabile 'message'
let message = "Hello";

// Assegna il valore booleano true alla variabile 'on'
let on = true;
</code></pre><p>Potresti aver notato che il segno uguale ha un significato leggermente diverso in programmazione che in matematica, e hai ragione!</p><p>L'operatore di assegnazione non viene utilizzato per confrontare se un numero è uguale a un altro numero nella programmazione.</p><p>Se vuoi fare questo tipo di confronto, devi usare l'operatore "uguale a" <code>==</code>.</p><p>Gli operatori di assegnazione possono anche essere combinati con operatori aritmetici, in modo da poter aggiungere o sottrarre valori dall'operando di sinistra.</p><p>Vedi la tabella seguente per i tipi di operatore di assegnazione:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>NOME</th>
<th>ESEMPIO OPERAZIONE</th>
<th>SIGNIFICATO</th>
</tr>
</thead>
<tbody>
<tr>
<td>Assegnazione</td>
<td><code>x = y</code></td>
<td><code>x = y</code></td>
</tr>
<tr>
<td>Addizione e Assegnazione</td>
<td><code>x += y</code></td>
<td><code>x = x + y</code></td>
</tr>
<tr>
<td>Sottrazione e assegnazione</td>
<td><code>x -= y</code></td>
<td><code>x = x - y</code></td>
</tr>
<tr>
<td>Moltiplicazione e Assegnazione</td>
<td><code>x *= y</code></td>
<td><code>x = x * y</code></td>
</tr>
<tr>
<td>Divisione e Assegnazione</td>
<td><code>x /= y</code></td>
<td><code>x = x / y</code></td>
</tr>
<tr>
<td>Resto e Assegnazione</td>
<td><code>x %= y</code></td>
<td><code>x = x % y</code></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Ora esaminiamo gli operatori di confronto.</p><h3 id="9-3-operatori-di-confronto"><strong>9.3 - Operatori di confronto</strong></h3><p>Gli operatori di confronto vengono utilizzati per confrontare due valori. Gli operatori in questa categoria restituiranno valori booleani: vero (<code>true</code>) o falso (<code>false</code>).</p><p>La tabella seguente mostra tutti gli operatori di confronto disponibili in JavaScript:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>NOME</th>
<th>ESEMPIO OPERAZIONE</th>
<th>SIGNIFICATO</th>
</tr>
</thead>
<tbody>
<tr>
<td>Uguale</td>
<td><code>x == y</code></td>
<td>Ritorna <code>true</code> se gli operandi sono uguali</td>
</tr>
<tr>
<td>Non uguale</td>
<td><code>x != y</code></td>
<td>Ritorna <code>true</code> se gli operandi non sono uguali</td>
</tr>
<tr>
<td>Strettamente uguale</td>
<td><code>x === y</code></td>
<td>Ritorna <code>true</code> se gli operandi sono uguali e sono dello stesso tipo</td>
</tr>
<tr>
<td>Strettamente non uguale</td>
<td><code>x !== y</code></td>
<td>Ritorna <code>true</code> se gli operandi non sono uguali e sono di tipi diversi</td>
</tr>
<tr>
<td>Maggiore di</td>
<td><code>x &gt; y</code></td>
<td>Ritorna <code>true</code> se l'operando di sinistra è maggiore di quello di destra</td>
</tr>
<tr>
<td>Maggiore o uguale</td>
<td><code>x &gt;= y</code></td>
<td>Ritorna <code>true</code> se l'operando di sinistra è maggiore o uguale a quello di destra</td>
</tr>
<tr>
<td>Minore di</td>
<td><code>x &lt; y</code></td>
<td>Ritorna <code>true</code> se l'operando di sinistra è minore di quello di destra</td>
</tr>
<tr>
<td>Minore o uguale</td>
<td><code>x &gt;= y</code></td>
<td>Ritorna <code>true</code> se l'operando di sinistra è minore o uguale a quello di destra</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Ecco alcuni esempi di utilizzo di questi operatori:</p><pre><code class="language-js">console.log(9 == 9); // true

console.log(9 != 20); // true

console.log(2 &gt; 10); // false

console.log(2 &lt; 10); // true

console.log(5 &gt;= 10); // false

console.log(10 &lt;= 10); // true
</code></pre><p>Anche gli operatori di confronto possono essere usati per confrontare stringhe in questo modo:</p><pre><code class="language-js">console.log("ABC" == "ABC"); // true

console.log("ABC" == "abc"); // false

console.log("Z" == "A"); // false
</code></pre><p>I confronti tra stringhe fanno distinzione tra maiuscole e minuscole, come mostrato nell'esempio precedente.</p><p>JavaScript ha anche due versioni di ciascun operatore di confronto: <em>loose</em> e <em>strict</em> (rigoroso).</p><p>In modalità <em>strict</em>, JavaScript confronterà i tipi senza eseguire una coercizione di tipo.</p><p>È necessario aggiungere un altro simbolo uguale <code>=</code> all'operatore come segue</p><pre><code class="language-js">console.log("9" == 9); // true
console.log("9" === 9); // false

console.log(true == 1); // true
console.log(true === 1); // false
</code></pre><p>Dovresti usare gli operatori di confronto rigorosi a meno che tu non abbia una ragione specifica per non farlo.</p><h3 id="9-4-operatori-logici"><strong>9.4 - Operatori logici</strong></h3><p>Sono usati per verificare se una o più espressioni vengono valutate come vere (<code>true</code>) o false (<code>false</code>).</p><p>JavaScript ha tre operatori logici:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>NOME</th>
<th>ESEMPIO OPERAZIONE</th>
<th>SIGNIFICATO</th>
</tr>
</thead>
<tbody>
<tr>
<td>Logico E</td>
<td><code>x &amp;&amp; y</code></td>
<td>Ritorna <code>true</code> se tutti gli operandi sono <code>true</code>, <code>false</code> altrimenti</td>
</tr>
<tr>
<td>Logico O</td>
<td><code>x || y</code></td>
<td>Ritorna <code>true</code> se uno degli operandi è <code>true</code>, <code>false</code> altrimenti</td>
</tr>
<tr>
<td>Logico NON</td>
<td><code>!</code></td>
<td>Ribalta il risultato, ritorna <code>true</code> se <code>false</code> e viceversa</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>Questi operatori possono ritornare solo valori booleani. Per esempio puoi determinare se 7 sia maggiore di 2 e 5 sia maggiore di 4:</p><pre><code class="language-js">console.log(7 &gt; 2 &amp;&amp; 5 &gt; 4); // true
</code></pre><p>Questi operatori logici seguono le leggi della logica matematica:</p><ol><li><code>&amp;&amp;</code> operatore E - se una qualunque espressione ritorna <code>false</code>, il risultato è <code>false</code></li><li><code>||</code> operatore O - se una qualunque espressione ritorna <code>true</code>, il risultato è <code>true</code></li><li><code>!</code> operatore NON - nega l'espressione, ritornando l'opposto.</li></ol><p>Facciamo un piccolo esercizio. Cerca di eseguire queste istruzioni sul tuo computer. Sei in grado di indovinare i risultati?</p><pre><code class="language-js">console.log(true &amp;&amp; false);

console.log(false || false);

console.log(!true);
</code></pre><p>Questi operatori logici tornano utili quando devi verificare che uno specifico requisito sia soddisfatto nel tuo codice.</p><h3 id="9-5-operatore-typeof"><strong>9.5 - Operatore <code>typeof</code></strong></h3><p>JavaScript ti consente di verificare il tipo di dato usando l'operatore <code>typeof</code>. Per usarlo devi chiamarlo prima di specificare l'oggetto della verifica:</p><pre><code class="language-js">let x = 5;
console.log(typeof x) //  'number'

console.log(typeof "Nathan") // 'string'

console.log(typeof true) // 'boolean'
</code></pre><p>L'operatore <code>typeof</code> restituisce il tipo di dato sotto forma di stringa. Il tipo 'number' rappresenta sia i tipi interi che con virgola mobile (float), 'string' e 'boolean' &nbsp;rappresentano i rispettivi tipi.</p><h3 id="9-6-esercizio-nr-3"><strong>9.6 - Esercizio nr. 3</strong></h3><p>Cerca di indovinare i risultati per queste operazioni:</p><pre><code class="language-js">console.log(19 % 3);
console.log(10 == 3);
console.log(10 !== "10");
console.log(2 &lt; "10");
console.log("5" &gt; 2);
console.log((false &amp;&amp; true) || false);</code></pre><pre><code class="language-js">console.log(19 % 3);
console.log(10 == 3);
console.log(10 !== "10");
console.log(2 &lt; "10");
console.log("5" &gt; 2);
console.log((false &amp;&amp; true) || false);
</code></pre><h2 id="10-array"><strong>10 - Array</strong></h2><p>Un array è un tipo di dato oggetto che può essere usato per contenere più di un valore. Un array può essere un elenco di stringhe, numeri, booleani, oggetti oppure un misto di tutti questi.</p><p>Per creare un array, devi usare le parentesi quadre <code>[]</code> e separare gli elementi usando una virgola.</p><p>Ecco come creare un elenco di stringhe:</p><pre><code class="language-js">let birds = ['Owl', 'Eagle', 'Parrot', 'Falcon'];
</code></pre><p>Puoi pensare a un array come a un elenco di elementi, ciascuno memorizzato in uno scomparto di un armadietto:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/10-array-as-a-locker-1.png" class="kg-image" alt="Array as a locker illustration" width="600" height="400" loading="lazy"></figure><p>Puoi anche dichiarare un array vuoto, senza elementi:</p><pre><code class="language-js">let birds = [];
</code></pre><p>Un array può anche contenere elementi di tipo diverso:</p><pre><code class="language-js">let mixedArray = ['Bird', true, 10, 5.17]
</code></pre><p>L'array qui sopra contiene una stringa, un booleano, un intero e un numero con virgola mobile.</p><h3 id="10-1-posizione-dell-indice"><strong>10.1 - Posizione dell'indice</strong></h3><p>JavaScript ricorda la posizione degli elementi all'interno di un array. La posizione di un elemento è anche chiamata indice numerico.</p><p>Tornando all'esempio dell'armadietto, puoi pensare ai numeri di indice come ai numeri degli scomparti dell'armadietto. Il numero di indice inizia da 0 come segue:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/10-array-index-analogy.png" class="kg-image" alt="Array index numbers as locker numbers" width="600" height="400" loading="lazy"></figure><p>Per accedere o modificare un elemento di un array, devi aggiungere al nome della variabile che rappresenta l'array la notazione <code>[x]</code> dove <code>x</code> è il numero di indice dell'elemento. Ecco un esempio:</p><pre><code class="language-js">// Accede al primo elemento dell'array
myArray[0];

// Accede al secondo elemento dell'array
myArray[1];
</code></pre><p>Supponi tu voglia stampare la stringa 'Owl' dall'array <code>birds</code>. Ecco come puoi fare:</p><pre><code class="language-js">let birds = ['Owl', 'Eagle', 'Parrot', 'Falcon'];

console.log(birds[0]); // Owl
</code></pre><p>Ecco qua. È necessario digitare il nome dell'array, seguito dal numero di indice racchiuso tra parentesi quadre.</p><p>È inoltre possibile assegnare un nuovo valore a un elemento con indice specifico utilizzando l'operatore di assegnazione.</p><p>Sostituiamo 'Parrot' con 'Vulture':</p><pre><code class="language-js">let birds = ['Owl', 'Eagle', 'Parrot', 'Falcon'];
birds[2] = 'Vulture';

console.log(birds);
// ['Owl', 'Eagle', 'Vulture', 'Falcon']
</code></pre><p>Visto che l'indice dell'array inizia da 0, il valore 'Parrot' è conservato alla posizione di indice 2, non 3.</p><h3 id="10-2-metodi-speciali-per-la-manipolazione-di-array"><strong>10 - 2 Metodi speciali per la manipolazione di array</strong></h3><p>Poiché l'array è un oggetto, è possibile chiamare i metodi forniti da JavaScript per manipolare i valori dell'array.</p><p>Ad esempio, puoi utilizzare il metodo <code>push()</code> per aggiungere un elemento alla fine dell'array:</p><pre><code class="language-js">let birds = ['Owl', 'Eagle'];

birds.push('Sparrow');

console.log(birds);
// ['Owl', 'Eagle', 'Sparrow']
</code></pre><p>Un altro metodo chiamato <code>pop()</code> può essere usato per eliminare l'elemento alla fine dell'array:</p><pre><code class="language-js">let birds = ['Owl', 'Eagle', 'Sparrow'];

birds.pop();

console.log(birds);
// ['Owl', 'Eagle']
</code></pre><p>Il metodo <code>unshift()</code> si può usare per inserire un elemento all'inizio dell'array &nbsp;(posizione di indice 0):</p><pre><code class="language-js">let fishes = ['Salmon', 'Goldfish', 'Tuna'];

fishes.unshift('Sardine');

console.log(fishes);
// ['Sardine', 'Salmon', 'Goldfish', 'Tuna']
</code></pre><p>Di contro il metodo <code>shift()</code> può essere usato per rimuovere l'elemento all'inizio dell'array (posizione di indice 0):</p><pre><code class="language-js">let fishes = ['Salmon', 'Goldfish', 'Tuna'];

fishes.shift();

console.log(fishes);
// ['Goldfish', 'Tuna']
</code></pre><p>Il metodo <code>indexOf()</code> può essere usato per trovare e ritornare la posizione di indice di un elemento in un array.</p><p>Questo metodo ritornerà <code>-1</code> quando l'elemento non viene trovato nell'array:</p><pre><code class="language-js">let fishes = ['Salmon', 'Goldfish', 'Tuna'];

let pos = fishes.indexOf('Tuna');

console.log(pos); // 2
</code></pre><p>Per ottenere la dimensione di un array puoi accedere alla sua proprietà <code>length</code>:</p><pre><code class="language-js">let fishes = ['Salmon', 'Goldfish', 'Tuna'];

console.log(fishes.length); // 3
</code></pre><p>Nota che non aggiungiamo parentesi accanto a <code>length</code> qui sopra. Questo perché <code>length</code> è una proprietà dell'oggetto array e non un metodo.</p><p>Impareremo di più sugli oggetti prossimamente.</p><h3 id="10-3-esercizio-nr-4"><strong>10.3 - Esercizio nr. &nbsp;4</strong></h3><p>Crea un array denominato <code>colori</code> che includa i colori "rosso", "verde" e "blu".</p><p>Poi aggiungi il colore "nero" dopo l'ultimo indice dell'array. Quindi stampa l'array.</p><p>Successivamente, rimuovi il valore "rosso" e scambia la posizione di "verde" e "blu". Stampa nuovamente l'array.</p><p>Infine, aggiungi il colore "giallo" all'inizio dell'array, quindi stampalo.</p><p>Il risultato dovrà essere il seguente:</p><pre><code class="language-txt">[ 'rosso', 'verde', 'blu', 'nero' ]
[ 'blu', 'verde', 'nero' ]
[ 'giallo', 'blu', 'verde', 'nero' ]
</code></pre><p>Devi modificare l'array originale usando i metodi illustrati in questo capitolo.</p><!--kg-card-begin: markdown--><p><a name="11-flussi-di-controllo-condizionali"></a></p>
<h2 id="11flussidicontrollocondizionali">11 - Flussi di controllo (condizionali)</h2>
<!--kg-card-end: markdown--><p>Fino a ora, il codice JavaScript che hai scritto viene eseguito riga per riga dall'alto verso il basso. Ma cosa succede se si desidera eseguire alcune righe di codice solo quando viene soddisfatta una determinata condizione?</p><p>Un programma per computer di solito deve tenere conto di molte condizioni diverse che possono verificarsi durante l'esecuzione dello stesso.</p><p>Questo è simile a come un essere umano prende decisioni nella propria vita. Ad esempio, hai i soldi per permetterti una vacanza in Giappone? Se sì, vai. In caso contrario, risparmia ulteriormente!</p><p>È qui che entra in gioco il flusso di controllo. Il <strong>flusso di controllo</strong> è una funzionalità in un linguaggio di programmazione che ti consente di eseguire in modo selettivo codice specifico in base alle diverse condizioni che possono verificarsi.</p><p>L'utilizzo dei flussi di controllo ti consente di definire più percorsi che un programma può intraprendere in base alle condizioni presenti nello stesso.</p><p>Ci sono due tipi di flussi di controllo comunemente usati in JavaScript: condizionali e cicli (loop).<br>Questa sezione si concentrerà sulle istruzioni condizionali come:</p><ol><li>L'istruzione <code>if...else</code></li><li>L'istruzione <code>switch...case</code></li></ol><p>Imparerai le istruzioni per i cicli nella successiva sezione.</p><h3 id="11-1-istruzione-if-else"><strong>11.1 - Istruzione if...else</strong></h3><p>L'istruzione <code>if</code> ti consente di creare una parte di programma che viene eseguita solamente se viene soddisfatta una specifica condizione.</p><p>La sintassi è la seguente:</p><pre><code class="language-js">if (condizione) {
  // codice da eseguire se la condizione è soddisfatta
}
</code></pre><p>Vediamo un esempio. Supponiamo che tu voglia andare in vacanza, per cui ti servono 5000 dollari.</p><p>Usando l'istruzione <code>if</code>, ecco come verificare se hai abbastanza denaro:</p><pre><code class="language-js">let balance = 7000;

if (balance &gt; 5000) {
  console.log("Hai sufficiente denaro per questo viaggio. Andiamo!");
}
</code></pre><p>Esegui il codice qui sopra una volta e vedrai la stringa stampata sul terminale.</p><p>Ora modifica il valore di <code>balance</code> a 3000 e non otterrai alcuna risposta.</p><p>Ciò accade perché il codice all'interno dell'istruzione <code>if</code> viene eseguito solo quando la condizione è vera.</p><p>Dopo l'istruzione <code>if</code>, puoi scrivere un'altra riga di codice sotto di essa come segue:</p><pre><code class="language-js">let balance = 7000;

if (balance &gt; 5000) {
  console.log("Hai sufficiente denaro per questo viaggio. Andiamo");
}
console.log("Fine!");
</code></pre><p>La seconda istruzione <code>console.log()</code> qui sopra verrà eseguita indipendentemente dal valore assegnato alla variabile <code>balance</code>.</p><p>Se vuoi che venga eseguita solo quando la condizione <code>if</code> è soddisfatta, metti anche questa riga all'interno delle parentesi graffe:</p><pre><code class="language-js">let balance = 7000;

if (balance &gt; 5000) {
  console.log("Hai sufficiente denaro per questo viaggio. Andiamo");
  console.log("Fine!");
}
</code></pre><p>Supponiamo ora di dover eseguire del codice solo quando la condizione dell'istruzione <code>if</code> <strong>non</strong> è soddisfatta.</p><p>È qui che entra in gioco l'istruzione <code>else</code>. L'istruzione <code>else</code> viene utilizzata per eseguire il codice solo quando l'istruzione <code>if</code> non è soddisfatta.</p><p>Ecco un esempio:</p><pre><code class="language-js">let balance = 7000;

if (balance &gt; 5000) {
  console.log("Hai sufficiente denaro per questo viaggio. Andiamo");
} else {
  console.log("Mi dispiace, non c'è denaro a sufficienza. Risparmia di più!");
}
console.log("Fine!");
</code></pre><p>Ora modifica il valore di <code>balance</code> in modo che sia inferiore a 5000 e attiverai il blocco <code>else</code> nell'esempio.</p><p>JavaScript ha anche l'istruzione <code>else if</code> che ti consente di scrivere un'altra condizione da verificare se la condizione dell'istruzione <code>if</code> non è soddisfatta.</p><p>Considera l'esempio seguente:</p><pre><code class="language-js">let balance = 7000;

if (balance &gt; 5000) {
  console.log("Hai sufficiente denaro per questo viaggio. Andiamo!");
} else if (balance &gt; 3000) {
  console.log("Hai denaro solo per una vacanza senza andare troppo lontano!");
} else {
  console.log("Mi dispiace, non c'è denaro a sufficienza. Risparmia di più!");
}
console.log("Fine!");
</code></pre><p>Quando il valore &nbsp;di <code>balance</code> è inferiore a 5000, l'istruzione <code>else if</code> verificherà se il valore è superiore a 3000. In tal caso, il programma procederà a consigliarti di fare una vacanza senza spendere troppi soldi per il viaggio.</p><p>Puoi scrivere tante istruzioni <code>else if</code> quante necessarie e ognuna verrà eseguita solo se l'istruzione precedente non viene soddisfatta.</p><p>Insieme, le istruzioni <code>if..else..else if</code> consentono di eseguire diversi blocchi di codice a seconda della condizione affrontata dal programma.</p><h3 id="11-2-istruzione-switch-case"><strong>11.2 - Istruzione switch...case</strong></h3><p>L'istruzione <code>switch</code> fa parte della sintassi principale di JavaScript che consente di controllare il flusso di esecuzione del codice.</p><p>È spesso pensata come un'alternativa all'istruzione <code>if..else</code> in quanto ti dà un codice più leggibile, specialmente quando hai molte condizioni diverse da valutare.</p><p>Ecco un esempio di un'istruzione <code>switch</code> funzionante. Spiegherò il codice qui sotto:</p><pre><code class="language-js">let age = 15;
switch (age) {
  case 10:
    console.log("Hai 10 anni");
    break;
  case 20:
    console.log("Hai 20 anni");
    break;
  default:
    console.log("Non hai nè 10 nè 20 anni");
}
</code></pre><p>Innanzitutto, è necessario passare tra parentesi un'espressione che deve essere valutata dall'istruzione <code>switch</code>. Nell'esempio, la variabile <code>age</code> viene passata come argomento per la valutazione.</p><p>Quindi, devi scrivere i valori <code>case</code> che l'istruzione <code>switch</code> cercherà di far corrispondere alla tua espressione. Il valore per <code>case</code> è immediatamente seguito da due punti (<code>:</code>) per contrassegnare l'inizio del blocco case:</p><pre><code class="language-js">case "apple":
</code></pre><p>Tieni presente il tipo di dati del valore per <code>case</code> che si desidera far corrispondere all'espressione. Se vuoi abbinare una stringa, devi inserire un valore di tipo <code>string</code>. Le istruzioni <strong>switch non eseguiranno la coercizione di tipo</strong> quando hai un valore di tipo <code>number</code> come argomento ma metti un tipo <code>string</code> per <code>case</code>:</p><pre><code class="language-js">switch (1) {
  case "1":
    console.log("Hello World!");
    break;
}
</code></pre><p>Il valore di tipo <code>number</code> non corrisponde al valore per <code>case</code>, di tipo <code>string</code>, quindi JavaScript non stamperà nulla nella console.</p><p>Lo stesso accade anche per i valori booleani. Il numero 1 non sarà forzato come <code>true</code> e il numero 0 non sarà forzato come <code>false</code>:</p><pre><code class="language-js">switch (0) {
  case true:
    console.log("Hello True!");
    break;
  case false:
    console.log("Bonjour False!");
    break;
  default:
    console.log("No matching case");
}
</code></pre><!--kg-card-begin: markdown--><p><a name="11-3-corpo-dell-istruzione-switch-case"></a></p>
<h3 id="113corpodellistruzioneswitchcase">11.3 - Corpo dell'istruzione switch...case</h3>
<!--kg-card-end: markdown--><p>Il corpo dell'istruzione <code>switch</code> è composto da tre parole chiave:</p><ul><li><code>case</code> per iniziare un blocco di codice case</li><li><code>break</code> per impedire all'istruzione <code>switch</code> di eseguire le successive istruzioni <code>case</code></li><li><code>default</code> per eseguire una parte di codice qualora non venga trovata alcuna corrispondenza di <code>case</code> per il valore di <code>switch</code>.</li></ul><p>Quando la tua espressione trova un <code>case</code> corrispondente, JavaScript eseguirà il codice che segue l'istruzione <code>case</code> finché non trova la parola chiave <code>break</code>. Se ometti la parola chiave <code>break</code>, l'esecuzione del codice continuerà al blocco successivo.</p><p>Dai un'occhiata al seguente esempio:</p><pre><code class="language-js">switch (0) {
  case 1:
    console.log("Il valore è uno");
  case 0:
    console.log("Il valore è zero");
  default:
    console.log("Nessuna corrispondenza");
}
</code></pre><p>Quando esegui il codice qui sopra, JavaScript stamperà:</p><pre><code class="language-shell">&gt; "Il valore è zero"
&gt; "Nessuna corrispondenza"
</code></pre><p>Questo perché senza la parola chiave <code>break</code>, <code>switch</code> continuerà a valutare l'espressione rispetto ai casi rimanenti anche quando è stato già trovato un caso corrispondente.</p><p>La tua valutazione switch può corrispondere a più di un caso, quindi la parola chiave <code>break</code> viene comunemente utilizzata per uscire dal processo una volta trovata una corrispondenza.</p><p>Infine, puoi anche inserire espressioni come valori di <code>case</code>:</p><pre><code class="language-js">switch (20) {
  case 10 + 10:
    console.log("value is twenty");
    break;
}
</code></pre><p>Devi tuttavia tenere presente che il valore per un blocco <code>case</code> deve <strong>corrispondere esattamente</strong> all'argomento di <code>switch</code>.</p><p>Uno degli errori più comuni quando si utilizza l'istruzione <code>switch</code> è che si pensa che il valore di <code>case</code> venga valutato come vero o falso.</p><p>I seguenti blocchi <code>case</code> non funzioneranno nelle istruzioni <code>switch</code>:</p><pre><code class="language-js">let age = 5;

switch (age) {
  case age &lt; 10:
    console.log("Il valore è minore di 10");
    break;
  case age &lt; 20:
    console.log("Il valore è minore di 20");
    break;
  default:
    console.log("Il valore è maggiore o uguale a 20");
}
</code></pre><p>Devi ricordarti delle differenze rispetto a come <code>if</code> e <code>case</code> eseguono la valutazione della condizione di verifica:</p><ul><li>Il blocco <code>if</code> verrà eseguito quando la condizione di verifica viene soddisfatta (<strong>valutata come <code>true</code></strong>)</li><li>Il blocco <code>case</code> verrà eseguito quando la condizione di verifica <strong>corrisponde esattamente</strong> a quella data come argomento a &nbsp;<code>switch</code> </li></ul><!--kg-card-begin: markdown--><p><a name="11-4-casi-d-uso-dell-istruzione-switch-case"></a></p>
<h3 id="114casidusodellistruzioneswitchcase">11.4 - Casi d'uso dell'istruzione switch...case</h3>
<!--kg-card-end: markdown--><p>La regola empirica da considerare per scegliere tra <code>if</code> e <code>switch</code> è questa:</p><blockquote><em>Usi<em> <code>switch</code> </em>solo quando il codice risulta complicato da scrivere usando <code>if</code></em></blockquote><p>Ad esempio, supponiamo di voler scrivere il nome di un giorno della settimana in base al numero del giorno della settimana.</p><p>Ecco come puoi scriverlo:</p><pre><code class="language-js">let weekdayNumber = 1;

if (weekdayNumber === 0) {
  console.log("Domenica");
} else if (weekdayNumber === 1) {
  console.log("Lunedì");
} else if (weekdayNumber === 2) {
  console.log("Martedì");
} else if (weekdayNumber === 3) {
  console.log("Mercoledì");
} else if (weekdayNumber === 4) {
  console.log("Giovedì");
} else if (weekdayNumber === 5) {
  console.log("Venerdì");
} else if (weekdayNumber === 6) {
  console.log("Sabato");
} else {
  console.log("Numero di giorno non valido");
}
</code></pre><p>Non posso sapere tu cosa ne pensi, ma il codice qui sopra sembra decisamente complicato per me! Anche se non vi è nulla di sbagliato in quel codice, puoi abbellirlo usando <code>switch</code>:</p><pre><code class="language-js">let weekdayNumber = 1;

switch (weekdayNumber) {
  case 0:
    console.log("Domenica");
    break;
  case 1:
    console.log("Lunedì");
    break;
  case 2:
    console.log("Martedì");
    break;
  case 3:
    console.log("Mercoledì");
    break;
  case 4:
    console.log("Giovedì");
    break;
  case 5:
    console.log("Venerdì");
    break;
  case 6:
    console.log("Sabato");
    break;
  default:
    console.log("Il numero del giorno non è valido");
}
</code></pre><p>Quando hai molte condizioni da valutare per lo stesso blocco, puoi probabilmente combinare più condizioni <code>if</code> usando gli operatori logici <strong>E<strong> (<code>&amp;&amp;</code>)</strong></strong> oppure <strong><strong>O</strong> <strong>(<code>||</code>)</strong></strong>:</p><pre><code class="language-js">let myFood = "Banana";

if (myFood === "Banana" || myFood === "Mela") {
  console.log("Mangia frutta ogni giorno per mantenerti sano.");
}

if (myFood === "Torta al cioccolato"
  console.log("Goditi un dolce regalo.");
}
</code></pre><p>È possibile sostituire il codice precedente utilizzando l'istruzione <code>switch</code>. La chiave è che devi impilare più <code>case</code> come fosse uno, &nbsp;in questo modo:</p><pre><code class="language-js">let myFood = "Banana";

switch (myFood) {
  case "Banana":
  case "Mela":
    console.log("Mangia frutta ogni giorno per mantenerti sano.");
    break;
  case "Chocolate Cake":
    console.log("Goditi un dolce regalo.");
    break;
}
</code></pre><p>Sfortunatamente, <code>switch</code> non può sostituire più condizioni <code>if</code> che usano l'operatore <code>&amp;&amp;</code> visto il modo nel quale il processo di valutazione di <code>case</code> funziona. Devi usare un'istruzione <code>if</code> in quel caso.</p><h3 id="11-5-esercizio-nr-5"><strong>11.5 - Esercizio nr. 5</strong></h3><p>Una scuola elementare fornisce diversi premi in base al giudizio conseguito da uno studente:</p><ul><li>Gli studenti che hanno ricevuto una A avranno del cioccolato</li><li>Gli studenti che hanno ricevuto una B avranno un biscotto</li><li>Gli studenti che hanno ricevuto una C avranno una caramella</li><li>Per tutti gli altri giudizi stampa "Nessun premio da dare."</li></ul><p>Crea una variabile chiamata <code>giudizio</code> che conserverà la valutazione data allo studente.</p><p>Esempio dei possibili risultati a seconda del valore di <code>giudizio</code>:</p><pre><code class="language-txt">Hai ottenuto una A, eccoti del cioccolato!
Hai ottenuto una B, eccoti un biscotto!
Hai ottenuto una C, c'è spazio per migliorare, eccoti una caramella!
Nessun premio da dare

</code></pre><p>Puoi usare sia istruzioni &nbsp;<code>if...else</code> che <code>switch...case</code>.</p><!--kg-card-begin: markdown--><p><a name="12-flussi-di-controllo-cicli"></a></p>
<h2 id="12flussidicontrollocicli">12 - Flussi di controllo (cicli)</h2>
<!--kg-card-end: markdown--><p>Quando si programma un'applicazione in JavaScript, è spesso necessario scrivere una parte di codice che deve essere eseguita ripetutamente.</p><p>Diciamo che vuoi scrivere un programma che stampi i numeri da 1 a 10 nella console. Puoi farlo chiamando <code>console.log</code> 10 volte in questo modo:</p><pre><code class="language-js">console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);

// e così via...
</code></pre><p>Funziona, ma c'è un modo migliore per scrivere questo tipo di attività ripetitiva.</p><p>Un'<strong>istruzione di ciclo (loop)</strong> è un'altra categoria di istruzione di flusso di controllo utilizzata per eseguire un blocco di codice più volte fintanto che viene soddisfatta una determinata condizione.</p><p>Esistono due istruzioni di ciclo utilizzate in JavaScript:</p><ul><li>L'istruzione <code>for</code></li><li>L'istruzione <code>while</code></li></ul><p>Impariamo come utilizzare queste istruzioni nella pratica.</p><h3 id="12-1-istruzione-for"><strong>12.1 - Istruzione for</strong></h3><p>Invece di ripetere te stesso 10 volte per stampare i numeri da 1 a 10, puoi usare l'istruzione <code>for</code> e scrivere solo una singola riga di codice come segue:</p><pre><code class="language-js">for (let x = 0; x &lt; 10; x++) {
  console.log(x);
}
</code></pre><p>Ecco qua! L'istruzione <code>for</code> è seguita da parentesi <code>()</code> all'interno delle quali ci sono 3 espressioni:</p><ul><li>L'espressione di <strong>inizializzazione</strong>, in cui si dichiari una variabile da utilizzare come origine della condizione del ciclo. Rappresentata come <code>x = 0</code> nell'esempio.</li><li>L'espressione di <strong>condizione</strong>, in cui la variabile nell'inizializzazione verrà valutata per una condizione specifica. Rappresentata come <code>x &lt; 10</code> nell'esempio.</li><li>L'espressione <strong>aritmetica</strong>, in cui il valore della variabile viene incrementato o decrementato alla fine di ogni ciclo.</li></ul><p>Queste espressioni sono separate da un punto e virgola (<code>;</code>).</p><p>Dopo le espressioni, le parentesi graffe <code>{}</code> verranno utilizzate per creare un blocco di codice che verrà eseguito da JavaScript fintanto che l'espressione della <strong>condizione</strong> restituisce <code>true</code>.</p><p>Puoi identificare a cosa corrispondono le espressioni prestando attenzione al punto e virgola (<code>;</code>) che termina l'istruzione.</p><pre><code class="language-js">for ( [inizializzazione]; [condizione]; [espressione aritmetica]) {
  // Fintanto che la condizione ritorna true,
  // Questo blocco verrà eseguito ripetutamente
}
</code></pre><p>L'espressione aritmetica può rappresentare un incremento (<code>++</code>) o un decremento (<code>--</code>) . Viene valutata ogni volta che l'esecuzione del blocco di codice all'interno delle parentesi graffe termina:</p><pre><code class="language-js">for (let x = 10; x &gt;= 1; x--) {
  console.log(x);
}
</code></pre><p>Puoi anche usare gli operatori scorciatoia aritmetici come <code>+=</code> e <code>-=</code> come mostrato qui sotto:</p><pre><code class="language-js">// Istruzione for con espressione scorciatoia aritmetica
for (let x = 1; x &lt; 20; x += 3) {
  console.log(x);
}
</code></pre><p>Qui, il valore di <code>x</code> sarà incrementato di 3 ogni volta che il ciclo viene eseguito.</p><p>Una volta terminato il ciclo, &nbsp;JavaScript continuerà a eseguire il codice che segue scritto al di fuori del corpo di <code>for</code>:</p><pre><code class="language-js">for (let x = 1; x &lt; 2; x++) {
  console.log(x);
}
console.log("Il ciclo for è terminato");
console.log("Continua l'esecuzione del codice");
</code></pre><h3 id="12-2-quando-usare-un-ciclo-for"><strong>12.2 - Quando usare un ciclo for</strong></h3><p>Il ciclo <code>for</code> è utile <strong>quando sai quante volte</strong> devi eseguire un'attività ripetitiva.</p><p>Ad esempio, supponiamo che tu stia scrivendo un programma per lanciare una moneta. Devi trovare quante volte esce testa quando la moneta viene lanciata 10 volte. Puoi farlo usando il metodo <code>Math.random</code>:</p><ul><li>Quando il numero è inferiore a 0,5 è necessario incrementare il contatore della variabile <code>tails</code> (croce).</li><li>Quando il numero è pari o superiore a 0,5, è necessario incrementare il contatore della variabile <code>heads</code> (testa)</li></ul><pre><code class="language-js">let heads = 0;
let tails = 0;
for (x = 1; x &lt;= 10; x++) {
  if (Math.random() &lt; 0.5) {
    tails++;
  } else {
    heads++;
  }
}

console.log("La moneta è stata lanciata 10 volte");
console.log(`Numero di volte in cui è uscito testa: ${heads}`);
console.log(`Numero di volte in cui è uscito croce: ${tails}`);
</code></pre><p>L'esempio qui sopra mostra dove il ciclo <code>for</code> offre l'approccio più efficace.</p><p>Ora vediamo un esercizio alternativo di lancio della moneta in cui il ciclo <code>for</code> non è efficace:</p><p><strong>Scopri quante volte devi lanciare una moneta finché non esce testa.</strong></p><p>Questa volta non sai <strong>quante volte</strong> devi lanciare la moneta. Qui è dove devi usare l'istruzione di ciclo <code>while</code>, che imparerai nella prossima sezione.</p><h3 id="12-3-istruzione-while"><strong>12.3 - Istruzione while</strong></h3><p>L'istruzione <code>while</code> o ciclo <code>while</code> viene utilizzato per eseguire un blocco di codice fintanto che la condizione restituisce <code>true</code>.</p><p>Puoi definire la condizione e l'istruzione per il ciclo come segue:</p><pre><code class="language-js">while (condizione) {
  istruzione;
}
</code></pre><p>Proprio come il ciclo <code>for</code>, il ciclo <code>while</code> viene utilizzato per eseguire ripetutamente un pezzo di codice finché la condizione indicata risulta vera.</p><p>Nell'esempio seguente, il blocco di istruzioni verrà eseguito fino a quando l'espressione della condizione non restituirà <code>false</code>:</p><pre><code class="language-js">let i = 0;

while (i &lt; 6) {
  console.log(`Il valore di i = ${i}`);
  i++;
}
</code></pre><p>Qui, il ciclo <code>while</code> stamperà ripetutamente il valore di <code>i</code> finché <code>i</code> è minore di 6. In ogni iterazione, il valore di <code>i</code> viene incrementato di 1 finché non raggiunge 6 e il ciclo termina.</p><p>Tieni presente che devi includere un pezzo di codice che prima o poi trasformi la condizione di valutazione in <code>false</code> o il ciclo while verrà eseguito per sempre. L'esempio seguente causerà un ciclo infinito:</p><pre><code class="language-js">let i = 0;

while (i &lt; 6) {
  console.log(`Il valore di i = ${i}`);
}
</code></pre><p>Visto che il valore di <code>i</code> non cambia mai, il ciclo <code>while</code> continuerà per sempre!</p><h3 id="12-4-quando-usare-un-ciclo-while"><strong>12.4 - Quando usare un ciclo while</strong></h3><p>Visto che entrambi <code>while</code> e <code>for</code> possono essere usati per eseguire ripetutamente un pezzo di codice, quando dovresti usare un ciclo <code>while</code> invece di <code>for</code>?</p><p>Un modo semplice per sapere quando dovresti usare <code>while</code> è quando <strong>non sai quante volte</strong> devi eseguire il codice.</p><p>Tornando all'esempio del lancio della moneta, c'è un caso che è perfetto per un ciclo <code>while</code>:</p><p><strong>Scopri quante volte devi lanciare una moneta finché non esce testa.</strong></p><p>Devi anche <strong>mostrare quante volte</strong> lanci la moneta finché non esce testa:</p><pre><code class="language-js">let flips = 0;
let isHeads = false;

while (!isHeads) {
  flips++;
  isHeads = Math.random() &lt; 0.5;
}

console.log(`Ci sono voluti ${flips} lanci per ottenere testa.`);
</code></pre><p>Qui la condizione <code>isHead = Math.random() &lt; 0.5</code> simula il lancio di una moneta. Quando il risultato è <code>true</code>, vuol dire che si è ottenuto testa e il ciclo sarà terminato.</p><p>Visto che non sai quanto volte dovrai eseguire il ciclo prima che esca testa, devi usare un ciclo <code>while</code> invece che un ciclo <code>for</code>.</p><h3 id="12-5-esercizio-nr-6">12.5 - Esercizio nr. 6</h3><p>Scrivi un programma che stampi una mezza piramide usando gli asterischi <code>*</code> , il cui risultato è mostrato qui sotto:</p><pre><code class="language-txt">*
**
***
****
*****
</code></pre><p>Poi stampa una mezza piramide rovesciata, come segue:</p><pre><code class="language-txt">*****
****
***
**
*
</code></pre><h2 id="13-funzioni"><strong>13 - Funzioni</strong></h2><p>Una funzione è semplicemente una sezione (o un blocco) di codice scritto per eseguire un'attività specifica.</p><p>Ad esempio, la funzione di conversione di tipo <code>String()</code> viene utilizzata per convertire i dati di un altro tipo in una stringa.</p><p>Anche <code>console.log()</code> e vari metodi di array che abbiamo imparato nei capitoli precedenti sono funzioni. Ma poiché queste funzioni vengono invocate da un oggetto, vengono chiamate metodi.</p><p>Imparerai di più sui metodi più avanti nel <a href="#14-oggetti">capitolo 14</a>. Per ora, sappi solo che una funzione e un metodo sono essenzialmente la stessa cosa, tranne per il fatto che un metodo viene chiamato da un oggetto.</p><p>Oltre alle funzioni integrate fornite da JavaScript, puoi anche creare una tua funzione.</p><h3 id="13-1-come-creare-la-tua-funzione"><strong>13.1 - Come creare la tua funzione</strong></h3><p>La creazione di una funzione inizia con la digitazione della parola chiave <code>function</code> seguita dal nome della funzione, una coppia di parentesi tonde, quindi una coppia di parentesi graffe.</p><p>Ecco un esempio:</p><pre><code class="language-js">function greet() {
  // Qui il corpo della funzione
  console.log("Ciao!");
}
</code></pre><p>Per chiamare una funzione, devi specificarne il nome seguito dalle parentesi tonde:</p><pre><code class="language-js">greet(); // Ciao!
</code></pre><p>Il codice all'interno della funzione viene eseguito quando chiami la funzione.</p><h3 id="13-2-parametri-e-argomenti-della-funzione"><strong>13.2 - Parametri e argomenti della funzione</strong></h3><p>I parametri sono variabili utilizzate per accettare input forniti quando viene chiamata la funzione.</p><p>È possibile specificare i parametri nell'intestazione della funzione, all'interno delle parentesi tonde.</p><p>L'esempio seguente mostra una funzione che ha un parametro chiamato <code>name</code>:</p><pre><code class="language-js">function greet(name) {
  // corpo della funzione
}
</code></pre><p>Come userai il parametro <code>name</code> all'interno della funzione è una tua decisione.</p><p>Potresti usare il parametro all'interno di una funzione <code>print()</code>, in questo modo:</p><pre><code class="language-js">function greet(name) {
  console.log(`Ciao, ${name}!`);
  console.log("Bel tempo oggi, non è vero?");
}
</code></pre><p>Ora ogni volta che devi chiamare la funzione <code>greet()</code>, devi passare un valore per il parametro <code>name</code>.</p><p>Il valore che hai passato per il parametro viene detto argomento, ecco come fare:</p><pre><code class="language-js">greet("Peter");
</code></pre><p>La stringa 'Peter' all'interno delle parentesi quando chiami la funzione verrà passata come valore del parametro <code>name</code>.</p><p>Esegui il codice e otterrai questo risultato:</p><pre><code class="language-txt">Ciao, Peter!
Bel tempo oggi, non è vero?
</code></pre><p>Puoi avere più di un parametro quando definisci la funzione, ma devi separare ciascun parametro con un virgola, come segue:</p><pre><code class="language-js">function greet(name, weather) {
  console.log(`Ciao, ${name}!`);
  console.log(`Oggi è ${weather}, non è vero?`);
}

greet("Nathan", "piovoso");
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">Ciao, Nathan!
Oggi è piovoso, non è vero?
</code></pre><p>Quando specifichi due parametri nell'intestazione della funzione, è necessario passare due argomenti. Se chiami la funzione senza passare gli argomenti, il valore sarà <code>undefined</code>.</p><p>Nella sezione successiva imparerai come creare parametri con valori predefiniti, che ti consentono di chiamare la funzione senza doverle passare un argomento.</p><p>Per ora, spero che tu veda la comodità di avere parametri. Rendono le tue funzioni più adattabili e riutilizzabili ricevendo diversi valori per coprire una varietà di scenari che la funzione potrebbe rappresentare.</p><p>Come mostrato nell'esempio, i parametri <code>name</code> (nome) e <code>weather</code> (tempo) ti consentono di salutare molte persone diverse in condizioni meteorologiche diverse.</p><p>Che sia soleggiato, piovoso o nuvoloso, basta cambiare <code>name</code> e <code>weather</code> quando vuoi salutare un'altra persona.</p><h3 id="13-3-parametri-predefiniti"><strong>13.3 - Parametri predefiniti</strong></h3><p>Quando definisci una funzione, puoi impostare un valore predefinito per qualsiasi parametro in quella funzione.</p><p>Per esempio il parametro <code>name</code> nella funzione qui sotto è un parametro predefinito:</p><pre><code class="language-js">function greet(name = "Nathan") {
  console.log(`Ciao ${name}!`);
  console.log("Bel tempo oggi, non è vero?");
}
</code></pre><p>Qui il valore predefinito 'Nathan' verrà usato se nessun valore oppure <code>undefined</code> viene passato per il parametro <code>name</code>.</p><p>Puoi verificarlo chiamando la funzione <code>greet()</code> senza argomento, in questo modo:</p><pre><code class="language-js">greet();
greet("Jack");
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">Ciao, Nathan!
Bel tempo oggi, non è vero?

Ciao, Jack!
Bel tempo oggi, non è vero?
</code></pre><p>Qualunque funzione tu definisca, può avere un misto di parametri predefiniti e non predefiniti.</p><p>Ecco un'altro esempio di una funzione con un parametro predefinito (<code>name</code>) e uno non predefinito (<code>weather</code>):</p><pre><code class="language-js">function greet(weather, name = "Nathan") {
  console.log(`Ciao, ${name}!`);
  console.log(`Oggi è ${weather}, non è vero?`);
}

greet("soleggiato");
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">Ciao, Nathan!
Oggi è soleggiato, non è vero?
</code></pre><p>Nota che il parametro <code>weather</code> è stato posizionato davanti al parametro <code>name</code>. Questo è per comodità in modo che non sia necessario specificare il parametro predefinito.</p><p>Se inserisci il parametro non predefinito dopo il parametro predefinito, devi passare un valore al parametro <code>name</code> per arrivare al parametro <code>weather</code>.</p><p>Considera l'esempio seguente:</p><pre><code class="language-js">function greet(name = "Nathan", weather) {
  console.log(`Ciao, ${name}!`);
  console.log(`Oggi è ${weather}, non è vero?`);
}

greet(undefined, "sunny");
</code></pre><p>Per passare un argomento al parametro &nbsp;<code>weather</code> , devi prima passare <code>undefined</code> o un altro valore al parametro <code>name</code>.</p><p>Ecco perché è meglio specificare i parametri non definiti prima di quelli predefiniti.</p><h3 id="13-4-parametri-predefiniti-e-null"><strong>13.4 - Parametri predefiniti e null</strong></h3><p>Se ricordi, nella <a href="#7-5-null">sezione 7.5</a> abbiamo esplorato brevemente la differenza tra <code>undefined</code> come valore vuoto "predefinito" e <code>null</code> come valore vuoto "intenzionale".</p><p>Quando a una funzione si passa <code>undefined</code> per un parametro predefinito, verrà utilizzato il valore del parametro predefinito:</p><pre><code class="language-js">function greet(name = "John"){
  console.log(name);
}

greet(undefined); // John
</code></pre><p>Come puoi vedere, JavaScript stampa il valore del parametro predefinito "John" quando passi <code>undefined</code> alla funzione.</p><p>Ma quando passi <code>null</code> alla funzione, il parametro predefinito verrà ignorato:</p><pre><code class="language-js">function greet(name = "John"){
  console.log(name);
}

greet(null); // null
</code></pre><p>Questo è uno degli errori più comuni che commettono i principianti quando imparano JavaScript. Quando usi il valore <code>null</code>, JavaScript penserà che vuoi che quel valore sia vuoto, quindi non sostituisce il valore con il parametro predefinito.</p><p>Quando utilizzi <code>undefined</code>, JavaScript lo sostituirà con il parametro predefinito. Potresti riscontrare questo problema mentre lavori con il codice JavaScript nella tua carriera, quindi tienilo a mente.</p><h3 id="13-5-istruzione-return"><strong>13.5 - Istruzione return</strong></h3><p>Una funzione può anche avere un'istruzione <code>return</code> all'interno del blocco di codice. Un'istruzione <code>return</code> viene utilizzata per restituire un valore al chiamante.</p><p>Ad esempio, la seguente funzione restituisce la somma di due valori:</p><pre><code class="language-js">function sum(a, b) {
  return a + b;
}

let result = sum(3, 2);
console.log(result); // 5
</code></pre><p>Il valore restituito da una funzione può essere assegnato a una variabile per ulteriori operazioni. Puoi aggiungere l'istruzione <code>return</code> ovunque all'interno della funzione.</p><p>Quando JavaScript raggiunge l'istruzione <code>return</code>, salta l'ulteriore codice scritto all'interno del blocco funzione e torna al punto in cui chiami la funzione.</p><p>La seguente funzione ha due istruzioni return:</p><pre><code class="language-js">function checkAge(age) {
  if (age &gt; 18) {
    return "Puoi prendere la patente";
  }
  return "Non puoi ancora prendere la patente";
}

console.log(checkAge(20));
console.log(checkAge(15));
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">Puoi prendere la patente
Non puoi ancora prendere la patente</code></pre><p>Quando chiamiamo la funzione <code>checkAge()</code> la prima volta, il valore dell'argomento <code>age</code> (età) è maggiore di 18, quindi JavaScript esegue l'istruzione <code>return</code> all'interno del blocco <code>if</code>.</p><p>La seconda volta che abbiamo chiamato la funzione, la condizione <code>if</code> non è soddisfatta, quindi JavaScript esegue invece l'istruzione <code>return</code> sotto il blocco <code>if</code>.</p><p>Puoi anche interrompere l'esecuzione di una funzione e tornare al chiamante specificando l'istruzione <code>return</code> senza alcun valore:</p><pre><code class="language-js">function greet() {
  console.log("Ciao!");
  return;
  console.log("Arriverderci!!");
}

greet()
</code></pre><p><strong>Risultato</strong>:</p><pre><code class="language-txt">Ciao!
</code></pre><p>Qui, l'istruzione <code>return</code> viene invocata tra le chiamate delle funzioni <code>console.log()</code>.</p><p>JavaScript esegue la prima chiamata di <code>console.log()</code>, quindi salta il resto del codice. La stringa 'Arrivederci!' non viene stampata.</p><h3 id="13-6-ambito-di-una-variabile"><strong>13.6 - Ambito di una variabile</strong></h3><p>Ora che stai imparando le funzioni, è un buon momento per parlare dell'ambito di una variabile.</p><p>Una variabile dichiarata all'interno di una funzione è accessibile solo da quella funzione. Questo perché quella variabile ha un ambito locale.</p><p>D'altro canto, una variabile dichiarata al di fuori di qualsiasi blocco è nota come variabile globale a causa del suo ambito globale.</p><p>Questi due ambiti sono importanti perché quando provi ad accedere a una variabile locale al di fuori del suo ambito, riceverai un errore. Per esempio:</p><pre><code class="language-js">function greet() {
  let myString = "Hello World!";
}

greet();
console.log(myString);
</code></pre><p>Quando esegui il codice qui sopra JavaScript risponde con un errore, dicendo che la variabile <code>myString</code> non è definita:</p><pre><code class="language-txt">ReferenceError: myString is not defined
</code></pre><p>Questo perché la variabile <code>myString</code> è dichiarata all'interno della funzione <code>greet()</code>, quindi non puoi accedere a quella variabile al di fuori di essa. Non importa anche se hai chiamato quella funzione prima di accedere alla variabile.</p><p>Viceversa, è possibile accedere a una variabile globale da qualsiasi punto, anche all'interno di una funzione:</p><pre><code class="language-js">let myString = "Hello World!";

function greet() {
  console.log(myString);
}

greet(); // Hello World!
</code></pre><p>Qui, la funzione <code>greet()</code> è in grado di accedere alla variabile <code>myString</code> dichiarata al di fuori della funzione.</p><p>Tieni presente che questo vale solo per le variabili dichiarate usando <code>let</code> e <code>const</code>.</p><p>Puoi anche definire una variabile locale con lo stesso nome della variabile globale senza sovrascriverla.</p><p>Ecco un esempio:</p><pre><code class="language-js">let myString = "Hello World!";

function greet() {
  let myString = "Morning!";
  console.log(myString);
}

greet();  // Morning!
console.log(myString); // Hello World!
</code></pre><p>Quando chiami la funzione <code>greet()</code>, alla variabile locale chiamata <code>myString</code> è stata assegnata la stringa 'Morning!'.</p><p>Al di fuori della funzione, la variabile globale anch'essa chiamata <code>myString</code> esiste ancora e il valore non viene modificato.</p><p>JavaScript considera la variabile di ambito locale come una variabile diversa. Quando dichiari la stessa variabile all'interno di una funzione, qualsiasi codice all'interno della funzione farà sempre riferimento alla variabile locale.</p><p>In pratica, raramente è necessario dichiarare una variabile con lo stesso nome in ambiti diversi:</p><ul><li>Qualsiasi variabile dichiarata all'esterno di una funzione non dovrebbe essere utilizzata all'interno di una funzione senza passarla come parametro.</li><li>Una variabile dichiarata all'interno di una funzione non dovrebbe mai riferirsi al di fuori di tale funzione</li></ul><p>Tienilo a mente quando scrivi funzioni JavaScript.</p><h3 id="13-7-parametro-rest"><strong>13.7 - Parametro rest</strong></h3><p>Il parametro rest è un parametro che può accettare qualsiasi numero di dati come argomenti. Gli argomenti verranno memorizzati come un array.</p><p>È possibile definire un parametro rest nell'intestazione della funzione aggiungendo tre punti <code>...</code> prima del nome del parametro.</p><p>Ecco un esempio di creazione di una funzione che ha un argomento di lunghezza variabile:</p><pre><code class="language-js">function printArguments(...args){
    console.log(args);
}
</code></pre><p>Quando si chiama la funzione &nbsp;<code>printArguments()</code> qui sopra, puoi specificare tanti argomenti quanti ne vuoi:</p><pre><code class="language-js">function printArguments(...args){
    console.log(args);
}

printArguments("A", "B", "C"); 
// [ 'A', 'B', 'C' ]
printArguments(1, 2, 3, 4, 5);
// [ 1, 2, 3, 4, 5 ]
</code></pre><p>Tieni presente che una funzione può avere solo un parametro rest e il parametro rest deve essere l'ultimo parametro nella funzione.</p><p>Puoi utilizzare un parametro rest quando la tua funzione deve lavorare con un numero indefinito di argomenti.</p><h3 id="13-8-funzione-freccia"><strong>13.8 - Funzione freccia</strong></h3><p>La <strong>sintassi della funzione freccia</strong> consente di scrivere una funzione JavaScript con una sintassi più breve e concisa.</p><p>Quando è necessario creare una funzione, il metodo principale consiste nell'utilizzare la parola chiave <code>function</code> seguita dal nome della funzione come mostrato di seguito:</p><pre><code class="language-js">function greetings(name) {
  console.log(`Hello, ${name}!`);
}

greetings("John"); // Hello, John!
</code></pre><p>La sintassi della funzione freccia consente la creazione di una espressione funzione che produce lo stesso risultato del codice qui sopra.</p><p>Ecco la funzione <code>greetings()</code> riscritta usando la sintassi freccia:</p><pre><code class="language-js">const greetings = (name) =&gt; {
  console.log(`Hello, ${name}!`);
};

greetings("John"); // Hello, John!
</code></pre><p>Quando crei una funzione usando la sintassi freccia, devi assegnare l'espressione a una variabile in modo che la funzione abbia un nome.</p><p>Fondamentalmente, la sintassi della funzione freccia è la seguente:</p><pre><code class="language-js">const nomeFunzione = (param1, param2, ...) =&gt; {
  // corpo della funzione
}
</code></pre><p>Nella descrizione generica della funzione freccia qui sopra,</p><ul><li><code>nomeFunzione</code> è il nome della variabile alla quale viene assegnata la funzione. Puoi chiamare la funzione successivamente nel tuo codice con <code>nomeFunzione()</code>.</li><li><code>(param1, param2, ...)</code> sono i parametri della funzione. Puoi definire tanti parametri quanti sono necessari alla funzione.</li><li>di seguito la freccia <code>=&gt;</code> che indica l'inizio della funzione.</li></ul><p>Il codice qui sopra equivale a scrivere:</p><pre><code class="language-js">const nomeFunzione = function(param1, param2, ...) {
  // corpo della funzione
}
</code></pre><p>La sintassi della funzione freccia non aggiunge nuove capacità al linguaggio.</p><p>Viceversa offre un miglioramento nel modo nel quale scrivi una funzione in JavaScript.</p><p>Sulle prime potrebbe sembrare strano, se sei abituato a utilizzare la parola chiave <code>function</code>.</p><p>Ma quando inizi a usare la sintassi della freccia, vedrai che è molto comodo e più facile da scrivere.</p><!--kg-card-begin: markdown--><p><a name="13-9-funzioni-freccia-su-singola-riga-o-più-righe"></a></p>
<h3 id="139funzionifrecciasusingolarigaopirighe">13.9 - Funzioni freccia su singola riga o più righe</h3>
<!--kg-card-end: markdown--><p>La funzione freccia ti fornisce un modo per scrivere una funzione su riga singola in cui il lato destro della freccia <code>=&gt;</code> viene restituito al lato sinistro.</p><p>Quando usi la parola chiave <code>function</code>, devi usare le parentesi graffe <code>{}</code> e la parola chiave <code>return</code> come segue:</p><pre><code class="language-js">function plusTwo(num) {
  return num + 2;
}
</code></pre><p>Usando la funzione freccia, puoi omettere sia le parentesi graffe che la parola chiave <code>return</code>, creando una funzione su una sola riga, come segue:</p><pre><code class="language-js">const plusTwo = (num) =&gt; num + 2;
</code></pre><p>Senza le parentesi graffe, JavaScript valuta l'espressione alla destra della freccia e la ritorna al chiamante.</p><p>La sintassi della funzione freccia va bene anche per funzioni che non ritornano un valore, come mostrato qui sotto:</p><pre><code class="language-js">const greetings = () =&gt; console.log("Hello World!");
</code></pre><p>Quando usi la sintassi della funzione freccia, le parentesi graffe sono richieste solo quando il corpo della funzione è composto da più righe:</p><pre><code class="language-js">const greetings = () =&gt; {
  console.log("Hello World!");
  console.log("How are you?");
};
</code></pre><h3 id="13-10-funzione-freccia-senza-parentesi-tonde"><strong>13.10 Funzione freccia senza parentesi tonde</strong></h3><p>Le parentesi tonde <code>()</code> sono usate nelle funzioni &nbsp;JavaScript per contenere i parametri che può ricevere la funzione.</p><p>Quando usi la parola chiave <code>function</code> , le parentesi tonde sono richieste:</p><pre><code class="language-js">function plusThree(num) {
  return num + 3;
}
</code></pre><p>La funzione freccia, viceversa, consente di omettere le parentesi tonde quando la funzione ha <strong>esattamente un solo parametro</strong>.</p><p>Questo codice di esempio è una espressione di funzione freccia valida:</p><pre><code class="language-js">const plusThree = num =&gt; num + 3;
</code></pre><p>Come puoi vedere si possono eliminare la parentesi tonde e graffe, così come la parola chiave <code>return</code>.</p><p>Devi tuttavia usare la parentesi tonde quando si verificano le seguenti condizioni:</p><ul><li>la funzione non ha parametri</li><li>la funzione ha più di un parametro</li></ul><p>Quando non hai parametri, devi usare le parentesi tonde, in questo modo:</p><pre><code class="language-js">const greetings = () =&gt; console.log("Hello World!");
</code></pre><p>Lo stesso vale se hai più di un parametro.</p><p>La funzione che segue ha due parametri: <code>name</code> e <code>age</code>.</p><pre><code class="language-js">const greetings = (name, age) =&gt; console.log("Hello World!");
</code></pre><p>La sintassi della funzione freccia rende le parentesi tonde opzionali quando hai una funzione con un solo parametro.</p><h3 id="13-11-la-funzione-freccia-non-ha-associazione-con-arguments"><strong>13.11 - La funzione freccia non ha associazione con <code>arguments</code></strong></h3><p>Quando usi la parola chiave &nbsp;<code>function</code> per definire una funzione, puoi accedere agli argomenti che riceve usando la parola chiave <code>arguments</code>, così:</p><pre><code class="language-js">const printArgs = function () {
  console.log(arguments);
};

printArgs(1, 2, 3);
// [Arguments] { '0': 1, '1': 2, '2': 3 }
</code></pre><p>Nel codice qui sopra, la parola chiave <code>arguments</code> fa riferimento all'oggetto che conserva tutti gli argomenti passati alla funzione.</p><p>Al contrario, la funzione freccia non ha l'oggetto <code>arguments</code> e darà errore quando tenti di accedervi:</p><pre><code class="language-js">const printArgs = () =&gt; console.log(arguments);

printArgs(1, 2, 3);
//Uncaught ReferenceError: arguments is not defined 
//Errore di riferimento non gestito: arguments non è definito
</code></pre><p>Puoi usare la sintassi JavaScript spread per imitare l'associazione con <code>arguments</code> come segue:</p><pre><code class="language-js">const printArgs = (...arguments) =&gt; console.log(arguments);

printArgs(1, 2, 3);
// [1, 2, 3]
</code></pre><p>Utilizzando la sintassi spread, gli argomenti passati alla funzione freccia verranno memorizzati in un array.</p><p>Nota che se usi la sintassi spread hai bisogno delle parentesi tonde anche se stai passando solo un argomento alla funzione.</p><p>È possibile accedere agli argomenti ricevuti con la notazione dell'indice dell'array come <code>arguments[0]</code>, <code>arguments[1]</code> nell'esempio e così via.</p><h3 id="13-12-convertire-facilmente-una-funzione-normale-in-funzione-freccia"><strong>13.12 - Convertire facilmente una funzione normale in &nbsp;funzione freccia</strong></h3><p>Puoi seguire <strong>tre semplici passaggi</strong> per convertire una funzione normale in funzione freccia:</p><ol><li>Sostituisci la parola chiave <code>function</code> con una dichiarazione di variabile <code>let</code> o <code>const</code>.</li><li>Aggiungi il simbolo <code>=</code> dopo il nome della funzione e prima delle parentesi tonde.</li><li>Aggiungi il simbolo <code>=&gt;</code> dopo le parentesi tonde.</li></ol><p>Il codice qui sotto ti aiuterà a visualizzare i passaggi:</p><pre><code class="language-js">function plusTwo(num) {
  return num + 2;
}

// step 1: sostituisci function con let / const
const plusTwo(num) {
  return num + 2;
}

// step 2: aggiungi = dopo il nome della funzione
const plusTwo = (num) {
  return num + 2;
}

// step 3: aggiungi =&gt; dopo le parentesi tonde
const plusTwo = (num) =&gt; {
  return num + 2;
}
</code></pre><p>I tre passaggi precedenti sono sufficienti per convertire qualsiasi vecchia sintassi della funzione JavaScript nella nuova sintassi della funzione freccia.</p><p>Quando hai una funzione su riga singola, c'è un quarto passaggio facoltativo per rimuovere le parentesi graffe e la parola chiave <code>return</code> come segue:</p><pre><code class="language-js">// da così
const plusTwo = num =&gt; {
  return num + 2;
};

// a così
const plusTwo = num =&gt; num + 2;
</code></pre><p>Quando hai esattamente un solo parametro puoi anche rimuovere le parentesi tonde:</p><pre><code class="language-js">// da così
const plusTwo = (num) =&gt; num + 2;

// a così
const plusTwo = num =&gt; num + 2;
</code></pre><p>Tuttavia gli ultimi due passaggi sono opzionali. Solo i primi tre sono necessari per convertire qualunque funzione scritta con <code>function</code> e usare la sintassi della funzione freccia.</p><h3 id="13-13-esercizio-nr-7"><strong>13.13 Esercizio nr. 7</strong></h3><p>Scrivi una funzione chiamata <code>calcolaQuadrato()</code> che viene utilizzata per calcolare l'area e il perimetro di una forma quadrata.</p><p>La funzione accetta un solo parametro (<code>lato</code>), che rappresenta il lato del quadrato.</p><p>La formula per calcolare l'area è &nbsp;<code>lato * lato</code> e la formula per calcolare il perimetro è <code>4 * lato</code></p><p>Il risultato che mostra la dimensione del lato, l'area e il perimetro potrebbe essere come segue se l'argomento del parametro <code>lato</code> è 8:</p><pre><code class="language-txt">Il lato del quadrato è 8
L'area del quadrato è 64
Il perimetro del quadrato è 32
</code></pre><h2 id="14-oggetti"><strong>14 - Oggetti</strong></h2><p>Un oggetto è un tipo di dato speciale che consente di memorizzare più di un valore, proprio come un array.</p><p>La differenza tra un oggetto e un array è che un array memorizza i dati come un elenco di elementi, mentre un oggetto memorizza i dati nel formato di coppia <code>chiave:valore</code>.</p><p>Vediamo un esempio che illustra questa differenza. Supponi di voler memorizzare informazioni su un libro nel tuo programma.</p><p>Usare variabili normali, sarebbe simile a questo:</p><pre><code class="language-js">let titoloLibro = "JavaScript Introduction";
let autoreLibro = "Nathan Sebhastian";
</code></pre><p>Questo va bene ma non è certo il modo migliore per memorizzare valori in relazione tra loro.</p><p>Un altro modo di conservare il valore sarebbe usare un array:</p><pre><code class="language-js">let mioLibro = ["JavaScript Introduction", "Nathan Sebhastian"];
</code></pre><p>Questo è certamente meglio in quanto puoi raggruppare i dati correlati, ma non hai modo di aggiungere contesto al valore.</p><p>Ecco quando torna utile un oggetto. Puoi dichiarare un oggetto che rappresenta un singolo libro e conservare i dati nel formato <code>chiave:valore</code>:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};
</code></pre><p>Un oggetto viene dichiarato utilizzando le parentesi graffe <code>{}</code> e ogni elemento all'interno delle parentesi è scritto nel formato <code>chiave:valore</code>.</p><p>Un elemento di un oggetto è anche noto come proprietà, con la <em>chiave</em> che rappresenta il nome della proprietà e il <em>valore</em> il contenuto della proprietà.</p><p>Come un array, devi separare ogni elemento all'interno di un oggetto usando una virgola.</p><p>Puoi assegnare una stringa o numeri come chiave di un elemento e puoi assegnare qualsiasi tipo di dato come valore, inclusa una funzione:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
  descrizione: function () {
    console.log(`Titolo: ${this.titolo}`);
    console.log(`Autore: ${this.autore}`);
  },
};
</code></pre><p>Qui, la chiave <code>descrizione</code> è una funzione che stampa il valore di <code>titolo</code> e <code>autore</code> dall'oggetto.</p><p>La parola chiave <code>this</code> si riferisce al contesto del codice, che in questo caso è l'oggetto <code>mioLibro</code>.</p><p>Di solito, la chiave in un oggetto è qualcosa che fornisce più contesto al valore che contiene. Una chiave deve anche essere univoca, quindi non puoi usare la stessa chiave due volte nello stesso oggetto.</p><p>Ad esempio, se disponi di dati su un libro, puoi utilizzare chiavi come <code>titolo</code>, <code>autore</code> e <code>prezzo</code> per aiutarti a comprendere il contesto del valore memorizzato in ciascuna chiave.</p><h3 id="14-1-accedere-ai-valori"><strong>14.1 - Accedere ai valori</strong></h3><p>Per accedere ai valori di un oggetto puoi utilizzare la notazione punto (<code>.</code>) oppure le parentesi quadre <code>[]</code>.</p><p>Ecco un esempio di accesso alle proprietà di un oggetto usando la notazione punto:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};

console.log(mioLibro.titolo);
console.log(mioLibro.autore);
</code></pre><p>Ecco come usare le parentesi quadre per accedere alle stesse proprietà:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};

console.log(mioLibro["titolo"]);
console.log(mioLibro["autore"]);

</code></pre><p>Ricorda che devi racchiudere il nome della proprietà tra apici, come una stringa, altrimenti &nbsp;JavaScript penserà che stai passando una variabile all'interno delle parentesi quadre.</p><!--kg-card-begin: markdown--><p><a name="14-2-aggiungere-una-nuova-proprieta"></a></p>
<h3 id="142aggiungereunanuovapropriet">14.2 - Aggiungere una nuova proprietà</h3>
<!--kg-card-end: markdown--><p>Puoi aggiungere una nuova proprietà a un oggetto usando sia la notazione punto che le parentesi quadre, così:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};

// aggiunge la proprietà anno di pubblicazione
mioLibro.anno = 2023;

// aggiunge la proprietà editore
mioLibro["editore"] = "CodeWithNathan";

console.log(mioLibro);
</code></pre><p>Quando stampi l'oggetto, ecco il risultato:</p><pre><code class="language-txt">{
  titolo: 'JavaScript Introduction',
  autore: 'Nathan Sebhastian',
  anno: 2023,
  editore: 'CodeWithNathan'
}
</code></pre><p>Puoi aggiungere tante proprietà quante necessarie allo stesso oggetto.</p><!--kg-card-begin: markdown--><p><a name="14-3-modificare-una-proprieta"></a></p>
<h3 id="143modificareunapropriet">14.3 - Modificare una proprietà</h3>
<!--kg-card-end: markdown--><p>Per modificare una proprietà esistente, devi specificarla con la notazione punto o con le parentesi quadre, quindi aggiungere l'operatore di assegnazione e il nuovo valore, in questo modo:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};

// modifica il valore della proprietà autore
mioLibro.autore = "John Doe";

console.log(mioLibro);
</code></pre><p><strong>Risultato</strong>:</p><pre><code class="language-txt">{
  titolo: 'JavaScript Introduction',
  autore: 'John Doe'
}
</code></pre><p>Come puoi vedere, il &nbsp;valore della proprietà <code>autore</code> è stato modificato.</p><!--kg-card-begin: markdown--><p><a name="14-4-eliminare-una-proprieta"></a></p>
<h3 id="144eliminareunapropriet">14.4 - Eliminare una proprietà</h3>
<!--kg-card-end: markdown--><p>Per eliminare una proprietà da un oggetto devi usare <code>delete</code> in questo modo:</p><pre><code class="language-js">let mioLibro = {
  titolo: "JavaScript Introduction",
  autore: "Nathan Sebhastian",
};

delete mioLibro.autore;

console.log(mioLibro);
</code></pre><p><strong>Risultato<strong>:</strong></strong></p><pre><code class="language-txt">{ titolo: 'JavaScript Introduction' }
</code></pre><p>Quando cerchi di accedere alla proprietà cancellata (o a una proprietà che non esiste), otterrai il valore <code>undefined</code>.</p><!--kg-card-begin: markdown--><p><a name="14-5-verificare-se-esiste-una-proprieta"></a></p>
<h3 id="145verificareseesisteunapropriet">14.5 Verificare se esiste una proprietà</h3>
<!--kg-card-end: markdown--><p>Per verificare se una data proprietà esiste nel tuo oggetto puoi usare l'operatore <code>in</code>, così:</p><pre><code class="language-js">nomeProprietà in mioOggetto
</code></pre><p>L'operatore <code>in</code> ritorna <code>true</code> se <code>nomeProprietà</code> esiste nel tuo oggetto.</p><p>Di seguito un esempio:</p><pre><code class="language-js">let persona = {
  nomeProprio: "Nathan",
  cognome: "Sebhastian"
}

// verifica se esiste 'nomeProprio'
console.log('nomeProprio' in persona); // true

// verifica se esiste 'eta'
console.log('eta' in persona); // false
</code></pre><p>Ora sai come manipolare gli oggetti JavaScript.</p><h3 id="14-6-esercizio-nr-8"><strong>14.6 - Esercizio nr. 8</strong></h3><p>Crea un oggetto <code>persona</code> con le seguenti proprietà:</p><ul><li><code>nome</code> - nome della persona</li><li><code>eta</code> - età della persona</li><li><code>saluto()</code> - una funzione per salutare un'altra persona</li></ul><p>All'interno della funzione <code>saluto()</code> introduci la persona, specificando nome ed età.</p><p>Ecco un esempio del risultato:</p><pre><code class="language-txt">persona.saluto();

Ciao! Mi chiamo Alex e ho 22 anni.
</code></pre><h2 id="15-esercizio-finale-sviluppare-un-registratore-di-cassa"><strong>15 - Esercizio finale: sviluppare un registratore di cassa</strong></h2><p>Sviluppiamo un registratore di cassa che può aggiungere elementi a un carrello della spesa, calcolare il prezzo totale, gli sconti e accettare il pagamento in contanti.</p><p>Ipotizziamo che la moneta sia il dollaro (USD) così che non lo dovrai specificare nel programma.</p><p>Il registratore di cassa ha 3 elementi in vendita:</p><ul><li>Un Telefono per 300</li><li>Una Smart TV per 220</li><li>Una Console di Gioco per 150</li></ul><p>C'è il 10% di sconto quando il prezzo totale supera 400.</p><p>Il registratore di cassa dovrebbe avere un carrello della spesa all'inizio vuoto.</p><p>Il registratore di cassa dovrebbe fornire un metodo chiamato <code>aggiungiArticolo</code> che riceve il nome di un articolo come parametro. Quando chiamato, dovrebbe verificare se l'articolo risulta disponibile per la vendita. In questo caso l'articolo dovrebbe essere aggiunto al carrello della spesa. Se l'articolo non è disponibile, mostra un messaggio che dice che quell'articolo non viene venduto.</p><p>Il registratore di cassa dovrebbe fornire un metodo chiamato <code>calcolaPrezzoTotale</code> che somma il prezzo di tutti gli articoli nel carrello della spesa. Dovrebbe iterare sugli articoli presenti nel carrello e sommare i loro prezzi.</p><p>Il registratore di cassa dovrebbe fornire un metodo chiamato <code>pagamento</code> che ottiene l'importo ricevuto per il pagamento come parametro.</p><p>Dovrebbe poi calcolare il prezzo totale degli articoli nel carrello usando il metodo <code>calcolaPrezzoTotale</code>. Se il totale è maggiore di 400, deve applicare lo sconto del 10%.</p><p>Il metodo dovrebbe poi confrontare la somma ricevuta dall'utente per il pagamento con il totale dovuto e mostrare un messaggio appropriato:</p><ul><li>Se il totale pagato è uguale o maggiore del prezzo degli articoli dovrebbe mostrare un messaggio che ringrazia il cliente per l'acquisto. Se c'è del resto dovrebbe mostrarne l'ammontare.</li><li>Se il totale pagato è minore del prezzo dovuto, dovrebbe visualizzare un messaggio che indica che il cliente non ha abbastanza denaro per pagare gli articoli acquistati.</li><li>Il programma dovrebbe includere delle istruzioni <code>console.log()</code> appropriate per stampare dei messaggi quando vengono aggiunti articoli al carrello, per visualizzare il prezzo totale e per elaborare il pagamento.</li></ul><p>Il programma dovrebbe gestire situazioni nelle quali il cliente paga esattamente il dovuto, quando il pagamento è minore del dovuto e quando pagamento è maggiore del dovuto.</p><p>Per sviluppare il programma devi sfruttare quello che hai imparato sugli oggetti, gli array i flussi condizionali e i cicli.</p><p>Ti consiglio di provare prima a sviluppare da solo il programma. Se non sai come proseguire allora verifica la soluzione fornita alla fine dell'articolo. Buona fortuna!</p><h2 id="16-conclusione"><strong>16 - Conclusione</strong></h2><p>Congratulazioni per aver terminato la lettura di questo manuale! Abbiamo esaminato insieme molti concetti per imparare a programmare utilizzando JavaScript.</p><p>Spero che ti sia piaciuto leggerlo tanto quanto io mi sono divertito a scriverlo. Mi piacerebbe ricevere il tuo feedback, sapere cosa ti è piaciuto e cosa no, così posso migliorare il tutorial.</p><p>Se vuoi saperne di più su JavaScript, sto creando un corso che ti aiuta a utilizzare JavaScript per creare applicazioni web. È attualmente in un periodo di pre-ordinazione, quindi puoi ottenere il corso a un prezzo inferiore e supportare il mio lavoro nella creazione di altri tutorial. Puoi <a href="https://codewithnathan.com/js-course">ricevere informazioni qui</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/nathan-js-tutorial.jpg" class="kg-image" alt="The JavaScript Tutorial by Nathan Sebhastian" width="600" height="400" loading="lazy"></figure><h2 id="17-soluzioni"><strong>17 - Soluzioni</strong></h2><h3 id="esercizio-nr-1"><strong>Esercizio nr. 1</strong></h3><pre><code class="language-js">console.log("Il tuo nome dovrebbe essere qui");
console.log("La tua età dovrebbe essere qui");
console.log("La tua occupazione dovrebbe essere qui");
</code></pre><h3 id="esercizio-nr-2"><strong>Esercizio nr. 2</strong></h3><pre><code class="language-js">let nome = "Il tuo nome dovrebbe essere qui";
let eta = "La tua età dovrebbe essere qui";
let occupazione = "La tua occupazione dovrebbe essere qui";

console.log(nome);
console.log(eta);
console.log(occupazione);
</code></pre><h3 id="esercizio-nr-3"><strong>Esercizio nr. 3</strong></h3><pre><code class="language-txt">1
false
true
true
true
false
</code></pre><h3 id="esercizio-nr-4"><strong>Esercizio nr. 4</strong></h3><pre><code class="language-js">let colori = ["rosso", "verde", "blu"];

colori.push("nero");
console.log(colori);

colori.shift();
colori[0] = "blu";
colori[1] = "verde";
console.log(colori);

colori.unshift("giallo");
console.log(colori);
</code></pre><h3 id="esercizio-nr-5"><strong>Esercizio nr. 5</strong></h3><p>Usando l'istruzione <code>if...else</code> :</p><pre><code class="language-js">let giudizio = "D";

if (giudizio === "A") {
  console.log("Hai ottenuto una A, eccoti del cioccolato");
} else if (giudizio === "B") {
  console.log("Hai ottenuto una B, eccoti un biscotto!");
} else if (giudizio === "C") {
  console.log(
    "Hai ottenuto una C, c'è spazio per migliorare, eccoti una caramella!"
  );
} else {
  console.log("Nessun premio da dare");
}</code></pre><p>Usando l'istruzione <code>switch...case</code> </p><pre><code class="language-js">let giudizio = "C";
switch (giudizio) {
  case "A":
    console.log("Hai ottenuto una A, eccoti del cioccolato");   
    break;
  case "B":
    console.log("Hai ottenuto una B, eccoti un biscotto!");
    break;
  case "C":
    console.log(
      "Hai ottenuto una C, c'è spazio per migliorare, eccoti una caramella!"  
   );
    break;
  default:
    console.log("Nessun premio da dare");

}</code></pre><h3 id="esercizio-nr-6"><strong>Esercizio nr. 6</strong></h3><p>Modello della mezza piramide:</p><pre><code class="language-js">let pattern;

for (let i = 1; i &lt;= 5; i++) {
  pattern = "";
  for (let j = 1; j &lt;= i; j++) {
    pattern += "*";
  }
  console.log(pattern);
}
</code></pre><p>Modello della mezza piramide invertita:</p><pre><code class="language-js">for (let i = 4; i &gt;= 0; i--) {
  pattern = "";
  for (let j = 0; j &lt;= i; j++) {
    pattern += "*";
  }
  console.log(pattern);
}
</code></pre><h3 id="esercizio-nr-7"><strong>Esercizio nr. 7</strong></h3><pre><code class="language-js">function calcolaQuadrato(lato) {
  console.log(`Il lato del quadrato è ${lato}`);
  console.log(`L'area del quadrato è ${lato * lato}`);
  console.log(`Il perimetro del quadrato è ${4 * lato}`);
}

calcolaQuadrato(7);
</code></pre><h3 id="esercizio-nr-8"><strong>Esercizio nr. 8</strong></h3><pre><code class="language-js">const persona = {
  nome: "Alex",
  eta: 22,
  saluto: function () {
    console.log(
      `Ciao! Mi chiamo ${this.nome} e ho ${this.age} anni.`
    );
  },
};

persona.saluto();
</code></pre><h3 id="esercizio-finale"><strong>Esercizio finale</strong></h3><p>Crea un file chiamato <code>registratoreDiCassa.js</code> e inserisci il seguente codice:</p><pre><code class="language-js">const registratoreDiCassa = {
  articoliInVendita: [
    { nome: "Telefono", prezzo: 300 },
    { nome: "Smart TV", prezzo: 220 },
    { nome: "Console di Gioco", prezzo: 150 },
  ],
  carrelloSpesa: [],
  aggiungiArticolo: function (nome) {
    let articoloTrovato = this.articoliInVendita.find(function (articolo) {
      return articolo.nome === nome;
    });
    if (articoloTrovato) {
      this.carrelloSpesa.push(articoloTrovato);
      console.log(`Aggiunto ${nome} al tuo carrello della spesa`);
    } else {
      console.log(`Mi dispiace, non vendiamo ${nome} qui!`);
    }
  },
  calcolaPrezzoTotale: function () {
    let prezzoTotale = 0;
    this.carrelloSpesa.forEach(function (articoloAcquistato) {
      prezzoTotale += articoloAcquistato.prezzo;
    });
    return prezzoTotale;
  },
  pagamento: function (pagato) {
    let prezzoTotale = this.calcolaPrezzoTotale();
    if (prezzoTotale &gt; 400) {
      prezzoTotale -= prezzoTotale * 0.1;
      console.log(
        `Hai il 10% di sconto e il tuo prezzo da pagare è ${prezzoTotale}`
      );
    }
    if (pagato &gt;= prezzoTotale) {
      if (pagato - prezzoTotale &gt; 0) {
        console.log(`Ecco il tuo resto ${amount - prezzoTotale}`);
      }
      console.log(`Grazie per l'acquisto! Speriamo di averti di nuovo qui!`);
    } else {
      console.log(
        "Spiacenti, non non hai abbastanza denaro per acquistare gli articoli nel carrello"
      );
    }
  },
};</code></pre><p>Per verificare il programma, aggiungi le righe seguenti alla fine del file <code>registratoreDiCassa.js</code>:</p><pre><code class="language-js">registratoreDiCassa.aggiungiArticolo("Telefono");
registratoreDiCassa.aggiungiArticolo("Smart TV");
console.log(registratoreDiCassa.calcolaPrezzoTotale());
registratoreDiCassa.pagamento(700);
</code></pre><p>Quando esegui il programma con <code>node registratoreDiCassa.js</code> dovresti ottenere questo risultato:</p><pre><code class="language-txt">Aggiunto Telefono al tuo carrello della spesa
Aggiunto Smart TV al tuo carrello della spesa
520
Hai il 10% di sconto e il tuo prezzo da pagare è 468
Ecco il tuo resto 232
Grazie per l'acquisto! Speriamo di averti di nuovo qui!
</code></pre><p>Grazie per la lettura!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Strutture Dati: Array — Una Introduzione Visuale per Principianti ]]>
                </title>
                <description>
                    <![CDATA[ Impara a conoscere le strutture dati che usi ogni giorno. 👋 Benvenuto! Iniziamo con un po' di necessario contesto. Ho qualche domanda per te: ✅ Ascolti musica sul tuo smartphone? ✅ Mantieni un elenco di contatti sul telefono? ✅ Hai mai visto una classifica durante una competizione? Se la tua ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/strutture-dati-array/</link>
                <guid isPermaLink="false">64a66f27aedaa5069ba96f62</guid>
                
                    <category>
                        <![CDATA[ programmazione ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 17 Jul 2023 08:08:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/07/1_plaTqL5DDa2MgqeK-0EClg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/data-structures-101-arrays-a-visual-introduction-for-beginners-7f013bcc355a/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Data Structures 101: Arrays — A Visual Introduction for Beginners</a>
      </p><h3 id="impara-a-conoscere-le-strutture-dati-che-usi-ogni-giorno-">Impara a conoscere le strutture dati che usi ogni giorno.</h3><p>👋 Benvenuto! Iniziamo con un po' di necessario contesto. Ho qualche domanda per te:<br>✅ Ascolti musica sul tuo smartphone?<br>✅ Mantieni un elenco di contatti sul telefono?<br>✅ Hai mai visto una classifica durante una competizione?</p><p><strong>Se la tua risposta è "sì" a una qualsiasi di queste domande, allora è quasi certo che hai usato gli array e non lo sapevi nemmeno!<strong><strong><strong> 😃 </strong></strong></strong></strong>Gli array sono strutture di dati molto potenti che memorizzano <strong>elenchi di elementi</strong>. Hanno infinite applicazioni. Sono molto importanti nel mondo dell'informatica.</p><p>In questo articolo imparerai i pro e i contro degli array, la loro struttura, le operazioni che puoi eseguire su di essi e i casi d'uso.</p><p><strong>Cominciamo!<strong> <strong><strong>👍</strong></strong></strong></strong></p><h3 id="-approfondimento-della-struttura-di-base-degli-array">🔎 Approfondimento della struttura di base degli array</h3><p>Per capire come funzionano, è molto utile visualizzare la memoria del tuo computer come una griglia, proprio come quella qui sotto. Ogni parte di informazione viene conservata in uno di quei piccoli elementi (i quadrati) che compongono la griglia.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/uxNDqnrhHuS197WjrTeak8WQq2QZKAJD5xp4" class="kg-image" alt="uxNDqnrhHuS197WjrTeak8WQq2QZKAJD5xp4" width="600" height="400" loading="lazy"></figure><p>Gli <strong>a<strong>rray </strong></strong>si avvalgono di questa struttura a "griglia" per <strong>conservare elenchi di informazioni correlate in posizioni di memoria adiacenti </strong>al fine di garantire estrema efficienza nel trovare questi valori. 🔳🔳🔳🔳</p><p><strong>Puoi visualizzare la struttura di un array in questo modo<strong>:</strong></strong></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-10-00-22.png" class="kg-image" alt="HjKZtf6JKxcrH8t51iRrId-4lTqjOlGtICip" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-06-10-00-22.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-06-10-00-22.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-10-00-22.png 1193w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p><strong>Gli elementi di un array sono adiacenti nella memoria. </strong>Se devi accedere a più di uno di essi, il processo è estremamente ottimizzato in quanto il tuo computer sa già dove si trova il valore.</p><p>Stupendo, non è vero? Impariamo come avviene dietro le quinte! 😃</p><h4 id="-classificazione"><strong><strong>📚 Classifica</strong>z<strong>ion</strong>e</strong></h4><p>Gli array sono classificati come <strong>Strutture Dati Omogenee</strong> in quanto conservano <strong>elementi dello stesso tipo</strong>.</p><p>Possono conservare numeri, stringhe, valori booleani (vero e falso), caratteri, oggetti e così via. Ma <strong>una volta definito il tipo di valore che dovrà contenere il tuo array, tutti i suoi elementi dovranno essere dello stesso tipo. Non puoi "mischiare" elementi di tipi diversi<strong>.</strong></strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/sbk9-CGxQ5VKddqpz9S12GxpR26I8f8e0hj6" class="kg-image" alt="sbk9-CGxQ5VKddqpz9S12GxpR26I8f8e0hj6" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-10-11-43.png" class="kg-image" alt="oS1i6uyY71HPvrPCVEqEVDpscFgyeUCAwlPN" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-06-10-11-43.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-06-10-11-43.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-10-11-43.png 1191w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><h3 id="-leggere-valori-la-magia-inizia-"><strong><strong>👀 </strong>Leggere Valori<strong> — </strong>La Magia Inizia<strong>!</strong></strong></h3><p>Il meraviglioso potere degli array proviene direttamente dalla loro <strong>efficienza nell'accedere ai valori</strong>. Questo avviene grazie alla loro struttura tipo griglia. Esaminiamo il processo in maggiore dettaglio.🔍</p><p><strong>Quando crei un array<strong>:</strong></strong><br>- Lo assegni a una variabile. 👈<br>- Definisci il tipo di elementi che dovrà contenere. 🎈<br>- Definisci la sua dimensione (il numero massimo di elementi). 📚</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/xzGLFN8ymKFdxyZWHk4YInJ6cyQQHxUJiJQX" class="kg-image" alt="xzGLFN8ymKFdxyZWHk4YInJ6cyQQHxUJiJQX" width="600" height="400" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>:</strong></strong> Il nome che assegni a questa variabile è molto importante in quanto lo utilizzerai successivamente nel tuo codice per accedere e/o modificarne i valori.</p><p>Ma come puoi dire al computer di accedere a un particolare valore? Qui gli indici hanno un ruolo vitale!</p><h4 id="1-indici"><strong><strong>1️⃣ Indic</strong>i</strong></h4><p><strong>Si usa quello che viene chiamato "indice" </strong>per accedere a un valore in un array. È un numero che fa riferimento alla posizione in cui il valore è conservato.</p><p>Come puoi vedere nel diagramma qui sotto, il primo elemento dell'array viene indirizzato usando l'indice 0. Mano a mano che ti sposti verso destra, il valore dell'indice aumenta di uno per ciascuno spazio in memoria.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-46-35.png" class="kg-image" alt="TuWNHRYkAgpBEjuszG9DElXUIAf8Osw2z--7" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-08-09-46-35.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-08-09-46-35.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-46-35.png 1218w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>So che partire a contare da 0 invece che da 1 può sembrare strano, ma è quella che viene chiamata <a href="https://en.wikipedia.org/wiki/Zero-based_numbering" rel="noopener">Numerazione a base zero</a>. È molto comune in informatica.</p><p><strong>La sintassi generale per accedere a un elemento è </strong><code><strong><strong><strong><strong>&lt;</strong></strong></strong>VariabileArray<strong><strong><strong>&gt;[&lt;ind</strong></strong></strong>ice<strong><strong><strong>&gt;]</strong></strong></strong></strong></code></p><p><strong>Per esempio<strong><strong><strong>:</strong></strong></strong></strong><br>Se il tuo array è associato alla variabile <code><strong><strong><strong><strong>myArray</strong></strong></strong></strong></code> e vuoi accedere al primo elemento (indice 0), dovresti usare <code><strong><strong><strong><strong>myArray[0]</strong></strong></strong></strong></code></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/Yu9nSlzmHkZV4e7f7sulFIamSwWONw4wNcpg" class="kg-image" alt="Yu9nSlzmHkZV4e7f7sulFIamSwWONw4wNcpg" width="600" height="400" loading="lazy"></figure><h4 id="2-memoria"><strong><strong>2️⃣ Memor</strong>ia</strong></h4><p>Ora che sai come accedere ai valori, vediamo come sono conservati gli array nella memoria del computer. <strong>Quando definisci la dimensione di un array, tutto lo spazio in memoria corrispondente alla dimensione viene "riservato" da quel momento in poi </strong>per valori futuri che vorresti poter inserire.</p><p><strong><strong><strong><strong>💡 Not</strong></strong></strong>a<strong><strong><strong>:</strong></strong></strong></strong> Se non riempi tutto l'array con valori, quello spazio verrà riservato e mantenuto vuoto fino a quando non lo farai.</p><p><strong>Per esempio<strong>:</strong></strong><br>Diciamo che definisci un array di dimensione 5 ma inserisci un solo valore. Tutto lo spazio rimanente sarà vuoto e "riservato" in memoria, in attesa di future assegnazioni.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/7Hoys8sq0RuDF4-Rgr4WRD4RrImGhtQmzR9P" class="kg-image" alt="7Hoys8sq0RuDF4-Rgr4WRD4RrImGhtQmzR9P" width="600" height="400" loading="lazy"></figure><p>Questa è la chiave: gli array sono estremamente efficienti nell'accedere ai valori in quanto tutti gli elementi sono conservati in spazi contigui di memoria. <strong>In questo modo, il computer sa esattamente dove cercare per trovare le informazioni che hai richiesto</strong>.</p><p><strong>Ma<strong><strong><strong>… </strong></strong></strong></strong>c'è un aspetto negativo 😞 in quanto non è <strong>efficiente dal punto di vista della memoria</strong>. Stai riservando memoria per operazioni future che potrebbero non accadere mai. <strong>Ecco perché gli array sono consigliati in situazioni dove sai in anticipo quanti elementi andrai a conservare</strong>.</p><h3 id="-operazioni-dietro-le-quinte-"><strong><strong>🔧 Opera</strong>z<strong>io</strong>ni<strong> — </strong>Dietro le quinte<strong>!</strong></strong></h3><p>Ora che sai cosa sono gli array, quando vengono usati e come conservano i loro elementi, approfondiremo le operazioni che si possono compiere su di essi come l'inserimento e l'eliminazione.</p><h4 id="1-inserimento-benvenuto-"><strong><strong>1️⃣ Inser</strong>imento<strong> — </strong>Benvenuto<strong>!</strong></strong></h4><p>Supponiamo di avere un array di dimensione 6 e di avere ancora spazio vuoto all'interno. Vogliamo inserire un elemento "e" all'inizio dell'array (indice 0), ma questa posizione è già occupata dall'elemento "a". Cosa dovremmo fare?</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/JX8sviJCpwXkWT6mZ4fDIwzSNFDUZ0C8LfrP" class="kg-image" alt="JX8sviJCpwXkWT6mZ4fDIwzSNFDUZ0C8LfrP" width="600" height="400" loading="lazy"></figure><p><strong>Per inserire elementi negli array</strong>, spostiamo tutti gli elementi già presenti che si trovano alla destra della posizione di inserimento di una posizione in avanti verso destra. L'elemento "a" ora sarà a indice 1, l'elemento "b" a indice 2 e così via…</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/8KFz74m1v5dPBzXGr5IXAvt3a5XFbzL78gVs" class="kg-image" alt="8KFz74m1v5dPBzXGr5IXAvt3a5XFbzL78gVs" width="600" height="400" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>Potresti aver bisogno di creare una variabile per tenere traccia del valore dell'ultimo indice che contiene elementi. Nel diagramma qui sopra, l'array viene riempito fino all'indice 4 prima dell'inserimento. In questo modo, puoi determinare se l'array è pieno e quale indice dovresti utilizzare per inserire un elemento alla fine.</p><p>Dopo aver fatto questo, il nuovo elemento viene inserito con successo. 👏</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/VqmOSyTnIvPWbkw9p1PIhenPthaxd3bHxzvS" class="kg-image" alt="VqmOSyTnIvPWbkw9p1PIhenPthaxd3bHxzvS" width="600" height="400" loading="lazy"></figure><h4 id="-aspetta-un-minuto-cosa-succede-se-l-array-pieno"><strong><strong>⚠️ </strong>Aspetta un minuto! Cosa succede se l'array è pieno<strong>?</strong></strong></h4><p>Cosa pensi che accada se l'<strong>array è pieno e cerchi di inserire </strong>un elemento? 😱</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-12-00-45.png" class="kg-image" alt="IlI473xQSRYYCMjlcF0YMSOs-Kca2hqqupGk" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-06-12-00-45.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-06-12-00-45.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-06-12-00-45.png 1188w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p><strong><strong>In </strong>questo caso devi creare un array nuovo più grande, poi copiare manualmente tutti gli elementi nel nuovo array. </strong>Questa operazione è <strong>molto onerosa dal punto di vista del tempo</strong>. Immagina cosa accadrebbe se avessi un array con milioni di elementi! Potrebbe volerci moltissimo tempo per completare l'operazione. ⏳</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/P2q2OaohnsEPDa3KMu3e6eOJaPpw-bpufH95" class="kg-image" alt="P2q2OaohnsEPDa3KMu3e6eOJaPpw-bpufH95" width="600" height="400" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>L'unica eccezione a questa regola, laddove l'inserimento è molto veloce, è quando inserisci un elemento alla <strong>fine</strong> dell'array (alla posizione di indice alla destra dell'ultimo elemento) e c'è ancora spazio disponibile. Questo viene fatto con un tempo costante O(1).</p><h4 id="2-cancellazione-ciao-ciao-"><strong><strong>2️⃣ </strong>Cancellazione<strong>— </strong>Ciao Ciao<strong>!</strong></strong></h4><p>Diciamo ora che vuoi eliminare un elemento dall'array.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/yG5HNXTX7Xj7aXAstjEMU2VNWHkEZXtG9q5z" class="kg-image" alt="yG5HNXTX7Xj7aXAstjEMU2VNWHkEZXtG9q5z" width="600" height="400" loading="lazy"></figure><p>Per mantenere l'efficienza per l'accesso casuale (essere in grado di accedere in modo estremamente veloce all'array tramite un indice) gli elementi devono essere conservati in spazi contigui di memoria. <strong>Non puoi semplicemente eliminare l'elemento e lasciare uno spazio vuoto</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-07-16-36-01.png" class="kg-image" alt="bd9KRk22FyVVrW3RJEKvCd8y-VAJQodeABOD" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-07-16-36-01.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-07-16-36-01.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-07-16-36-01.png 1189w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><p>Dovresti spostare di una posizione a sinistra gli elementi situati dopo l'elemento che vuoi cancellare.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/G13PaxPTyIQRCBJdh2Ioup-4jM-qlDMnTVd7" class="kg-image" alt="G13PaxPTyIQRCBJdh2Ioup-4jM-qlDMnTVd7" width="600" height="400" loading="lazy"></figure><p>Alla fine l'array risulterà questo 👇. Come puoi vedere, "b" è stato eliminato con successo.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/85yhQ9XK19hJ2paBhkb9Cf0-8v52DO0igncc" class="kg-image" alt="85yhQ9XK19hJ2paBhkb9Cf0-8v52DO0igncc" width="600" height="400" loading="lazy"></figure><p><strong><strong><strong><strong>💡 Not</strong></strong></strong>a<strong><strong><strong>: </strong></strong></strong></strong>La cancellazione è molto efficiente quando rimuove l'<strong>ultimo</strong> elemento. Visto che devi creare una variabile che tenga traccia dell'ultimo indice che contiene un elemento (nel diagramma qui sopra, 3), puoi rimuovere direttamente l'elemento usando l'indice.</p><h4 id="3-trovare-un-elemento"><strong><strong>3️⃣ </strong>Trovare un elemento</strong></h4><p>Hai tre opzioni per trovare un elemento in un array:</p><ul><li><strong>Se conosci la sua posizione</strong>, usa l'indice.</li><li><strong>Se non conosci la sua posizione e i tuoi dati sono ordinati</strong>, puoi usare degli algoritmi per ottimizzare la tua ricerca, come la Ricerca Binaria.</li><li><strong>Se non conosci la sua posizione e i dati non sono ordinati</strong>, devi scorrere tutti gli elementi nell'array e verificare se l'elemento corrente è quello che stai cercando (vedi la serie di diagrammi qui sotto).</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-21-57.png" class="kg-image" alt="hlrl4kdBl3eM8cT7DXJX7rItWeHzTvrretfG" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-08-09-21-57.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-08-09-21-57.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-21-57.png 1227w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-24-17.png" class="kg-image" alt="nFz0jZQu4dtAqv4fauEE-7zVqxtGlKVVfKew" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-08-09-24-17.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-08-09-24-17.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-24-17.png 1227w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-26-50-1.png" class="kg-image" alt="hxcwNp-VfOem0psPkl26HCLrILCR1mlrdpku" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-08-09-26-50-1.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-08-09-26-50-1.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-26-50-1.png 1227w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-29-22.png" class="kg-image" alt="dEd3ArmSERT63fk95KSlKwwCqdwjvUBAOQen" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-08-09-29-22.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-08-09-29-22.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-08-09-29-22.png 1227w" sizes="(min-width: 720px) 720px" width="600" height="400" loading="lazy"></figure><h3 id="-riepilogando-"><strong><strong>👋 </strong>Riepilogando <strong>…</strong></strong></h3><ul><li><strong>Gli array sono strutture dati estremamente potenti</strong> che conservano elementi dello stesso tipo. Il tipo degli elementi e la dimensione dell'array sono fissi e definiti in fase di creazione.</li><li><strong>La memoria è allocata immediatamente</strong> dopo che l'array è creato ed è vuota fino a quando non assegni i valori.</li><li>Gli <strong>elementi sono posti in posizioni contigue di memoria</strong>, in modo che vi si possa accedere in modo molto efficiente (accesso casuale O(1) = tempo costante) usando gli <strong>indici</strong>.</li><li>Gli <strong>indici partono da 0</strong>, non da 1 come siamo abituati.</li><li>L'<strong>inserimento di elementi</strong> all'inizio o in mezzo all'array comporta lo spostamento degli elementi verso destra. Se l'array è pieno, occorre creare un nuovo array di maggiori dimensioni (il che non è molto efficiente). L'inserimento alla fine dell'array è molto efficiente - tempo costante O(1).</li><li>La <strong>rimozione di elementi</strong> dall'inizio o nel mezzo dell'array comporta lo spostamento di tutti gli elementi verso sinistra per evitare di lasciare uno spazio vuoto in memoria. Questo garantisce che gli elementi siano conservati in spazi di memoria contigui. La rimozione di un elemento alla fine dell'array è molto efficiente in quanto cancelli solo l'ultimo elemento senza spostare gli altri.</li><li><strong>Per trovare un elemento</strong>, devi controllare l'intero array fino a quando non lo trovi. Se i dati sono ordinati, puoi usare algoritmi come la Ricerca Binaria per ottimizzare il processo.</li></ul><blockquote><em><em>“</em>Impara dal passato, vivi nel presente, spera nel futuro. La cosa importante è non smettere di fare domande<em>.”</em></em><br><br><em><em>— Albert Einstein</em></em></blockquote><h4 id="-grazie-"><strong><strong>👋 </strong>Grazie<strong>!</strong></strong></h4><p>Spero vivamente che ti sia piaciuto il mio articolo. ❤️<br><strong>Seguimi su</strong> <a href="https://twitter.com/Estefania_CN_" rel="noopener">Twitter</a> per trovare altri articoli come questo. 😃</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Strutture Dati: Grafi — Un'Introduzione Visuale per Principianti ]]>
                </title>
                <description>
                    <![CDATA[ Impara a conoscere le strutture dati che usi ogni giorno 👋 Benvenuto! Iniziamo con un po' di necessario contesto. Ho qualche domanda per te: ✅ Usi Google Search? ✅ Usi Google Maps? ✅ Usi i siti di social media? Se la tua risposta è "sì" a una qualsiasi di queste ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/strutture-dati-grafi-unintroduzione-visuale-per-principianti/</link>
                <guid isPermaLink="false">649d2ba0697af406bfa1e64b</guid>
                
                    <category>
                        <![CDATA[ programmazione ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 10 Jul 2023 12:33:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/06/1_EBtSVCSmRvw40Bmu9vP69A.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/data-structures-101-graphs-a-visual-introduction-for-beginners-6d88f36ec768/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Data Structures 101: Graphs — A Visual Introduction for Beginners</a>
      </p><h4 id="impara-a-conoscere-le-strutture-dati-che-usi-ogni-giorno"><strong>I</strong>mpara a conoscere le strutture dati che usi ogni giorn<strong>o</strong></h4><p>👋 Benvenuto! Iniziamo con un po' di necessario contesto. Ho qualche domanda per te:<br><strong><strong>✅ </strong>Usi<strong> Google Search?</strong></strong><br><strong><strong>✅ </strong>Usi<strong> Google Maps?</strong></strong><br><strong><strong>✅ </strong>Usi i siti di <strong>social media?</strong></strong></p><p><strong>Se la tua risposta è "sì" a una qualsiasi di queste domande, allora hai sicuramente utilizzato i grafi e non lo sapevi nemmeno! Sorpreso?</strong> 😲 Lo ero anch'io! Questo articolo ti fornirà un'introduzione visiva al mondo dei grafi, al loro scopo, elementi e tipi.</p><p><strong>Queste strutture di dati hanno davvero attirato la mia attenzione grazie alle loro incredibili capacità.</strong> Sono così potenti che non immagini nemmeno quanto possano essere diverse le loro applicazioni nel mondo reale. Cominciamo! 😁</p><h3 id="-applicazioni-nel-mondo-reale-la-magia-inizia-"><strong><strong>🌐 </strong>Applicazioni nel Mondo Reale <strong>— </strong>La Magia Inizia<strong>!</strong></strong></h3><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/7Fthyp4QpNDWIPHyw-ufGzUtNambSqhQzamA" class="kg-image" alt="7Fthyp4QpNDWIPHyw-ufGzUtNambSqhQzamA" width="571" height="340" loading="lazy"></figure><p><strong>I grafi sono usati in diversi settori e campi<strong>:</strong></strong></p><ul><li>I<strong> sistemi <strong>GPS</strong> e<strong> Google Maps</strong></strong> usano i grafi per trovare il percorso più breve da una destinazione a un'altra.</li><li>I<strong> S<strong>ocial Network</strong></strong> usano i grafi per rappresentare le connessioni tra utenti.</li><li>L'algoritmo di<strong><strong> Google Search</strong></strong> usa i grafi per determinare la rilevanza dei risultati della ricerca.</li><li>La <strong>Ricerca Operativa</strong> è un campo che utilizza i grafi per trovare il percorso ottimale per ridurre i costi di trasporto e consegna di beni e servizi.</li><li>Anche la <strong>chimica<strong> </strong></strong>usa i grafi per rappresentare le molecole!!! ❤️</li></ul><p>Le loro applicazioni sono fantastiche, vero?<br>Iniziamo il nostro viaggio attraverso questo mondo! 😄</p><h3 id="-ti-presento-i-grafi-"><strong><strong>🔵 </strong>Ti Presento i<strong> Gra</strong>fi<strong>!</strong></strong></h3><p>Ora che hai un po' di contesto, iniziamo parlando del loro scopo principale e degli elementi che li costituiscono.</p><p><strong>I grafi sono usati per rappresentare, trovare, analizzare e ottimizzare connessioni tra gli elementi (case, aeroporti, luoghi, utenti, articoli ecc.<strong>).</strong></strong></p><p>Questo è &nbsp;un esempio dell'aspetto di un grafo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/vQ77VuGVlTR95GgMxzyKqydIqoRJcPcWrigy" class="kg-image" alt="vQ77VuGVlTR95GgMxzyKqydIqoRJcPcWrigy" width="654" height="411" loading="lazy"><figcaption>Grafo.</figcaption></figure><h4 id="-elementi-costitutivi"><strong><strong>💠 </strong>Elementi Costitutivi</strong></h4><p>Sono sicuro che avrai notato due elementi principali nel diagramma qui sopra: dei cerchi e delle linee spesse che li connettono tra loro. Sono chiamati rispettivamente <strong>nodi</strong> (nodes) e <strong>connessioni</strong> (edges).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-10-08-39-29-1.png" class="kg-image" alt="9KFiyFYi9bMktsJkMKLKaeJl31heUN9A-xrr" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-10-08-39-29-1.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-10-08-39-29-1.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-10-08-39-29-1.png 1061w" sizes="(min-width: 720px) 720px" width="1061" height="853" loading="lazy"></figure><p><strong>Entriamo nei dettagli<strong>! <strong><strong>👍</strong></strong></strong></strong></p><ul><li><strong><strong>Nod</strong>i<strong>:</strong></strong> sono gli &nbsp;<strong><strong>element</strong>i</strong> che creano la rete. Potrebbero rappresentare <strong>case, luoghi, aeroporti, porti, fermate d'autobus, edifici, utenti</strong>, praticamente qualunque cosa tu possa rappresentare come collegata ad altri elementi simili in una rete.</li><li><strong>Connessioni<strong>:</strong></strong> sono <strong>collegamenti </strong>tra i nodi. Potrebbero rappresentare <strong>strade, voli, percorsi di autobus, una connessione tra due utenti in un <strong>social network,</strong></strong> o qualunque cosa che potrebbe possibilmente rappresentare una connessione tra nodi nel contesto nel quale stai operando.</li></ul><h4 id="-cosa-succede-se-non-ci-sono-connessioni"><strong><strong>😱 </strong>Cosa Succede Se Non Ci Sono Connessioni<strong>?</strong></strong></h4><p>Se due nodi non sono collegati tra loro, vuol dire che <strong>non esiste connessione diretta tra i medesimi</strong>. Ma non ti spaventare! 😩 Potresti essere comunque in grado di andare da un nodo all'altro <strong>seguendo una serie di connessioni</strong>, come se passassi per diverse strade per raggiungere la tua destinazione finale. 🚛️ 🚛 🚛</p><p>Per esempio, nel diagramma qui sotto, sebbene non vi sia <strong>diretta</strong> connessione tra il <strong>nodo</strong> <strong>viola</strong> (a sinistra) e il <strong>nodo giallo</strong> (a destra), puoi comunque raggiungerlo dal nodo viola passando per il nodo arancione, poi per il nodo rosa, quindi per quello verde e arrivare finalmente al nodo giallo. 🏁</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/5GifDfcnk5D15YwlbmewVveYhSAkMhWKCnfm" class="kg-image" alt="5GifDfcnk5D15YwlbmewVveYhSAkMhWKCnfm" width="800" height="378" loading="lazy"><figcaption>Nessuna connessione diretta tra il nodo viola e quello giallo.</figcaption></figure><p>Questo è un aspetto chiave dei grafi, puoi <strong>trovare l'elemento desiderato seguendo i percorsi a disposizione<strong>.</strong></strong></p><h3 id="-notazione-e-terminologia"><strong><strong>🌟 Nota</strong>z<strong>ion</strong>e<strong> </strong>e<strong> Terminolog</strong>ia</strong></h3><p>È molto importante imparare il "linguaggio" formale per lavorare con i grafi:</p><ul><li><code><strong><strong>|V|</strong></strong></code> = <strong>Numero totale di vertici (nodi) </strong>in un grafo.</li><li><code><strong><strong>|E|</strong></strong></code> = <strong>Numero totale di connessioni</strong> in un grafo.</li></ul><p>Nell'esempio che segue, &nbsp;<code><strong><strong>|V| = 6</strong></strong></code> in quanto ci sono sei nodi (i cerchi) ed <code><strong><strong>|E| = 7</strong></strong></code><strong><strong> </strong></strong>poiché ci sono sette connessioni (le righe).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/5vbqwpnuO8nAdj51kN4Bk8ozdpL6WYWkkQHu" class="kg-image" alt="5vbqwpnuO8nAdj51kN4Bk8ozdpL6WYWkkQHu" width="663" height="382" loading="lazy"><figcaption>Grafo.</figcaption></figure><h3 id="-tipi-di-grafo"><strong><strong>📚 T</strong>ipi<strong> </strong>di Grafo</strong></h3><p>I grafi sono classificati in base alle caratteristiche delle loro connessioni. <strong>Vediamoli in dettaglio<strong>! <strong><strong>😃</strong></strong></strong></strong></p><h4 id="1-grafi-orientati"><strong><strong>1️⃣ </strong>Grafi Orientati</strong></h4><p><strong>Nei grafi orientati, le connessioni hanno una direzione. </strong>Vanno da un nodo all'altro, e non c'è modo di tornare al nodo iniziale usando quella connessione.</p><p>Come puoi vedere nel diagramma qui sotto, <strong>le connessioni ora hanno delle frecce che puntano verso una specifica direzione. Pensa a queste connessioni come a strade a senso unico</strong>. Puoi andare in una direzione per raggiungere la tua destinazione, ma non puoi tornare indietro facendo la stessa strada, devi cercare un percorso alternativo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/9KWaj30YcJDBhvteJvkQQ7YvOu3PVaPBaXpw" class="kg-image" alt="9KWaj30YcJDBhvteJvkQQ7YvOu3PVaPBaXpw" width="623" height="366" loading="lazy"><figcaption>Grafo Orientato</figcaption></figure><p>🍕 Per esempio se per un servizio di consegna pizza a domicilio creiamo un grafo &nbsp;che rappresenta una città, due case (i nodi) potrebbero essere <strong>connesse da una strada a senso unico</strong>. Potresti andare dalla casa A alla casa B passando per questa strada, ma non potresti ritornare, quindi dovresti utilizzare un percorso alternativo.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/U7ZcYL5X54m06sKCuQ3wv8K2-Ka7ixE67nxg" class="kg-image" alt="U7ZcYL5X54m06sKCuQ3wv8K2-Ka7ixE67nxg" width="655" height="498" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>In un grafo orientato, <strong>potresti non essere in grado di ritornare al tuo luogo di partenza in alcun modo</strong> se non esiste un percorso con le direzioni appropriate. 😞 Nel diagramma che segue, puoi notare che puoi andare dal nodo viola a quello verde, ma puoi vedere anche che non c'è modo di tornare dal nodo verde a quello viola, in quanto le connessioni sono "strade a senso unico".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/CPepyBE1XXy7fcXemQXQZGbncbZ4RCPH9Ezx" class="kg-image" alt="CPepyBE1XXy7fcXemQXQZGbncbZ4RCPH9Ezx" width="800" height="382" loading="lazy"><figcaption>Punto di non ritorno</figcaption></figure><h4 id="2-grafi-non-orientati"><strong><strong>2️⃣ </strong>Grafi Non Orientati</strong></h4><p><strong><strong>In </strong>questo tipo di grafi, le connessioni non sono orientate (non hanno una direzione specifica)<strong>. </strong></strong>Pensa a questo tipo di connessioni come a strade a doppio senso. Puoi andare da un nodo all'altro e tornare indietro usando lo stesso "percorso".</p><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>Quando vedi un diagramma di un grafo dove le connessioni non hanno frecce che puntano verso una specifica direzione, puoi assumere che il grafo non è orientato.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-10-08-54-31.png" class="kg-image" alt="kgILL-2f3arDbAUOwFKLRFxp2khpvvZ5J9vF" srcset="https://www.freecodecamp.org/italian/news/content/images/size/w600/2023/07/Screenshot-from-2023-07-10-08-54-31.png 600w, https://www.freecodecamp.org/italian/news/content/images/size/w1000/2023/07/Screenshot-from-2023-07-10-08-54-31.png 1000w, https://www.freecodecamp.org/italian/news/content/images/2023/07/Screenshot-from-2023-07-10-08-54-31.png 1216w" sizes="(min-width: 720px) 720px" width="1216" height="695" loading="lazy"></figure><p>🍕 Per il nostro servizio di consegna pizze a domicilio significherebbe che il veicolo per le consegna può andare <strong>dalla sorgente alla destinazione e tornare indietro usando la stessa strada o percorso</strong> (con sollievo del guidatore! 😇).</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/ijCoLsVRLPWxVTmUI13tnv-aTOtyiHHonk11" class="kg-image" alt="ijCoLsVRLPWxVTmUI13tnv-aTOtyiHHonk11" width="651" height="483" loading="lazy"></figure><p>Nel grafo qui sotto potresti andare <strong>dal nodo viola a quello verde e tornare indietro seguendo lo stesso percorso</strong>, quindi non raggiungerai un punto di non ritorno. 😌</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/Fe2wHkUPwhxYxdd9LXschmm2VfNaMhiiHJrb" class="kg-image" alt="Fe2wHkUPwhxYxdd9LXschmm2VfNaMhiiHJrb" width="800" height="401" loading="lazy"><figcaption>Puoi tornare indietro!</figcaption></figure><h3 id="-pesi-s-pesi-"><strong><strong>🏋 </strong>Pesi<strong>? — </strong>Sì, Pesi<strong>!</strong></strong></h3><h4 id="1-grafici-ponderati"><strong><strong>1️⃣ </strong>Grafici Ponderati</strong></h4><p><strong>Nei grafici ponderati, ciascuna connessione ha un valore associato (chiamato peso<strong>)</strong></strong>. Questo valore viene usato per rappresentare una data relazione quantificabile tra i nodi che collega.</p><p>Per esempio i pesi potrebbero rappresentare <strong>distanza, tempo, il numero di connessioni condivise tra due utenti in un</strong> <strong><strong>social network,</strong></strong> o qualsiasi cosa che potrebbe essere usata per descrivere la connessione tra nodi nel contesto nel quale stai lavorando.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/H1ASU4s0MP52QUyuqo4LIjlvZcR4kn7lkq2V" class="kg-image" alt="H1ASU4s0MP52QUyuqo4LIjlvZcR4kn7lkq2V" width="646" height="389" loading="lazy"><figcaption>Grafico Ponderato</figcaption></figure><p>Questi pesi sono usati dall'<strong><a href="https://www.freecodecamp.org/italian/news/lalgoritmo-dei-cammini-minimi-di-dijkstra-una-dettagliata-introduzione-grafica/">algoritmo di Dijkstra</a></strong> per ottimizzare le rotte per trovare i percorsi più brevi o meno costosi tra i nodi in una rete.</p><h4 id="2-grafi-non-ponderati"><strong><strong>2️⃣ </strong>Grafi Non Ponderati</strong></h4><p>Nei grafi non ponderati, al contrario, <strong>non abbiamo pesi associati alle loro connessioni</strong>. Un esempio di questo tipo di grafo si può trovare nei social network, dove le connessioni tra due utenti non possono essere quantificate. Pertanto la connessione non ha un peso.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/y5vDbTl6r5SZOxsjcpI1U68DuWFIe3D4zC6h" class="kg-image" alt="y5vDbTl6r5SZOxsjcpI1U68DuWFIe3D4zC6h" width="624" height="366" loading="lazy"><figcaption>Grafo non ponderato</figcaption></figure><p><strong><strong><strong><strong>💡</strong></strong> Not</strong>a<strong>: </strong></strong>Potresti aver notato che, fino ad ora, i nostri grafi hanno solo una connessione che connette ciascuna coppia di nodi. È normale chiedersi se potrebbero esserci più connessioni tra una coppia di nodi. In effetti questo è possibile con i &nbsp;<strong><a href="https://it.wikipedia.org/wiki/Multigrafo">Multigrafi</a></strong>! Essi possono avere più connessioni che connettono la stessa coppia di nodi.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/xE-qHRQhhKaBVgPhgm2xRzk6OJj5R1G2wtyd" class="kg-image" alt="xE-qHRQhhKaBVgPhgm2xRzk6OJj5R1G2wtyd" width="605" height="175" loading="lazy"><figcaption>Multigrafo.</figcaption></figure><h3 id="-numero-di-connessioni-un-fattore-importante"><strong><strong>🏆 Num</strong>ero di Connessioni<strong>! — </strong>Un Fattore Importante</strong></h3><p>È molto importante sapere se un grafo ha molte o poche connessioni in quanto questo è un fattore cruciale per decidere come vorrai rappresentare questa struttura dati nel tuo codice. <strong>Vediamo i diversi tipi<strong>! <strong><strong>👍</strong></strong></strong></strong></p><h4 id="1-grafo-denso"><strong><strong>1️⃣ </strong>Grafo Denso</strong></h4><p><strong>Sono i grafi che hanno molte connessioni. Ma, un momento<strong>! ⚠️ </strong></strong>So quello che starai pensando, come puoi quantificare "molte connessioni"? Questo è piuttosto soggettivo, giusto? 😇 Sono d'accordo con te, quindi quantifichiamole:</p><p>👉 <strong>Troviamo il numero massimo di connessioni in un grafo orientato. </strong>Se ci sono <code><strong><strong><strong><strong>|V|</strong></strong></strong></strong></code> nodi in un grafo orientato (sei, nell'esempio qui sotto), vuol dire che ogni nodo può avere fino a &nbsp;<code><strong><strong><strong><strong>|v|</strong></strong></strong></strong></code> connessioni (nell'esempio qui sotto, sei).</p><p>Questo perché <strong>ogni nodo potrebbe potenzialmente essere connesso con tutti gli altri nodi e con sé stesso</strong> (vedi il "loop" qui sotto). Pertanto il numero massimo di connessioni che il grafo può avere è <strong><strong><strong><strong> </strong></strong></strong></strong><code><strong><strong><strong><strong>|V|*|V|</strong></strong></strong></strong></code> , che rappresenta il numero totale di nodi moltiplicato per il numero massimo di connessioni che ogni nodo può avere.</p><p><strong>Quando il numero di connessioni nel grafo è vicino al numero massimo di connessioni, il grafo è denso<strong>. <strong><strong>😉</strong></strong></strong></strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/vyGE1CPDiqcjBx1X8BGpFt0bUXOWpn4CZABy" class="kg-image" alt="vyGE1CPDiqcjBx1X8BGpFt0bUXOWpn4CZABy" width="663" height="382" loading="lazy"><figcaption>Grafo.</figcaption></figure><p>💡 <strong><strong><strong><strong>Not</strong></strong></strong>a<strong><strong><strong>:</strong></strong></strong></strong> I “loop” si verificano quando un nodo ha una connessione che connette se stesso. Strano e interessante, vero? 😄</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/IDjXVX7CPToN73P5GO73qHdJBL1hhgS7msMV" class="kg-image" alt="IDjXVX7CPToN73P5GO73qHdJBL1hhgS7msMV" width="135" height="169" loading="lazy"><figcaption>Rappresentazione di un “loop”.</figcaption></figure><h4 id="2-grafi-sparsi"><strong><strong>2️⃣ Gra</strong>fi Sparsi</strong></h4><p><strong>I grafi sparsi hanno poche connessioni. </strong>Come puoi vedere nel diagramma qui sotto, non ci sono molte connessioni tra i nodi.</p><p><strong>Quando il numero di connessioni in un grafo è significativamente minore del numero massimo di connessioni, il grafo è sparso<strong><strong><strong>. 😉</strong></strong></strong></strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/i4OsBT4deG6soapNSKKTq-1DSQbV5vOFcBrN" class="kg-image" alt="i4OsBT4deG6soapNSKKTq-1DSQbV5vOFcBrN" width="647" height="379" loading="lazy"><figcaption>Grafo Sparso</figcaption></figure><h3 id="-ti-presento-i-cicli-"><strong><strong>⭕️ </strong>Ti Presento i Cicli<strong>!</strong></strong></h3><p><strong>Ora vediamo un concetto vitale per comprendere i grafi, i cicli<strong>.</strong></strong></p><p>Avrai probabilmente notato che, se segui una sequenza di connessioni in un grafo, potresti trovare il <strong>percorso che ti riporta allo stesso nodo</strong>. Questo è come "girare in tondo", esattamente come se stessi guidando per la tua città e prendessi un percorso che ti potrebbe portare al punto di partenza.</p><p><strong>Nei grafi, questi percorsi "circolari" sono chiamati cicli</strong>. Sono <strong>percorsi validi che iniziano e finiscono allo stesso nodo</strong>. Per esempio, nel diagramma qui sotto, puoi vedere che partendo da qualsiasi nodo puoi ritornarci seguendo le connessioni.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/f6A1AD4qMi8BlEgralqX1tFbjkurgOTrb21K" class="kg-image" alt="f6A1AD4qMi8BlEgralqX1tFbjkurgOTrb21K" width="386" height="372" loading="lazy"><figcaption>Ciclo semplice</figcaption></figure><p><strong>I cicli non sono sempre "isolati" in quanto possono fare parte di un grafo più grande</strong>. Puoi rilevarli facendo partire la tua ricerca da uno specifico nodo e cercando un percorso che ti riporta allo stesso nodo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/r2bS-ZNjPVqOXoOq3Z7OJrNoWCSLqemZzkmv" class="kg-image" alt="r2bS-ZNjPVqOXoOq3Z7OJrNoWCSLqemZzkmv" width="794" height="538" loading="lazy"><figcaption>Un ciclo in un grafo</figcaption></figure><h3 id="-riepilogando-"><strong><strong>👋 </strong>Riepilogando <strong>…</strong></strong></h3><ul><li><strong>I grafi sono strutture meravigliose</strong> che puoi usare quotidianamente tramite Google Search, Google Maps, GPS e i social media.</li><li>Sono usati per <strong>rappresentare elementi che condividono connessioni</strong>.</li><li>Gli elementi nel grafo sono chiamati <strong>nodi</strong> <strong>(nodes)</strong> i collegamenti tra loro <strong>connessioni (edges)</strong>.</li><li>I grafi possono essere <strong>orientati</strong>, quando le loro connessioni hanno uno specifico orientamento, simili alle strade a senso unico, oppure <strong>non orientati</strong>, quando le connessioni non hanno un orientamento specifico, simili alle strade a doppio senso.</li><li>Le connessioni possono avere un valore associato ad esse, chiamato <strong>peso</strong>.</li><li>Se un grafo ha molte connessioni si dice <strong>denso</strong>, altrimenti, se ha poche connessioni, viene detto <strong>sparso</strong>.</li><li>Una serie di connessioni può formare un <strong>ciclo</strong> se esse creano un percorso che ti consente di tornare al nodo di partenza.</li></ul><p><strong>Continua ad apprendere queste stupende strutture! Ne varrà sicuramente la pena per il tuo futuro di programmatore. </strong>In questo momento sto imparando le strutture dati e le trovo assolutamente affascinanti. 😃 🎆 ❤️</p><blockquote><em>La cosa importante è non smettere di fare domande. La curiosità esiste per ragioni proprie<em>. — Albert Einstein</em></em></blockquote><h4 id="-grazie-"><strong><strong>👋 </strong>Grazie<strong>!</strong></strong></h4><p>Spero davvero che tu abbia apprezzato il mio articolo. ❤️<br>Seguimi su<strong><strong> </strong></strong><a href="https://twitter.com/EstefaniaCassN">Twitter</a>. 😃</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ La Parola Chiave `this` in Javascript + 5 Regole Chiave di Binding Spiegate per Principianti di JS ]]>
                </title>
                <description>
                    <![CDATA[ La parola chiave di JavaScript this è uno degli aspetti del linguaggio più difficili da comprendere. Tuttavia è di importanza critica per la scrittura di codice JavaScript più avanzato. In JavaScript, la parola chiave this ci consente di:  * Riutilizzare funzioni in diversi contesti di esecuzione. Vale a dire ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/la-parola-chiave-this-in-javascript-5-regole-chiave-di-binding-spiegate-per-principianti-di-js/</link>
                <guid isPermaLink="false">6497384aa524800686f60037</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Thu, 06 Jul 2023 13:25:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/06/cover_freecodecamp.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/javascript-this-keyword-binding-rules/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The JavaScript `this` Keyword + 5 Key Binding Rules Explained for JS Beginners</a>
      </p><p>La parola chiave di JavaScript <code>this</code> è uno degli aspetti del linguaggio più difficili da comprendere. Tuttavia è di importanza critica per la scrittura di codice JavaScript più avanzato.</p><p>In JavaScript, la parola chiave <code>this</code> ci consente di:</p><ul><li>Riutilizzare funzioni in diversi contesti di esecuzione. Vale a dire che una funzione, una volta definita, può essere chiamata per oggetti diversi usando la parola chiave <code>this</code>.</li><li>Identificare l'oggetto nel contesto di esecuzione corrente quando chiamiamo un metodo.</li></ul><p>La parola chiave <code>this</code> è strettamente associata &nbsp;alle funzioni JavaScript. Quando si parla di <code>this</code>, la cosa fondamentale è capire dove viene chiamata una funzione, poiché non sappiamo a cosa si riferisca la parola chiave <code>this</code> fino a quando la funzione non viene invocata. </p><p>L'uso di &nbsp;<code>this</code> può essere categorizzato in cinque diversi aspetti di <code>binding</code> (associazione). In questo articolo, esamineremo tutti e cinque gli aspetti con degli esempi.</p><h1 id="innanzitutto-cos-il-binding"><strong>Innanzitutto, Cos'è il<strong><strong> Binding?</strong></strong></strong></h1><p>In JavaScript, un <em>ambiente lessicale</em> è il posto in cui viene fisicamente scritto il codice. Nell'esempio qui sotto, la variabile <code>name</code> dal punto di vista <em>lessicale </em>è all'interno della funzione <code>sayName()</code>.</p><pre><code class="language-js">function sayName() {
  let name = 'someName';
  console.log('Il nome è, ', name);
 }</code></pre><p>Un <em>contesto di esecuzione</em> fa riferimento al codice attualmente in esecuzione e tutto ciò che contribuisce a eseguirlo. Possono esserci molti ambienti lessicali a disposizione ma quello che è attualmente in esecuzione viene gestito dal <em><a href="https://it.wikipedia.org/wiki/Esecuzione_(informatica)#Premesse_e_contesto">contesto di esecuzione</a></em>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/10/lexical.gif" class="kg-image" alt="lexical" width="600" height="400" loading="lazy"><figcaption><em style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: italic; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">Lexical Environment vs Execution Context</em></figcaption></figure><p>Ciascun contesto di esecuzione contiene un <em>record di ambiente. </em>Quando il motore JavaScript esegue il codice, variabili e nomi di funzioni vengono aggiunti al <em>record di ambiente</em>.</p><p>Questo fenomeno è noto in JavaScript come <code>binding</code>. Il <code>binding</code> aiuta l'associazione degli identificatori (variabili e nomi di funzioni) con la parola chiave <code>this</code> per costituire un <em>contesto di esecuzione</em>.</p><p>Non preoccuparti se trovi questo concetto difficile da capire adesso. Ne avrai una migliore comprensione mano a mano che procediamo.</p><h1 id="regola-1-come-funziona-il-binding-implicito-di-javascript"><strong>Regola #1: Come Funziona il Binding Implicito di JavaScript</strong></h1><p>Il binding implicito copre la maggior parte dei casi d'uso per quanto riguarda la parola chiave <code>this</code>.</p><p>Quando invochiamo un metodo di un oggetto, usiamo la notazione punto (.) per accedervi. Nel binding implicito, devi verificare l'oggetto adiacente al metodo in fase di invocazione. Questo determina a cosa viene associato <code>this</code>.</p><p>Esaminiamo un esempio per capire meglio.</p><pre><code class="language-js">let blog = {
    name: 'Tapas',
    address: 'freecodecamp',
    message: function() {
        console.log(`${this.name} ha un blog su ${this.address}`);
    }
};

blog.message();</code></pre><p>Qui <code>this</code> viene associato all'oggetto <code>blog</code>. Lo sappiamo perché chiamiamo il metodo <code>message()</code> sull'oggetto <code>blog</code>. Pertanto <code>this.name</code> sarà <em><em><em><em><em><em><em><em>Tapas</em></em></em></em></em></em></em> </em>e <code>this.address</code> sarà &nbsp;<em><em>freeCodeCamp</em></em> e tali valori verranno stampati nella console.</p><p>Vediamo un altro esempio per capire meglio questo concetto:</p><pre><code class="language-js"> function greeting(obj) {
      obj.logMessage = function() {
          console.log(`${this.name} ha ${this.age} anni!`);
      }
  };

  const tom = {
      name: 'Tom',
      age: 7
  };

  const jerry = {
      name: 'jerry',
      age: 3
  };

  greeting(tom);
  greeting(jerry);

  tom.logMessage ();
  jerry.logMessage ();
</code></pre><p>In questo esempio abbiamo due oggetti, &nbsp;<code>tom</code> e <code>jerry</code>. Abbiamo decorato (arricchito) questi oggetti con un metodo chiamato <code>logMessage()</code>.</p><p>Nota che quando invochiamo <code>tom.logMessage()</code>, il metodo viene chiamato sull'oggetto <code>tom</code>. Pertanto <code>this</code> è associato all'oggetto <code>tom</code> e i valori stampati saranno <em><em><em><em><em><em><em><em>tom</em></em></em></em> </em></em></em></em>e<em><em><em><em> </em></em>7<em><em><em><em><em><em> </em></em></em></em></em></em></em></em>(<code>this.name</code> equivale a <em><code>tom</code></em> e <code>this.age</code> in questo caso è &nbsp;7). Lo stesso vale quando viene invocato <code>jerry.logMessage()</code>.</p><h1 id="regola-2-come-funziona-in-javascript-il-binding-esplicito"><strong>Regola #2: Come Funziona In JavaScript il Binding Esplicito</strong></h1><p>Abbiamo visto che JavaScript crea un ambiente per eseguire il codice che scriviamo. Si occupa della creazione in memoria di variabili, funzioni, oggetti e così via nella <em>fase di creazione</em>. Successivamente esegue il codice nella <em>fase di esecuzione. </em>Questo ambiente speciale viene chiamato <em>contesto di esecuzione</em>.</p><p>Possono essercene molti di questi ambienti (contesti di esecuzione) in un'applicazione JavaScript. Ogni contesto di esecuzione opera indipendentemente dagli altri.</p><p>A volte, tuttavia, potremmo voler usare cose che si trovano in un altro contesto di esecuzione. Ecco quando entra in gioco il binding esplicito.</p><p>Nel binding esplicito chiamiamo una funzione con un oggetto quando la funzione è al di fuori del contesto di esecuzione di quell'oggetto.</p><p>Ci sono tre metodi molto speciali: &nbsp;<code>call()</code>, <code>apply()</code> e <code>bind()</code> che ci aiutano a ottenere il binding esplicito.</p><h2 id="come-funziona-il-metodo-call-di-javascript"><strong>Come Funziona il Metodo <code>call()</code> di JavaScript</strong></h2><p>Con il metodo <code>call()</code>, il contesto nel quale la funzione deve essere chiamata verrà passato come parametro a &nbsp;<code>call()</code>. Vediamo come funziona con un esempio:</p><pre><code class="language-js">let getName = function() {
     console.log(this.name);
 }
 
let user = {
   name: 'Tapas',
   address: 'Freecodecamp'  
 };

getName.call(user);</code></pre><p>Qui sopra il metodo <code>call()</code> viene invocato su una funzione chiamata <code>getName()</code>. La funzione <code>getName()</code> stampa semplicemente alla console il valore di <code>this.name</code>. Ma cosa rappresenta <code>this</code> qui? Questo dipende da cosa è stato passato al metodo <code>call()</code>.</p><p>In questo caso <code>this</code> sarà associato all'oggetto <code>user</code>, in quanto lo abbiamo passato come parametro al metodo <code>call()</code>. Pertanto <code>this.name</code> dovrebbe avere il valore associato alla proprietà <code>name</code> dell'oggetto <code>user</code>, vale a dire <em><em><em><em>Tapas</em></em></em></em>.</p><p>Nell'esempio qui sopra abbiamo passato solo un argomento a <code>call()</code>. Tuttavia &nbsp;possiamo passare molteplici argomenti a <code>call()</code>, in questo modo:</p><pre><code class="language-js">let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }

let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
 
getName.call(user, hobbies[0], hobbies[1]);</code></pre><p>Qui abbiamo passato diversi argomenti al metodo <code>call()</code>. Il primo argomento deve essere il contesto dell'oggetto nel quale la funzione deve essere chiamata. Gli altri parametri potrebbero essere semplicemente valori da usare.</p><p>In questo caso sto passando <em>Nuotare </em>e<em> Tenere un Blog </em>come due parametri della funzione <code>getName()</code>.</p><p>Hai notato il punto dolente qui? Nel caso di <code>call()</code>, gli argomenti devono essere passati uno ad uno &nbsp;– il che non è un modo intelligente di fare le cose!. Ecco quando il nostro prossimo metodo, <code>apply()</code>, entra in &nbsp;gioco.</p><h2 id="come-funziona-il-metodo-apply-in-javascript"><strong>Come Funziona il Metodo <code>apply()</code> in JavaScript</strong></h2><p>Questo modo di passare argomenti al metodo <code>call()</code> può essere risolto usando un metodo alternativo chiamato <code>apply()</code>. Funziona esattamente come <code>call()</code>, ma ti consente di passare gli argomenti in modo più conveniente. Dai un'occhiata a questo codice:</p><pre><code class="language-js">let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }
 
let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
 
getName.apply(user, hobbies);</code></pre><p>Qui siamo in grado di passare un array di argomenti, il che è molto più conveniente rispetto al passarli ad uno ad uno.</p><p>Suggerimento: Quando hai solo uno o nessun valore di argomento da passare, usa <code>call()</code>. Quando hai diversi valori di argomento, usa <code>apply()</code>.</p><h2 id="come-funziona-il-metodo-bind-di-javascript"><strong>Come Funziona il Metodo <code>bind()</code> di JavaScript</strong></h2><p>Il metodo <code>bind()</code> è simile al metodo <code>call()</code>, con una differenza: diversamente da <code>call()</code>, che chiama la funzione direttamente, &nbsp;<code>bind()</code> ritorna una funzione completamente nuova che possiamo invocare.</p><pre><code class="language-js">let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }

let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
let newFn = getName.bind(user, hobbies[0], hobbies[1]); 

newFn();</code></pre><p>Qui <code>getName.bind()</code> non chiama la funzione <code>getName()</code><em><em><em><em> </em></em></em></em>direttamente. Ritorna una nuova funzione, <code>newFn</code> che possiamo invocare come <code>newFn()</code>.</p><h1 id="rule-3-il-binding-new-di-javascript"><strong>Rule #3: Il Binding <code>new</code> di JavaScript</strong></h1><p>La parola chiave <code>new</code> è usata per creare un oggetto dalla funzione costruttore.</p><pre><code class="language-js">let Cartoon = function(name, character) {
     this.name = name;
     this.character = character;
     this.log = function() {
         console.log(this.name +  ' è un ' + this.character);
     }
 };</code></pre><p>Puoi creare oggetti usando la parola chiave <code>new</code> in questo modo:</p><pre><code class="language-js"> let tom = new Cartoon('Tom', 'Gatto');
 let jerry = new Cartoon('Jerry', 'Topo');</code></pre><p>Quando una funzione viene invocata con la parola chiave <code>new</code>, JavaScript crea un oggetto <code>this</code> interno (così: <code>this = {}</code>) nella funzione. Il <code>this</code> appena creato si associa all'oggetto in fase di creazione usando la parola chiave <code>new</code>.</p><p>Sembra complicato? Ok, esaminiamolo approfonditamente. Osserva questa riga:</p><pre><code class="language-js">let tom = new Cartoon('Tom', 'Gatto');</code></pre><p>Qui la funzione <code>Cartoon</code> viene invocata con la parola chiave <code>new</code> . Quindi il <code>this</code> creato internamente sarà associato al nuovo oggetto creato qui, che è <code>tom</code>.</p><h1 id="regola-4-binding-dell-oggetto-globale-di-javascript"><strong>Regola #4: Binding dell'Oggetto Globale di JavaScript </strong></h1><p>Quale pensi che sarà il risultato del codice qui sotto? A cosa è associato <code>this</code> qui?</p><pre><code class="language-js">let sayName = function(name) {
    console.log(this.name);
};

window.name = 'Tapas';
sayName();</code></pre><p>Se la parola chiave <code>this</code> non viene risolta con alcuno dei binding, <em>implicito</em>, <em>esplicito</em> o <code>new</code>, allora <code>this</code> viene associata all'oggetto globale <code>window()</code> .</p><p>Esiste un'eccezione, tuttavia, la modalità strict (<strong>strict mode</strong>) di JavaScript non consente questo binding predefinito.</p><pre><code class="language-js">"use strict";
function myFunction() {
  return this;
}</code></pre><p>Nell'esempio qui sopra, &nbsp;<code>this</code> è <code>undefined.</code></p><h1 id="regola-5-binding-di-un-evento-html-in-javascript"><strong>Regola #5: Binding di un Evento HTML in JavaScript</strong></h1><p>Nei gestori di eventi HTML, <code>this</code> viene associato all'elemento HTML che riceve l'evento.</p><pre><code class="language-html">&lt;button onclick="console.log(this)"&gt;Click Me!&lt;/button&gt;</code></pre><p>Questo è il risultato nella console del click sul pulsante:</p><pre><code class="language-shell">"&lt;button onclick='console.log(this)'&gt;Click Me!&lt;/button&gt;"</code></pre><p>Puoi cambiare lo stile del pulsante al click dell'utente usando la parola chiave <code>this</code>, in questo modo:</p><pre><code class="language-html">&lt;button onclick="this.style.color='teal'"&gt;Click Me!&lt;/button&gt;</code></pre><p>Tuttavia, fai attenzione quando chiami una funzione per gestire un clic del pulsante e usi <code>this</code> all'interno di quella funzione; ipotizziamo questo codice HTML.</p><pre><code class="language-html">&lt;button onclick="changeColor()"&gt;Click Me!&lt;/button&gt;</code></pre><p>e questo codice JavaScript:</p><pre><code class="language-js">function changeColor() {
  this.style.color='teal';
}</code></pre><p>Quanto sopra non funzionerà come atteso. Come abbiamo visto nella regola &nbsp;4, in questo caso <code>this</code> sarà associato all'oggetto globale (in modalità <strong>non</strong> strict), laddove non esiste un oggetto <code>style</code> con il quale impostare il colore.</p><h1 id="riepilogo"><strong>Riepilogo</strong></h1><p>Per riassumere,</p><ul><li>In caso di binding implicito, &nbsp;<code>this</code> viene associato all'oggetto adiacente all'operatore punto (.) quando si invoca il metodo.</li><li>In caso di binding esplicito, possiamo chiamare una funzione con un oggetto quando la funzione è al di fuori del contesto di esecuzione dell'oggetto stesso. I metodi <code>call()</code>, <code>apply()</code>, e <code>bind()</code> giocano un grosso ruolo qui.</li><li>Quando una funzione viene chiamata con la parola chiave <code>new</code>, la parola chiave <code>this</code> all'interno della funzione si associa al nuovo oggetto che si sta costruendo.</li><li>Quando la parola chiave &nbsp;<code>this</code> non è risolta con alcuna dei binding, implicito, esplicito o <code>new</code>, allora <code>this</code> viene associato all'oggetto globale <code>window()</code>. Nella modalità <em>strict</em> di JavaScript, <code>this</code> sarà <code>undefined</code>.</li><li>Nei gestori di evento HTML, &nbsp;<code>this</code> viene associato all'elemento HTML che riceve l'evento.</li></ul><p>C'è un ulteriore caso nel quale &nbsp;<code>this</code> si comporta in modo differente, vale a dire le <em>funzioni freccia E6. </em>Daremo uno sguardo a questo caso in un articolo successivo.</p><p>Spero che tu abbia trovato utile questo articolo. Ti potrebbero anche piacere:</p><ul><li><a href="https://blog.greenroots.info/javascript-hoisting-internals-ckbuavl6f00dllas14hl9ckq1">JavaScript Hoisting Internals</a></li><li><a href="https://blog.greenroots.info/understanding-javascript-execution-context-like-never-before-ckb8x246k00f56hs1nefzpysq">Understanding JavaScript Execution Context like never before</a></li><li><a href="https://blog.greenroots.info/javascript-scope-fundamentals-with-tom-and-jerry-ckcq723h4007vkxs18dxa97ae">JavaScript Scope Fundamentals with Tom and Jerry</a></li><li><a href="https://blog.greenroots.info/understanding-javascript-closure-with-example-ckd17fci5001iw5s1fju4f8r0">Understanding JavaScript Closure with example</a></li></ul><p>Se hai apprezzato questo articolo, condividilo in modo che altri lo possano leggere. Puoi menzionarmi su Twitter (<a href="https://twitter.com/tapasadhikary">@tapasadhikary</a>) nei tuoi commenti, oppure sentiti libero di seguirmi.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Algoritmi di Grafo e Strutture Dati Spiegate con Esempi in Java e C++ ]]>
                </title>
                <description>
                    <![CDATA[ Cos'è un Algoritmo di Grafo? Gli algoritmi di grafo sono un insieme di istruzioni per attraversare (visitare i nodi di) un grafo. Alcuni algoritmi sono usati per trovare uno specifico nodo o il percorso tra due dati nodi. Perché gli Algoritmi di Grafo Sono Importanti I grafi sono strutture dati ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/algoritmi-dei-grafi-e-strutture-dati-spiegate-con-esempi-in-java-e-c/</link>
                <guid isPermaLink="false">648db71de33e9b0675789a82</guid>
                
                    <category>
                        <![CDATA[ Algoritmi ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Tue, 04 Jul 2023 05:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/06/5f9c9e3e740569d1a4ca3c1f.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/graph-algorithms-and-data-structures-explained-with-java-and-c-examples/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Graph Algorithms and Data Structures Explained with Java and C++ Examples</a>
      </p><h2 id="cos-un-algoritmo-di-grafo"><strong>Cos'è un Algoritmo di Grafo?</strong></h2><p>Gli algoritmi di grafo sono un insieme di istruzioni per attraversare (visitare i nodi di) un grafo.</p><p>Alcuni algoritmi sono usati per trovare uno specifico nodo o il percorso tra due dati nodi.</p><h3 id="perch-gli-algoritmi-di-grafo-sono-importanti"><strong>Perché gli Algoritmi di Grafo Sono Importanti</strong></h3><p>I grafi sono strutture dati molto utili che possono essere usate per modellare diversi problemi. Questi algoritmi hanno applicazione diretta nei siti di Social Network, nella modellazione di Macchine a Stati e molto altro.</p><h3 id="alcuni-comuni-algoritmi-di-grafo"><strong>Alcuni Comuni Algoritmi di Grafo</strong></h3><p>Alcuni dei più comuni sono:</p><ul><li>Ricerca in Ampiezza - Breadth First Search (BFS)</li><li>Ricerca in Profondità - Depth First Search (DFS)</li><li>Algoritmo di Dijkstra</li><li>Algoritmo di Floyd-Warshall</li></ul><h2 id="algoritmo-di-bellman-ford"><strong>Algoritmo di Bellman Ford</strong></h2><p>L'algoritmo di Bellman Ford è l'algoritmo per trovare il percorso più breve per grafi che possono avere pesi negativi. Questo algoritmo è anche valido per rilevare cicli di pesi negativi visto che l'algoritmo converge verso una soluzione ottimale in O(V*E) passaggi. Se quanto risultato non è ottimale, allora il grafo contiene un ciclo di peso negativo.</p><p>Ecco un'implementazione in &nbsp;Python:</p><pre><code class="language-Python">infinity = 1e10

def bellman_ford(graph, start, end):
    num_vertices = graph.get_num_vertices()
    edges = graph.get_edges()

    distance = [infinity for vertex in range(num_vertices)]
    previous = [None for vertex in range(num_vertices)]

    distance[start] = 0
    for i range(end+1):
        for (u, v) in edges:
            if distance[v] &gt; distance[u] + graph.get_weight(u, v):
                distance[v] = distance[u] + graph.get_weight(u, v)
                previous[v] = u

    for (u,v) in edges:
        if distance[v] &gt; distance[u] + graph.get_weight(u, v):
            raise NegativeWeightCycleError()
    return distance, previous
# 'distance' è la distanza dall'inizio verso quel nodo con il
# percorso più breve, utile per stampare la distanza più breve.
# 'previous' è un array che contiene il nodo che viene prima di 
# quello corrente, utile per stampare il percorso.
</code></pre><h2 id="ricerca-in-profondit-deep-search-first-dfs-"><strong>Ricerca in Profondità - Deep Search First (DFS)</strong></h2><p>È uno dei più semplici algoritmi di grafo. Attraversa il grafo prima verificando il nodo corrente, poi spostandosi verso uno dei suoi successori e ripetendo il processo. Se il nodo corrente non ha successori da verificare, torna indietro al suo predecessore e il processo continua (spostandosi verso un altro successore). Se viene trovata la soluzione la ricerca si arresta.</p><h3 id="implementazione-c-14-"><strong>Implementazione (C++14)</strong></h3><pre><code class="language-c">#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;queue&gt;  
#include &lt;algorithm&gt;
using namespace std; 
 
class Graph{ 
   int v;    // numero di vertici 
 
   // puntatore a un vettore che contiene una lista di adiacenze
   vector &lt; int &gt; *adj;
public: 
   Graph(int v);  // Costruttore 
 
   // funzione per aggiugere una connessione tra due nodi (edge)
   void add_edge(int v, int w);  
 
   // stampa l'attraversamento dfs da una data sorgente `s` 
   void dfs();
   void dfs_util(int s, vector &lt; bool&gt; &amp;visited);   
}; 
 
Graph::Graph(int v){ 
   this -&gt; v = v; 
   adj = new vector &lt; int &gt;[v]; 
} 
 
void Graph::add_edge(int u, int v){ 
   adj[u].push_back(v); // aggiunge v alla lista u
   adj[v].push_back(v);  // aggiunge u alla lista v (elimina questa istruzione se il grafo è diretto!)
} 
void Graph::dfs(){
   // vettore dei visitati - per tenere traccia dei visitati durante la ricerca DFS
   vector &lt; bool &gt; visited(v, false);  // marca tutti i nodi/vertici come non visitati
   for(int i = 0; i &lt; v; i++)
       if(!visited[i])
           dfs_util(i, visited);
} 
// nota l'utilizzo di una chiamata per riferimento qui!
void Graph::dfs_util(int s, vector &lt; bool &gt; &amp;visited){ 
   // marca il nodo/vertice corrente come visitato
   visited[s] = true;
    // stampa allo standard output (schermo)
   cout &lt;&lt; s &lt;&lt; " ";
   
   // attraversa la suo lista di adiacenze e chiama ricorsivamente dfs_util per tutti i suoi vicini!
   // (solo se il vicino non è ancora stato visitato!)
   for(vector &lt; int &gt; :: iterator itr = adj[s].begin(); itr != adj[s].end(); itr++)
       if(!visited[*itr])
           dfs_util(*itr, visited); 
} 
 
int main() 
{ 
   // crea un grafo usando la classe Graph definita qui sopra
   Graph g(4); 
   g.add_edge(0, 1); 
   g.add_edge(0, 2); 
   g.add_edge(1, 2); 
   g.add_edge(2, 0); 
   g.add_edge(2, 3); 
   g.add_edge(3, 3); 
 
   cout &lt;&lt; "Il seguente è l'attraversamento Deep First del grafo fornito"
        &lt;&lt; "(a partire dal vertice 0): "; 
   g.dfs(); 
   // il risultato sarebbe: 0 1 2 3
   return 0; 
} 
</code></pre><h3 id="valutazione"><strong>Valutazione</strong></h3><p>Complessità di spazio: O(n)</p><p>Complessità temporale per il caso peggiore O(n). Depth First Search è completo su una serie di nodi finita. Funziona meglio su alberi <em>shallow</em> (vale a dire alberi che hanno una piccola altezza o profondità, cioè un limitato numero di livelli o strati - n.d.t.).</p><h3 id="implementazione-di-dfs-in-c-"><strong>Implementazione di DFS in C++</strong></h3><pre><code class="language-c">#include&lt;iostream&gt;
#include&lt;vector&gt;
#include&lt;queue&gt;

using namespace std;

struct Graph{
	int v;
	bool **adj;
	public:
		Graph(int vcount);
		void addEdge(int u,int v);
		void deleteEdge(int u,int v);
		vector&lt;int&gt; DFS(int s);
		void DFSUtil(int s,vector&lt;int&gt; &amp;dfs,vector&lt;bool&gt; &amp;visited);
};
Graph::Graph(int vcount){
	this-&gt;v = vcount;
	this-&gt;adj=new bool*[vcount];
	for(int i=0;i&lt;vcount;i++)
		this-&gt;adj[i]=new bool[vcount];
	for(int i=0;i&lt;vcount;i++)
		for(int j=0;j&lt;vcount;j++)
			adj[i][j]=false;
}

void Graph::addEdge(int u,int w){
	this-&gt;adj[u][w]=true;
	this-&gt;adj[w][u]=true;
}

void Graph::deleteEdge(int u,int w){
	this-&gt;adj[u][w]=false;
	this-&gt;adj[w][u]=false;
}

void Graph::DFSUtil(int s, vector&lt;int&gt; &amp;dfs, vector&lt;bool&gt; &amp;visited){
	visited[s]=true;
	dfs.push_back(s);
	for(int i=0;i&lt;this-&gt;v;i++){
		if(this-&gt;adj[s][i]==true &amp;&amp; visited[i]==false)
			DFSUtil(i,dfs,visited);
	}
}

vector&lt;int&gt; Graph::DFS(int s){
	vector&lt;bool&gt; visited(this-&gt;v);
	vector&lt;int&gt; dfs;
	DFSUtil(s,dfs,visited);
	return dfs;
}
</code></pre><h2 id="algoritmo-di-floyd-warshall"><strong>Algoritmo di Floyd Warshall</strong></h2><p>È un ottimo algoritmo per trovare la distanza più breve tra tutti i vertici in un grafo. È un algoritmo molto conciso e una complessità temporale di O(V^3) (dove V è il numero dei vertici). Può essere usato con pesi negativi, anche se i cicli di pesi negativi non devono essere presenti nei grafi.</p><h3 id="valutazione-1"><strong>Valutazione</strong></h3><p>Complessità di spazio: O(V^2)</p><p>Complessità temporale per il caso peggiore: O(V^3)</p><h3 id="implementazione-python"><strong>Implementazione Python</strong></h3><pre><code class="language-Python"># Un grande valore come infinito
inf = 1e10 

def floyd_warshall(weights):
    V = len(weights)
    distance_matrix = weights
    for k in range(V):
        next_distance_matrix = [list(row) for row in distance_matrix] # fa una copia della matrice di distanze
        for i in range(V):
            for j in range(V):
                # Sceglie se il vertice k può andare bene come percorso con una distanza minore
                next_distance_matrix[i][j] = min(distance_matrix[i][j], distance_matrix[i][k] + distance_matrix[k][j])
        distance_matrix = next_distance_matrix # update
    return distance_matrix

# Un grafo rappresentato come matrice delle adiacenze 
graph = [
    [0, inf, inf, -3],
    [inf, 0, inf, 8],
    [inf, 4, 0, -2],
    [5, inf, 3, 0]
]

print(floyd_warshall(graph))
</code></pre><h2 id="ricerca-in-ampiezza-breadth-first-search-bfs-"><strong>Ricerca in Ampiezza - Breadth First Search (BFS)</strong></h2><p>È uno degli algoritmi di grafo più semplici. Attraversa il grafo prima verificando il nodo corrente, quindi espandendosi aggiungendo i suoi successori al livello successivo. Questo processo viene ripetuto per tutti i nodi nel livello corrente prima di spostarsi a quello successivo. Se la soluzione viene trovata, la ricerca si arresta.</p><h3 id="visualizzazione"><strong>Visualizzazione</strong></h3><figure class="kg-card kg-image-card"><img src="https://upload.wikimedia.org/wikipedia/commons/4/46/Animated_BFS.gif" class="kg-image" alt="Animated_BFS" width="187" height="175" loading="lazy"></figure><h3 id="valutazione-2"><strong>Valutazione</strong></h3><p>Complessità di spazio: O(n)</p><p>Complessità per il caso peggiore: O(n)</p><p>La Ricerca in Ampiezza è completa su un insieme finito di nodi e ottimale se il costo dello spostamento da un nodo all'altro è costante.</p><h3 id="codice-c-per-l-implementazione-di-bfs"><strong>Codice C++ per l'implementazione di BFS </strong></h3><pre><code class="language-c">// Programma per stampre l'attraversamento BFS da un dato
// vertice sorgente. BFS(int s) attraversa i vertici
// raggiungibili da s
#include&lt;iostream&gt; 
#include &lt;list&gt; 
  
using namespace std; 
  
// Questa classe rappresenta un grafo diretto usando una
// rappresentazione con lista di adiacenze
class Graph 
{ 
    int V;    // No. of vertices 
  
    // Puntatore a un array che contiene una lista di adiacenze
    list&lt;int&gt; *adj;    
public: 
    Graph(int V);  // Costruttore
  
    // funczione per aggiungere una connessione tra due nodi (edge) al grafo
    void addEdge(int v, int w);  
  
    // stampa l'attraversamento BFS da una data sorgente s
    void BFS(int s);   
}; 
  
Graph::Graph(int V) 
{ 
    this-&gt;V = V; 
    adj = new list&lt;int&gt;[V]; 
} 
  
void Graph::addEdge(int v, int w) 
{ 
    adj[v].push_back(w); // Add w to v’s list. 
} 
  
void Graph::BFS(int s) 
{ 
    // marca tutti i vertici come non visitati
    bool *visited = new bool[V]; 
    for(int i = 0; i &lt; V; i++) 
        visited[i] = false; 
  
    // Crea una coda per BFS 
    list&lt;int&gt; queue; 
  
    // Marca il nodo corrente come visitato e lo accoda
    visited[s] = true; 
    queue.push_back(s); 
  
    // 'i' verrà usato per ottenere tutti i vertici 
    // adiacenti di un vertice
    list&lt;int&gt;::iterator i; 
  
    while(!queue.empty()) 
    { 
        // Fa uscire un vertice dalla code e lo stampa
        s = queue.front(); 
        cout &lt;&lt; s &lt;&lt; " "; 
        queue.pop_front(); 
  
        // Ottiene tutti i vertici adiacenti di quello 
        // tolto dalla coda s. Se una adiacente non è stato
        // visitato, viene marcato come visitato e accodato
        for (i = adj[s].begin(); i != adj[s].end(); ++i) 
        { 
            if (!visited[*i]) 
            { 
                visited[*i] = true; 
                queue.push_back(*i); 
            } 
        } 
    } 
} 
  
// Programma per testare i metodi della classe Graph
int main() 
{ 
    // Crea un grafo dato il diagramma seguente
    Graph g(4); 
    g.addEdge(0, 1); 
    g.addEdge(0, 2); 
    g.addEdge(1, 2); 
    g.addEdge(2, 0); 
    g.addEdge(2, 3); 
    g.addEdge(3, 3); 
  
    cout &lt;&lt; "Il seguente è un attraversamento Breadth First Traversal "
         &lt;&lt; "(a partire dal vertice 2) \n"; 
    g.BFS(2); 
  
    return 0; 
}
</code></pre><h2 id="algoritmo-di-dijkstra"><strong>Algoritmo di Dijkstra</strong></h2><p>È un algoritmo presentato da E.W. Dijkstra. Cerca la sorgente del percorso più breve in un grafo con connessioni (edge) non negative (perché?).</p><p>Creiamo 2 array: <code>visited</code> e <code>distance</code>, che registrano rispettivamente se un vertice è visitato e qual è la distanza minima dal vertice sorgente. Inizialmente l'array <code>visited</code> viene assegnato con valori <code>false</code> e <code>distance</code> come infinito.</p><p>Partiamo dal vertice sorgente, che sarà <code>u</code>, e i suoi vertici adiacenti <code>v</code>. Ora per ogni <code>v</code> che è adiacente a <code>u</code>, la distanza è aggiornata se non è stato visitato prima e la distanza da <code>u</code> è minore della distanza corrente. Poi selezioniamo il vertice successivo con la distanza minore e che non sia stato ancora visitato.</p><p>Una coda di priorità è spesso usata per soddisfare quest'ultimo requisito nel minor tempo. Qui sotto un'implementazione della stessa idea usando <code>PriorityQueue</code> in Java.</p><pre><code class="language-Java">import java.util.*;
public class Dijkstra {
    class Graph {
	LinkedList&lt;Pair&lt;Integer&gt;&gt; adj[];
	int n; // Numero di vertici.
	Graph(int n) {
	    this.n = n;
	    adj = new LinkedList[n];
	    for(int i = 0;i&lt;n;i++) adj[i] = new LinkedList&lt;&gt;();
	}
	// aggiunge una connessione tra i vertici a e b con il costo come peso	public void addEdgeDirected(int a, int b, int cost) {
	    adj[a].add(new Pair(b, cost));
	}
	public void addEdgeUndirected(int a, int b, int cost) {
	    addEdgeDirected(a, b, cost);
	    addEdgeDirected(b, a, cost);
	}
    }
    class Pair&lt;E&gt; {
	E first;
	E second;
	Pair(E f, E s) {
	    first = f;
	    second = s;
	}
    }

    // Comparator per ordinare gli oggetti Pairs nella Priority Queue
    class PairComparator implements Comparator&lt;Pair&lt;Integer&gt;&gt; {
	public int compare(Pair&lt;Integer&gt; a, Pair&lt;Integer&gt; b) {
	    return a.second - b.second;
	}
    }

    // Calola il percorso più corto dalla sorgente per ogni vertice e ritorna la distanza
    public int[] dijkstra(Graph g, int src) {
	int distance[] = new int[g.n]; // la distanza più breve di ciascun vertice da src
	boolean visited[] = new boolean[g.n]; // il vertice è visitato o no
	Arrays.fill(distance, Integer.MAX_VALUE);
	Arrays.fill(visited, false);
	PriorityQueue&lt;Pair&lt;Integer&gt;&gt; pq = new PriorityQueue&lt;&gt;(100, new PairComparator());
        pq.add(new Pair&lt;Integer&gt;(src, 0));
	distance[src] = 0;
	while(!pq.isEmpty()) {
	    Pair&lt;Integer&gt; x = pq.remove(); // Estrae il vertice con la distanza più breve da src
	    int u = x.first;
	    visited[u] = true;
	    Iterator&lt;Pair&lt;Integer&gt;&gt; iter = g.adj[u].listIterator();
	    // Itera sui vicini di u e aggiorna le loro distanze
	    while(iter.hasNext()) {
		Pair&lt;Integer&gt; y = iter.next();
		int v = y.first;
		int weight = y.second;
		// Verifica se il vertice v non è visitato
		// Se il nuovo percorso attraverso u offre un costo minore allora aggiorna l'array distance e aggiungi a pq
		if(!visited[v] &amp;&amp; distance[u]+weight&lt;distance[v]) {
		    distance[v] = distance[u]+weight;
		    pq.add(new Pair(v, distance[v]));
		}
	    }
	}
	return distance;
    }

    public static void main(String args[]) {
	Dijkstra d = new Dijkstra();
	Dijkstra.Graph g = d.new Graph(4);
	g.addEdgeUndirected(0, 1, 2);
	g.addEdgeUndirected(1, 2, 1);
	g.addEdgeUndirected(0, 3, 6);
	g.addEdgeUndirected(2, 3, 1);
	g.addEdgeUndirected(1, 3, 3);

	int dist[] = d.dijkstra(g, 0);
	System.out.println(Arrays.toString(dist));
    }
}
</code></pre><h2 id="algoritmo-di-ford-fulkerson"><strong>Algoritmo di Ford Fulkerson</strong></h2><p>Questo algoritmo risolve il problema del massimo flusso del grafo. Trova la migliore soluzione di flusso tramite le connessioni (edge) dei grafi in modo da ottenere il massimo flusso in uscita dall'altra parte. La sorgente ha una specifica velocità di input e ciascuna connessione ha un peso associato a essa che è la quantità massima che può passare attraverso quella connessione.</p><p>L'algoritmo di Ford Fulkerson è anche chiamato algoritmo di Edmund-Karp visto che le specifiche complete sono state fornite da Jack Edmonds e Richard Karp.</p><p>Funziona creando percorsi di aumento, ovvero percorsi dalla sorgente all'uscita che hanno un flusso non zero. Facciamo passare il flusso attraverso i percorsi e aggiorniamo i limiti. Ciò può portare a situazioni in cui non abbiamo più mosse disponibili. Ecco dove la capacità di "annullamento" di questo algoritmo gioca un ruolo importante. In caso di blocco, diminuiamo il flusso e apriamo la connessione per far passare la nostra sostanza corrente.</p><h2 id="passaggi"><strong>Passaggi</strong></h2><ol><li>Imposta il flusso a zero per tutte le connessioni.</li><li>Fintanto che c'è un percorso dalla sorgente allo scarico:</li><li>Cerca il peso minimo sul percorso, che associ a &nbsp;<code>limit</code> .</li><li>Trova tutte le connessioni (<code>u</code>, <code>v</code>) sul percorso e:<br>1. Aggiungi &nbsp;<code>limit</code> &nbsp;al flusso da <code>u</code> a <code>v</code>. (Per la mossa corrente)<br>2. Sottrai &nbsp;<code>limit</code> &nbsp;dal flusso da <code>v</code> a <code>u</code> (Per un annullamento della mossa in futuro)</li></ol><h3 id="valutazione-3"><strong>Valutazione</strong></h3><p>Complessità temporale: <code>O(V*E^2)</code></p><h3 id="implementazione-python-1"><strong>Implementazione Python</strong></h3><pre><code class="language-Python"># Un numero grande per infinito
inf = 1e10

def maximum_flow(graph, source, sink):
  max_flow = 0
  parent = bfs(graph, source, sink)
  while path:
    limit = inf
    v = sink
    while v != source:
        u = parent[s]
        path_flow = min(limit, graph[u][v])
        v = parent[v]
    max_flow += path_flow

    v = sink
    while v != source:
        u = parent[v]
        graph[u][v] -= path_flow
        graph[v][u] += path_flow
        v = parent[v]

    path = bfs(graph, source, sink)
  return max_flow</code></pre> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Il Manuale delle Migliori Pratiche di Progettazione di API REST - Come Creare un'API REST con JavaScript, Node.js ed Express.js ]]>
                </title>
                <description>
                    <![CDATA[ Ho creato e utilizzato molte API negli ultimi anni. In questo periodo, mi sono imbattuto in buone e cattive pratiche e ho sperimentato brutte situazioni durante l'utilizzo e la creazione di API. Ma ci sono stati anche grandi momenti. Ci sono articoli utili online che presentano molte migliori pratiche, ma ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/il-manuale-delle-migliori-pratiche-di-progettazione-di-api-rest/</link>
                <guid isPermaLink="false">642e916ebdacb60671303019</guid>
                
                    <category>
                        <![CDATA[ API Rest ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jul 2023 05:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/04/rest-api-design-course-header.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/rest-api-design-best-practices-build-a-rest-api/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">REST API Design Best Practices Handbook – How to Build a REST API with JavaScript, Node.js, and Express.js</a>
      </p><p>Ho creato e utilizzato molte API negli ultimi anni. In questo periodo, mi sono imbattuto in buone e cattive pratiche e ho sperimentato brutte situazioni durante l'utilizzo e la creazione di API. Ma ci sono stati anche grandi momenti.</p><p>Ci sono articoli utili online che presentano molte migliori pratiche, ma secondo me molti di essi mancano di praticità. Conoscere la teoria con pochi esempi va bene, ma mi sono sempre chiesto come sarebbe l'implementazione in un esempio più attinente al mondo reale.</p><p>Fornire esempi semplici aiuta nella comprensione del concetto stesso senza molta complessità, ma in pratica le cose non sono sempre così semplici. Sono piuttosto sicuro che sai di cosa sto parlando 😁</p><p>Ecco perché ho deciso di scrivere questo tutorial. Ho unito insieme tutte le cose (buone e meno buone) che ho appreso in un articolo fruibile fornendo un esempio pratico che può essere seguito. Alla fine, creeremo un'API completa mentre implementeremo una buona pratica dopo l'altra.</p><p>Alcune cose da ricordare prima di partire:</p><p>Le buone pratiche, come potresti avere intuito, non sono leggi o regole specifiche da seguire. Sono convenzioni o suggerimenti che si sono evoluti nel tempo e si sono rivelati efficaci. Al giorno d'oggi, alcune sono diventate lo standard. Tuttavia questo non vuol dire che tu le debba adottare in toto.</p><p>Dovrebbero fornirti una direzione per rendere la tua API migliore per quanto riguarda l'esperienza utente (sia chi la usa che chi la crea), la sicurezza e le prestazioni.</p><p>Tieni a mente che i progetti sono diversi e richiedono diversi approcci. Potrebbero esserci situazioni nelle quali non puoi o non dovresti seguire certe convenzioni. Quindi ogni sviluppatore deve prendere queste decisioni in autonomia o con i suoi colleghi.</p><p>Ora che abbiamo tolto di mezzo queste cose, senza ulteriori indugi, mettiamoci al lavoro!</p><h2 id="sommario"><strong>Sommario</strong></h2><ul><li><a href="#il-nostro-progetto-di-esempio">Il nostro progetto di esempio</a></li><li><a href="#prerequisiti">Prerequisiti</a></li><li><a href="#architettura">Architettura</a></li><li><a href="#impostazione-di-base">Impostazione di base</a></li><li><a href="#migliori-pratiche-per-api-rest">Migliori pratiche per API REST</a></li><li><a href="#versionamento">Versionamento</a></li><li><a href="#nomi-di-risorse-al-plurale">Nomi risorse al plurale</a></li><li><a href="#accettare-e-rispondere-con-dati-in-formato-json">Accettare e rispondere con dati in formato JSON</a></li><li><a href="#rispondere-con-codici-di-errore-standard-http">Rispondere con codici di errore standard HTTP</a>	</li><li><a href="#evitare-verbi-nei-nomi-degli-endpoint">Evitare verbi nei nomi degli endpoint</a></li><li><a href="#raggruppare-risorse-associate">Raggruppare risorse associate</a></li><li><a href="#integrare-filtro-ordinamento-e-paginazione">Integrare filtro, ordinamento e paginazione</a></li><li><a href="#usare-cache-dei-dati-per-migliorare-le-prestazioni">Usare cache dei dati per migliorare le prestazioni</a></li><li><a href="#buone-pratiche-di-sicurezza">Buone pratiche di sicurezza</a></li><li><a href="#documentare-correttamente-la-tua-api">Documentare correttamente la tua API</a></li><li><a href="#conclusione">Conclusione</a></li></ul><h3 id="il-nostro-progetto-di-esempio">Il Nostro Progetto di Esempio</h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/04/alvaro-reyes-qWwpHwip31M-unsplash--1-.jpg" class="kg-image" alt="alvaro-reyes-qWwpHwip31M-unsplash--1-" width="600" height="400" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@alvarordesign?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Alvaro Reyes</a> on <a href="https://unsplash.com/s/photos/project?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><p>Prima di iniziare l'implementazione delle migliori pratiche nel nostro progetto di esempio, ti faccio una breve introduzione di ciò che andremo a creare.</p><p>Creeremo un'API REST per una Applicazione di Allenamento CrossFit. Se non sei familiare con il CrossFit, si tratta di un metodo di fitness e uno sport competitivo che combina allenamenti ad alta intensità con elementi da parecchi sport (sollevamento pesi, ginnastica e altri).</p><p>Nella nostra applicazione vorremmo creare, leggere, aggiornare e cancellare i <strong><strong>WOD</strong></strong> (<strong><strong>W</strong></strong>orkouts <strong><strong>o</strong></strong>f the <strong><strong>D</strong></strong>ay - Allenamenti della giornata). Questo aiuterà i nostri utenti (vale a dire i proprietari di palestre) a generare piani di allenamento e tracciare i propri allenamenti all'interno di una singola applicazione. Inoltre potranno anche aggiungere qualche importante suggerimento di allenamento per ciascuna sessione.</p><p>Il nostro compito sarà la progettazione e l'implementazione di un'API per quell'applicazione.</p><h3 id="prerequisiti">Prerequisiti</h3><p>Per seguire il tutorial dovrai avere qualche esperienza di JavaScript, Node.js, Express.js e di architettura di backend. Termini come REST e API non dovrebbero essere nuovi per te e dovresti avere una comprensione del <a href="https://it.wikipedia.org/wiki/Sistema_client/server">Modello Client-Server</a>.</p><p>Naturalmente non devi essere un esperto in questi campi, ma averne familiarità e possibilmente qualche esperienza dovrebbe essere sufficiente.</p><p>Se non hai tutti i prerequisiti, ovviamente non è un motivo per saltare questo tutorial. C'è ancora molto da imparare qui anche per te. Ma avere queste conoscenze ti renderà più facile seguire.</p><p>Anche se questa API è scritta in JavaScript e usa Express, le migliori pratiche non si limitano a questi strumenti. Possono essere applicate anche ad altri linguaggi di programmazione o framework.</p><h3 id="architettura"><strong><strong>Archite</strong>t<strong>tur</strong>a</strong></h3><p>Come discusso qui sopra, useremo Express.js per la nostra API. Non voglio creare un'architettura complessa, quindi mi piacerebbe attenermi all'<strong>architettura a 3 livelli</strong>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-25-um-14.33.24-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-25-um-14.33.24-1" width="600" height="400" loading="lazy"></figure><p>All'interno del <strong><strong>Controller</strong></strong> gestiremo tutto ciò che abbia relazione con HTTP. Il che vuol dire che avremo a che fare con richieste e risposte per i nostri endpoint. Sopra questo livello c'è anche un piccolo <strong><strong>Router</strong></strong> da Express che instrada le richieste al controller corrispondente.</p><p>Tutta la logica di business sarà nel<strong><strong> Service</strong> Layer<strong> </strong></strong>(Livello Servizio) che esporta certi servizi (metodi) usati dal controller.</p><p>Il terzo livello, <strong><strong>Data Access Layer</strong></strong> &nbsp;(Livello di Accesso Dati) sarà dove lavoreremo con il nostro database. Esporteremo alcuni metodi per certe operazioni di database come creare un WOD (allenamento del giorno) che può essere usato dal nostro Service Layer.</p><p>Nel nostro esempio non useremo un <em>vero</em> database come MongoDB o PostgreSQL in quanto preferirei concentrarmi maggiormente sulle migliori pratiche stesse. Pertanto useremo un file JSON locale che imita il nostro database. Tuttavia questa logica può essere trasferita ad altri database, naturalmente.</p><h3 id="impostazione-di-base"><strong>Impostazione di Base</strong></h3><p>Ora dovremmo essere in grado di creare l'impostazione di base per la nostra API. Non complicheremo eccessivamente le cose e costruiremo una struttura di progetto semplice ma organizzata.</p><p>Per prima cosa creiamo la struttura di directory generale con tutti i file necessari e le dipendenze. Quindi eseguiremo un piccolo test per verificare che tutto venga eseguito correttamente:</p><pre><code class="language-bash"># Crea la directory del progetto e portati su di essa
mkdir crossfit-wod-api &amp;&amp; cd crossfit-wod-api</code></pre><pre><code class="language-bash"># Crea una cartella src e portati su di essa
mkdir src &amp;&amp; cd src</code></pre><pre><code class="language-bash"># Crea le sotto cartelle
mkdir controllers &amp;&amp; mkdir services &amp;&amp; mkdir database &amp;&amp; mkdir routes</code></pre><pre><code class="language-bash"># Crea un file indice (il punto di entrata della nostra API)
touch index.js</code></pre><pre><code class="language-bash"># Attualmente ci troviamo nella cartella src, quindi dobbiamo prima salire di un livello 
cd .. 

# Crea il file package.json 
npm init -y</code></pre><p>Installa le dipendenze per l'impostazione di base:</p><pre><code class="language-bash"># Dipendenze di sviluppo
npm i -D nodemon 

# Dipendenze 
npm i express</code></pre><p>Apri il progetto con il tuo editor di testo preferito e configura Express:</p><pre><code class="language-javascript">// In src/index.js 
const express = require("express"); 

const app = express(); 
const PORT = process.env.PORT || 3000; 

// A scopo di test 
app.get("/", (req, res) =&gt; { 
    res.send("&lt;h2&gt;It's Working!&lt;/h2&gt;"); 
}); 

app.listen(PORT, () =&gt; { 
    console.log(`API is listening on port ${PORT}`); 
});</code></pre><p>Aggiungi un nuovo script chiamato <strong><strong>"dev"</strong></strong> all'interno di package.json:</p><pre><code class="language-json">{
  "name": "crossfit-wod-api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon src/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "nodemon": "^2.0.15"
  },
  "dependencies": {
    "express": "^4.17.3"
  }
}
</code></pre><p>Lo script si assicura che il server di sviluppo venga riavviato automaticamente quando eseguiamo delle modifiche (grazie a nodemon).</p><p>Lancia il server di sviluppo:</p><pre><code class="language-bash">npm run dev</code></pre><p>Se osservi il tuo terminale, dovresti vedere un messaggio che dice <strong><strong>"API is listening on port 3000"</strong></strong>.</p><p>All'interno del tuo browser vai a <strong><strong>localhost:3000</strong></strong>. Se tutto è impostato correttamente, dovresti vedere quanto segue:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.09.44.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-11.09.44" width="600" height="400" loading="lazy"></figure><p>Grande! Ora tutto è impostato per implementare le migliori pratiche.</p><h2 id="migliori-pratiche-per-api-rest"><strong>Migliori Pratiche per API <strong>REST</strong></strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/04/constantin-wenning-idDvA4jPBO8-unsplash--1-.jpg" class="kg-image" alt="constantin-wenning-idDvA4jPBO8-unsplash--1-" width="600" height="400" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@conniwenningsimages?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Constantin Wenning</a> on <a href="https://unsplash.com/s/photos/handshake?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><p>Bene! Ora che abbiamo un'impostazione veramente di base per Express, possiamo estendere la nostra API con le seguenti migliori pratiche.</p><p>Iniziamo in modo semplice con i nostri endpoint <a href="https://it.wikipedia.org/wiki/CRUD">CRUD</a> fondamentali. Successivamente estenderemo l'API con ciascuna migliore pratica.</p><h3 id="versionamento"><strong><strong>Version</strong>amento</strong></h3><p>Aspetta un secondo. Prima di scrivere codice specifico per qualsiasi API dobbiamo essere consapevoli del versionamento. Come in ogni altra applicazione, ci saranno miglioramenti, nuove funzionalità e cose di questo genere. Quindi è importante applicare un buon versionamento anche alla nostra API.</p><p>Il grande vantaggio è che possiamo lavorare con nuove funzionalità o miglioramenti su una nuova versione mentre i client stanno ancora usando la versione corrente e non saranno interessati da modifiche non retro compatibili.</p><p>Non forzeremo neanche i client ad adottare la nuova versione immediatamente. Possono usare la versione corrente e migrare in autonomia quando la nuova versione è stabile.</p><p>La versione corrente e la nuova sono praticamente in esecuzione in parallelo e non interferiscono tra loro.</p><p>Come possiamo differenziare le versioni? Una buona pratica è aggiungere un segmento di percorso come <strong><strong>v1</strong></strong> o <strong><strong>v2 </strong></strong>all'interno dell'URL.</p><pre><code class="language-javascript">// Versione 1 
"/api/v1/workouts" 

// Versione 2 
"/api/v2/workouts" 

// ...</code></pre><p>Ecco ciò che esporremo al mondo esterno, quello che sarà utilizzato da altri sviluppatori. Dobbiamo anche strutturare il nostro progetto per poter differenziare ogni versione.</p><p>Ci sono molti approcci diversi per la gestione del versionamento all'interno di una API Express. Nel nostro caso, vorrei creare una sotto cartella per ogni versione all'interno della directory <strong>src</strong> chiamata <strong><strong>v1</strong></strong>, <strong>v2 </strong>e così via.</p><pre><code class="language-bash">mkdir src/v1</code></pre><p>Ora spostiamo la cartella <code>routes</code> nella nuova directory <code>v1</code>.</p><pre><code class="language-bash"># Ottieni il percorso della tua directory corrente (copialo)
pwd 

# Sposta "routes" in "v1" (inserisci il percorso ricavato qui sopra in {pwd}) 
mv {pwd}/src/routes {pwd}/src/v1</code></pre><p>La nuova directory <strong><strong><code>/src/v1/routes</code> </strong></strong>conterrà tutte le nostre rotte per la versione 1. Aggiungeremo "vero" contenuto successivamente. Per ora aggiungiamo un semplice file <strong><strong>index.js </strong></strong>per vedere se funziona.</p><pre><code class="language-bash"># In /src/v1/routes 
touch index.js</code></pre><p>All'interno del file inseriamo il codice per avviare un semplice router.</p><pre><code class="language-javascript">// In src/v1/routes/index.js
const express = require("express");
const router = express.Router();

router.route("/").get((req, res) =&gt; {
  res.send(`&lt;h2&gt;Hello from ${req.baseUrl}&lt;/h2&gt;`);
});

module.exports = router;</code></pre><p>Ora dobbiamo attaccare il nostro router per v1 all'interno del punto di entrata radice nel file <code>src/index.js</code>.</p><pre><code class="language-javascript">// In src/index.js
const express = require("express");
// *** AGGIUNGI ***
const v1Router = require("./v1/routes");

const app = express();
const PORT = process.env.PORT || 3000;

// *** RIMUOVI ***
app.get("/", (req, res) =&gt; {
  res.send("&lt;h2&gt;It's Working!&lt;/h2&gt;");
});

// *** AGGIUNGI ***
app.use("/api/v1", v1Router);

app.listen(PORT, () =&gt; {
  console.log(`API is listening on port ${PORT}`);
});
</code></pre><p>Ora nel tuo browser vai a <strong><strong>localhost:3000/api/v1</strong></strong> e dovresti vedere quanto segue:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.22.28.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-11.22.28" width="600" height="400" loading="lazy"></figure><p>Congratulazioni! Hai appena strutturato il progetto per gestire diverse versioni. Ora passiamo le richieste in arrivo su <code>/api/v1</code> alla versione 1 del nostro router, il quale successivamente instraderà ogni richiesta al metodo del controller corrispondente.</p><p>Prima di continuare, vorrei sottolineare una cosa.</p><p>Abbiamo appena spostato la nostra cartella <code>routes</code> all'interno della directory <code>v1</code>. Le altre cartelle come <code>controllers</code> o <code>services</code> rimangono ancora nella directory <code>src</code>. Questo va bene per adesso in quanto stiamo creando un'API piuttosto piccola. Possiamo usare gli stessi controller e servizi in ogni versione globalmente.</p><p>Quando l'API sta crescendo e richiede diversi metodi di controller specifici per la versione v2, per esempio, sarebbe una idea migliore spostare la cartella <code>controllers</code> all'interno della directory v2 in modo di avere tutta la logica specifica per quella particolare versione incapsulata.</p><p>Un'altra ragione per fare questo potrebbe essere che potremmo cambiare un servizio che è usato da tutte le altre versioni. Non vogliamo che ci siano problemi di compatibilità con altre versioni. Pertanto sarebbe una decisione saggia spostare anche la cartella <code>services</code> all'interno della cartella della specifica versione.</p><p>Come detto in precedenza, tuttavia, nel nostro esempio ritengo che vada bene differenziare solo le rotte e lasciare che il router gestisca il resto. Cionondimeno è importante tenere a mente di avere una struttura pulita quando l'API cresce di dimensioni e necessita di modifiche.</p><h3 id="nomi-di-risorse-al-plurale"><strong>Nomi di Risorse al Plurale</strong></h3><p>Dopo aver impostato tutto possiamo concentrarci sulla vera implementazione della nostra API. Come ho detto, vorrei iniziare con gli endpoint CRUD fondamentali.</p><p>In altre parole, iniziamo implementando gli endpoint per creare, leggere, aggiornare ed eliminare gli allenamenti.</p><p>Per prima cosa creiamo un controller, un servizio e un router specifici per i nostri allenamenti (workout).</p><pre><code class="language-bash">touch src/controllers/workoutController.js 

touch src/services/workoutService.js 

touch src/v1/routes/workoutRoutes.js</code></pre><p>Mi piace sempre partire prima con le rotte. Pensiamo come denominare i nostri endpoint. Ciò va di pari passo con questa particolare miglior pratica.</p><p>Possiamo denominare l'endpoint di creazione <strong><strong><code>/api/v1/workout</code> </strong></strong>in quanto vorremmo aggiungere un altro allenamento, giusto? Praticamente c'è nulla di sbagliato con questo approccio, ma può portare a fraintendimenti.</p><p>Ricorda sempre: la tua API viene usata da altri esseri umani e dovrebbe essere precisa. Questo si applica anche per la denominazione delle tue risorse.</p><p>Ho sempre immaginato una risorsa come una scatola. Nel nostro esempio la scatola è una collezione che contiene diversi <strong>allenamenti </strong>(workouts).</p><p>Usare il plurale per denominare le tue risorse ha il grande vantaggio che per le altre persone risulta chiaro che si tratta di una collezione di diversi allenamenti.</p><p>Pertanto definiamo i nostri endpoint all'interno del router nel file <code>workoutRoutes.js</code>.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
const express = require("express");
const router = express.Router();

router.get("/", (req, res) =&gt; {
  res.send("Get all workouts");
});

router.get("/:workoutId", (req, res) =&gt; {
  res.send("Get an existing workout");
});

router.post("/", (req, res) =&gt; {
  res.send("Create a new workout");
});

router.patch("/:workoutId", (req, res) =&gt; {
  res.send("Update an existing workout");
});

router.delete("/:workoutId", (req, res) =&gt; {
  res.send("Delete an existing workout");
});

module.exports = router;
</code></pre><p>Puoi eliminare il file di test <strong><strong><code>index.js</code></strong></strong> all'interno di <strong><strong><code>src/v1/routes</code></strong></strong>.</p><p>Ora passiamo ai nostri punti di entrata e agganciamo il nostro router per la versione v1 (v1WorkoutRouter).</p><pre><code class="language-javascript">// In src/index.js
const express = require("express");
// *** RIMUOVI ***
const v1Router = require("./v1/routes");
// *** AGGIUNGI ***
const v1WorkoutRouter = require("./v1/routes/workoutRoutes");

const app = express();
const PORT = process.env.PORT || 3000;

// *** RIMUOVI ***
app.use("/api/v1", v1Router);

// *** AGGIUNGI ***
app.use("/api/v1/workouts", v1WorkoutRouter);

app.listen(PORT, () =&gt; {
  console.log(`API is listening on port ${PORT}`);
});
</code></pre><p>È andato tutto liscio, giusto? Ora catturiamo tutte le richieste verso <strong><strong><code>/api/v1/workouts</code></strong></strong> con il nostro <code>v1WorkoutRouter</code>.</p><p>All'interno del nostro router chiameremo un metodo diverso gestito dal nostro controller per ciascun endpoint.</p><p>Creiamo un metodo per ciascun endpoint. Inviamo semplicemente un messaggio di risposta, dovrebbe bastare per adesso.</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
const getAllWorkouts = (req, res) =&gt; {
  res.send("Get all workouts");
};

const getOneWorkout = (req, res) =&gt; {
  res.send("Get an existing workout");
};

const createNewWorkout = (req, res) =&gt; {
  res.send("Create a new workout");
};

const updateOneWorkout = (req, res) =&gt; {
  res.send("Update an existing workout");
};

const deleteOneWorkout = (req, res) =&gt; {
  res.send("Delete an existing workout");
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Ora è tempo di rifattorizzare un po' il nostro router e usare i metodi del controller.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
const express = require("express");
const workoutController = require("../../controllers/workoutController");

const router = express.Router();

router.get("/", workoutController.getAllWorkouts);

router.get("/:workoutId", workoutController.getOneWorkout);

router.post("/", workoutController.createNewWorkout);

router.patch("/:workoutId", workoutController.updateOneWorkout);

router.delete("/:workoutId", workoutController.deleteOneWorkout);

module.exports = router;
</code></pre><p>Ora possiamo testare le nostre richieste <strong><strong>GET</strong> </strong>per l'endopoint <strong><strong><code>/api/v1/workouts/:workoutId</code></strong></strong> digitando <strong><strong>localhost:3000/api/v1/workouts/2342</strong></strong> nel browser. Dovresti vedere qualcosa tipo questo:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.29.19.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-11.29.19" width="600" height="400" loading="lazy"></figure><p>Ci siamo riusciti! Il primo livello della nostra architettura è fatto. Creiamo ora il livello del servizio implementando la nostra prossima migliore pratica.</p><h3 id="accettare-e-rispondere-con-dati-in-formato-json"><strong>Accettare e Rispondere con Dati in Formato JSON</strong></h3><p>Quando interagisci con un'API, invii sempre dati specifici con la tua richiesta oppure ricevi dati con la risposta. Ci sono molti formati di dato diversi ma JSON (JavaScript Object Notation) è un formato standardizzato.</p><p>Anche se JSON contiene il termine <strong><strong>JavaScript</strong></strong>, non legato specificatamente a questo linguaggio. Puoi scrivere le tue API anche in Java o Python, che sono anch'essi in grado di gestire bene JSON.</p><p>A causa della sua standardizzazione, l'API dovrebbe accettare e rispondere con dati in formato JSON.</p><p>Diamo uno sguardo alla nostra implementazione corrente e vediamo come possiamo integrare questa miglior pratica.</p><p>Per prima cosa creiamo il nostro livello di servizio.</p><pre><code class="language-javascript">// In src/services/workoutService.js
const getAllWorkouts = () =&gt; {
  return;
};

const getOneWorkout = () =&gt; {
  return;
};

const createNewWorkout = () =&gt; {
  return;
};

const updateOneWorkout = () =&gt; {
  return;
};

const deleteOneWorkout = () =&gt; {
  return;
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>È anche una buona pratica denominare i metodi del servizio allo stesso modo dei metodi del controller, in modo da avere una connessione tra questi. Iniziamo con il restituire nulla.</p><p>All'interno del controller nel file <code>workoutController.js</code> possiamo usare questi metodi.</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
// *** AGGIUNGI***
const workoutService = require("../services/workoutService");

const getAllWorkouts = (req, res) =&gt; {
  // *** AGGIUNGI ***
  const allWorkouts = workoutService.getAllWorkouts();
  res.send("Get all workouts");
};

const getOneWorkout = (req, res) =&gt; {
  // *** AGGIUNGI ***
  const workout = workoutService.getOneWorkout();
  res.send("Get an existing workout");
};

const createNewWorkout = (req, res) =&gt; {
  // *** AGGIUNGI ***
  const createdWorkout = workoutService.createNewWorkout();
  res.send("Create a new workout");
};

const updateOneWorkout = (req, res) =&gt; {
  // *** AGGIUNGI ***
  const updatedWorkout = workoutService.updateOneWorkout();
  res.send("Update an existing workout");
};

const deleteOneWorkout = (req, res) =&gt; {
  // *** AGGIUNGI ***
  workoutService.deleteOneWorkout();
  res.send("Delete an existing workout");
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Al momento non dovrebbe cambiare nulla all'interno delle nostre risposte. Tuttavia sotto il cofano il livello controller ora parla con il livello servizio.</p><p>All'interno dei metodi del servizio gestiremo la nostra logica di business come la trasformazione delle strutture dati e la comunicazione con il livello database.</p><p>Per fare questo, ci serve un database e una collezione di metodi che gestisca effettivamente l'interazione con il database. Il nostro database sarà un semplice file JSON che abbiamo già valorizzato in precedenza con qualche allenamento.</p><pre><code class="language-bash"># Crea un nuovo file chiamato db.json all'interno di src/database 
touch src/database/db.json 

# Crea un file workout.js che contiene tutti i metodi specifici per l'allenamento in /src/database 
touch src/database/Workout.js</code></pre><p>Copia quanto segue in db.json:</p><pre><code class="language-json">{
  "workouts": [
    {
      "id": "61dbae02-c147-4e28-863c-db7bd402b2d6",
      "name": "Tommy V",
      "mode": "For Time",
      "equipment": [
        "barbell",
        "rope"
      ],
      "exercises": [
        "21 thrusters",
        "12 rope climbs, 15 ft",
        "15 thrusters",
        "9 rope climbs, 15 ft",
        "9 thrusters",
        "6 rope climbs, 15 ft"
      ],
      "createdAt": "4/20/2022, 2:21:56 PM",
      "updatedAt": "4/20/2022, 2:21:56 PM",
      "trainerTips": [
        "Split the 21 thrusters as needed",
        "Try to do the 9 and 6 thrusters unbroken",
        "RX Weights: 115lb/75lb"
      ]
    },
    {
      "id": "4a3d9aaa-608c-49a7-a004-66305ad4ab50",
      "name": "Dead Push-Ups",
      "mode": "AMRAP 10",
      "equipment": [
        "barbell"
      ],
      "exercises": [
        "15 deadlifts",
        "15 hand-release push-ups"
      ],
      "createdAt": "1/25/2022, 1:15:44 PM",
      "updatedAt": "3/10/2022, 8:21:56 AM",
      "trainerTips": [
        "Deadlifts are meant to be light and fast",
        "Try to aim for unbroken sets",
        "RX Weights: 135lb/95lb"
      ]
    },
    {
      "id": "d8be2362-7b68-4ea4-a1f6-03f8bc4eede7",
      "name": "Heavy DT",
      "mode": "5 Rounds For Time",
      "equipment": [
        "barbell",
        "rope"
      ],
      "exercises": [
        "12 deadlifts",
        "9 hang power cleans",
        "6 push jerks"
      ],
      "createdAt": "11/20/2021, 5:39:07 PM",
      "updatedAt": "11/20/2021, 5:39:07 PM",
      "trainerTips": [
        "Aim for unbroken push jerks",
        "The first three rounds might feel terrible, but stick to it",
        "RX Weights: 205lb/145lb"
      ]
    }
  ]
}</code></pre><p>Come puoi vedere ci sono tre allenamenti inseriti. Un allenamento contiene i campi id, name, mode, equipment, exercises, createdAt, updatedAt, e trainerTips, (rispettivamente &nbsp;id, nome, modalità, equipaggiamenti, esercizi, creatoIl, aggiornatoIl e suggerimentiAllenatore - n.d.t.).</p><p>Partiamo con il più semplice e ritorniamo tutti gli allenamenti che sono stati salvati, poi iniziamo a implementare il metodo corrispondente all'interno del livello di accesso dati (<code>src/database/Workout.js</code>).</p><p>Ancora una volta, ho scelto di denominare il metodo qui con lo stesso nome di quello del servizio e del controller, ma è completamente opzionale.</p><pre><code class="language-javascript">// In src/database/Workout.js
const DB = require("./db.json");

const getAllWorkouts = () =&gt; {
  return DB.workouts;
};

module.exports = { getAllWorkouts };
</code></pre><p>Torniamo nuovamente al servizio nel file <code>workoutService.js</code> e implementiamo la logica per <code><strong>getAllWorkouts</strong></code>.</p><pre><code class="language-javascript">// In src/services/workoutService.js
// *** AGGIUNGI ***
const Workout = require("../database/Workout");
const getAllWorkouts = () =&gt; {
  // *** AGGIUNGI ***
  const allWorkouts = Workout.getAllWorkouts();
  // *** AGGIUNGI ***
  return allWorkouts;
};

const getOneWorkout = () =&gt; {
  return;
};

const createNewWorkout = () =&gt; {
  return;
};

const updateOneWorkout = () =&gt; {
  return;
};

const deleteOneWorkout = () =&gt; {
  return;
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Ritornare tutti gli allenamenti è piuttosto semplice e non dobbiamo fare trasformazioni in quanto è già un file JSON. Non dobbiamo neppure ricevere alcun argomento per ora. Quindi questa implementazione è piuttosto semplice, ma ci torneremo sopra in futuro.</p><p>Tornando al controller in <code>workoutControllers.js</code> riceviamo il valore di ritorno da <code>workoutService.getAllWorkouts()</code> e lo inviamo semplicemente al client. Abbiamo girato al controller la risposta dal database tramite il nostro servizio.</p><pre><code class="language-javascript">// In src/controllers/workoutControllers.js
const workoutService = require("../services/workoutService");

const getAllWorkouts = (req, res) =&gt; {
  const allWorkouts = workoutService.getAllWorkouts();
  // *** AGGIUNGI ***
  res.send({ status: "OK", data: allWorkouts });
};

const getOneWorkout = (req, res) =&gt; {
  const workout = workoutService.getOneWorkout();
  res.send("Get an existing workout");
};

const createNewWorkout = (req, res) =&gt; {
  const createdWorkout = workoutService.createNewWorkout();
  res.send("Create a new workout");
};

const updateOneWorkout = (req, res) =&gt; {
  const updatedWorkout = workoutService.updateOneWorkout();
  res.send("Update an existing workout");
};

const deleteOneWorkout = (req, res) =&gt; {
  workoutService.deleteOneWorkout();
  res.send("Delete an existing workout");
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Nel browser vai a <strong><strong>localhost:3000/api/v1/workouts</strong></strong> e dovresti vedere la risposta in formato JSON.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.38.14.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-11.38.14" width="600" height="400" loading="lazy"></figure><p>È andata alla grande! Rispondiamo con dati in formato JSON. E per quanto riguarda quello che accettiamo? Pensiamo a un endpoint dove riceviamo dati JSON dal client. L'endpoint per creare o aggiornare un allenamento necessita di dati dal client.</p><p>All'interno del controller estraiamo il corpo della richiesta per creare un nuovo allenamento e lo passiamo al servizio. All'interno del servizio lo inseriamo nel nostro <code>DB.json</code> e inviamo l'allenamento appena creato al client.</p><p>Per essere in grado di elaborare JSON inviato all'interno del corpo di una richiesta dobbiamo prima installare <strong><strong>body-parser</strong></strong> e configurarlo.</p><pre><code class="language-bash">npm i body-parser</code></pre><pre><code class="language-javascript">// In src/index.js 
const express = require("express");
// *** AGGIUNGI ***
const bodyParser = require("body-parser");
const v1WorkoutRouter = require("./v1/routes/workoutRoutes");

const app = express();
const PORT = process.env.PORT || 3000;

// *** AGGIUNGI ***
app.use(bodyParser.json());
app.use("/api/v1/workouts", v1WorkoutRouter);

app.listen(PORT, () =&gt; {
  console.log(`API is listening on port ${PORT}`);
});
</code></pre><p>Ora siamo in grado di ricevere dati in formato JSON all'interno del nostro controller in <strong><strong><code>req.body</code></strong></strong>.</p><p>Per eseguire un test appropriato, apriamo il nostro client HTTP preferito (io uso Postman), creiamo una richiesta POST a <strong>localhost:3000/api/v1/workouts</strong> e nel corpo della richiesta inseriamo in formato JSON quanto segue:</p><pre><code class="language-javascript">{
  "name": "Core Buster",
  "mode": "AMRAP 20",
  "equipment": [
    "rack",
    "barbell",
    "abmat"
  ],
  "exercises": [
    "15 toes to bars",
    "10 thrusters",
    "30 abmat sit-ups"
  ],
  "trainerTips": [
    "Split your toes to bars into two sets maximum",
    "Go unbroken on the thrusters",
    "Take the abmat sit-ups as a chance to normalize your breath"
  ]
}</code></pre><p>Come potresti aver notato, ci sono alcune proprietà mancanti come "id", "createdAt" e "updatedAt". È compito della nostra API aggiungere queste proprietà prima dell'inserimento. Ce ne occuperemo all'interno del servizio che gestisce gli allenamenti successivamente.</p><p>All'interno del metodo <strong><strong><code>createNewWorkout</code></strong></strong> nel controller, nel file <code>workoutController.js</code>, possiamo estrarre il corpo dall'oggetto request, effettuare qualche validazione e passarlo come argomento per il nostro servizio.</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
...

const createNewWorkout = (req, res) =&gt; {
  // *** AGGIUNGI ***
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    return;
  }
  // *** AGGIUNGI ***
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  // *** AGGIUNGI ***
  const createdWorkout = workoutService.createNewWorkout(newWorkout);
  // *** AGGIUNGI ***
  res.status(201).send({ status: "OK", data: createdWorkout });
};

...</code></pre><p>Per migliorare la validazione della richiesta in genere vorrai usare un pacchetto di terze parti come <a href="https://express-validator.github.io/docs/">express-validator</a>.</p><p>Passiamo al servizio che gestisce gli allenamenti e riceviamo i dati dal controller all'interno del metodo <code>createNewWorkout</code>.</p><p>Dopo avere aggiunto le proprietà mancanti all'oggetto, lo passiamo a un nuovo metodo nel nostro livello di accesso dati per conservarlo nel nostro DB.</p><p>Per prima cosa creiamo una semplice funzione di utilità che sovrascrive il nostro file JSON per salvare i nuovi dati.</p><pre><code class="language-bash"># Crea un file utils.js all'interno della directory database 
touch src/database/utils.js</code></pre><pre><code class="language-javascript">// In src/database/utils.js
const fs = require("fs");

const saveToDatabase = (DB) =&gt; {
  fs.writeFileSync("./db.json", JSON.stringify(DB, null, 2), {
    encoding: "utf-8",
  });
};

module.exports = { saveToDatabase };
</code></pre><p>Poi possiamo usare questa funzione nel nostro file Workout.js.</p><pre><code class="language-javascript">// In src/database/Workout.js
const DB = require("./db.json");
// *** AGGIUNGI ***
const { saveToDatabase } = require("./utils");


const getAllWorkouts = () =&gt; {
  return DB.workouts;
};

// *** AGGIUNGI ***
const createNewWorkout = (newWorkout) =&gt; {
  const isAlreadyAdded =
    DB.workouts.findIndex((workout) =&gt; workout.name === newWorkout.name) &gt; -1;
  if (isAlreadyAdded) {
    return;
  }
  DB.workouts.push(newWorkout);
  saveToDatabase(DB);
  return newWorkout;
};

module.exports = {
  getAllWorkouts,
  // *** AGGIUNGI ***
  createNewWorkout,
};
</code></pre><p>È andato tutto bene! Il passaggio successivo consiste nell'utilizzare i metodi del database all'interno del nostro servizio.</p><pre><code class="language-bash"># Installa il pacchetto uuid 
npm i uuid</code></pre><pre><code class="language-javascript">// In src/services/workoutService.js
// *** AGGIUNGI ***
const { v4: uuid } = require("uuid");
// *** AGGIUNGI ***
const Workout = require("../database/Workout");

const getAllWorkouts = () =&gt; {
    const allWorkouts = Workout.getAllWorkouts();
    return allWorkouts;
};

const getOneWorkout = () =&gt; {
  return;
};

const createNewWorkout = (newWorkout) =&gt; {
  // *** AGGIUNGI ***
  const workoutToInsert = {
    ...newWorkout,
    id: uuid(),
    createdAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  // *** AGGIUNGI ***
  const createdWorkout = Workout.createNewWorkout(workoutToInsert);
  return createdWorkout;
};

const updateOneWorkout = () =&gt; {
  return;
};

const deleteOneWorkout = () =&gt; {
  return;
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Wow! Divertente, non è vero? Ora puoi usare il tuo client HTTP e inviare la richiesta POST nuovamente, dovresti ricevere il nuovo allenamento creato in formato &nbsp;JSON.</p><p>Se provi ad aggiungere lo stesso allenamento nuovamente, riceverai un codice di stato 201, senza che l'allenamento venga inserito.</p><p>Questo significa che il nostro metodo di database per ora cancella gli inserimenti e non ritorna nulla. Infatti la nostra istruzione if verifica se un allenamento con lo stesso nome si trova già nel database. Per ora va bene così, gestiremo questa casistica nella nostra prossima miglior pratica!</p><p>Ora nel tuo browser invia una richiesta GET a <strong><strong>localhost:3000/api/v1/workouts</strong></strong> per ottenere tutti gli allenamenti. Dovresti vedere che il nostro allenamento è stato inserito e salvato con successo:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-11.57.23.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-11.57.23" width="600" height="400" loading="lazy"></figure><p>Puoi implementare gli altri metodi in autonomia oppure puoi semplicemente copiare le mia implementazioni.</p><p>Per primo il controller (puoi copiare semplicemente tutto il contenuto):</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
const workoutService = require("../services/workoutService");

const getAllWorkouts = (req, res) =&gt; {
  const allWorkouts = workoutService.getAllWorkouts();
  res.send({ status: "OK", data: allWorkouts });
};

const getOneWorkout = (req, res) =&gt; {
  const {
    params: { workoutId },
  } = req;
  if (!workoutId) {
    return;
  }
  const workout = workoutService.getOneWorkout(workoutId);
  res.send({ status: "OK", data: workout });
};

const createNewWorkout = (req, res) =&gt; {
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    return;
  }
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  const createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(201).send({ status: "OK", data: createdWorkout });
};

const updateOneWorkout = (req, res) =&gt; {
  const {
    body,
    params: { workoutId },
  } = req;
  if (!workoutId) {
    return;
  }
  const updatedWorkout = workoutService.updateOneWorkout(workoutId, body);
  res.send({ status: "OK", data: updatedWorkout });
};

const deleteOneWorkout = (req, res) =&gt; {
  const {
    params: { workoutId },
  } = req;
  if (!workoutId) {
    return;
  }
  workoutService.deleteOneWorkout(workoutId);
  res.status(204).send({ status: "OK" });
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Quindi il servizio (puoi copiare semplicemente tutto il contenuto):</p><pre><code class="language-javascript">// In src/services/workoutServices.js
const { v4: uuid } = require("uuid");
const Workout = require("../database/Workout");

const getAllWorkouts = () =&gt; {
  const allWorkouts = Workout.getAllWorkouts();
  return allWorkouts;
};

const getOneWorkout = (workoutId) =&gt; {
  const workout = Workout.getOneWorkout(workoutId);
  return workout;
};

const createNewWorkout = (newWorkout) =&gt; {
  const workoutToInsert = {
    ...newWorkout,
    id: uuid(),
    createdAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  const createdWorkout = Workout.createNewWorkout(workoutToInsert);
  return createdWorkout;
};

const updateOneWorkout = (workoutId, changes) =&gt; {
  const updatedWorkout = Workout.updateOneWorkout(workoutId, changes);
  return updatedWorkout;
};

const deleteOneWorkout = (workoutId) =&gt; {
  Workout.deleteOneWorkout(workoutId);
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Infine implementiamo i nostri metodi di database all'interno del livello di accesso dati (puoi copiare semplicemente tutto il contenuto):</p><pre><code class="language-javascript">// In src/database/Workout.js
const DB = require("./db.json");
const { saveToDatabase } = require("./utils");

const getAllWorkouts = () =&gt; {
  return DB.workouts;
};

const getOneWorkout = (workoutId) =&gt; {
  const workout = DB.workouts.find((workout) =&gt; workout.id === workoutId);
  if (!workout) {
    return;
  }
  return workout;
};

const createNewWorkout = (newWorkout) =&gt; {
  const isAlreadyAdded =
    DB.workouts.findIndex((workout) =&gt; workout.name === newWorkout.name) &gt; -1;
  if (isAlreadyAdded) {
    return;
  }
  DB.workouts.push(newWorkout);
  saveToDatabase(DB);
  return newWorkout;
};

const updateOneWorkout = (workoutId, changes) =&gt; {
  const indexForUpdate = DB.workouts.findIndex(
    (workout) =&gt; workout.id === workoutId
  );
  if (indexForUpdate === -1) {
    return;
  }
  const updatedWorkout = {
    ...DB.workouts[indexForUpdate],
    ...changes,
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  DB.workouts[indexForUpdate] = updatedWorkout;
  saveToDatabase(DB);
  return updatedWorkout;
};

const deleteOneWorkout = (workoutId) =&gt; {
  const indexForDeletion = DB.workouts.findIndex(
    (workout) =&gt; workout.id === workoutId
  );
  if (indexForDeletion === -1) {
    return;
  }
  DB.workouts.splice(indexForDeletion, 1);
  saveToDatabase(DB);
};

module.exports = {
  getAllWorkouts,
  createNewWorkout,
  getOneWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><p>Grande! Ora passiamo alla prossima miglior pratica e vediamo come possiamo gestire gli errori in modo appropriato.</p><h3 id="rispondere-con-codici-di-errore-standard-http"><strong><strong>R</strong>i<strong>spond</strong>ere con Codici di Errore Standard HTTP</strong></h3><p>Siamo già arrivati piuttosto lontano, ma non abbiamo ancora finito. La nostra API ha ora la capacità di gestire operazioni CRUD di base con conservazione dati. Grande, ma non l'ideale tuttavia.</p><p>Come mai? Fammi spiegare.</p><p>In un mondo perfetto va tutto liscio senza alcun errore. Ma come probabilmente saprai nel modo reale si possono verificare molti errori, da una prospettiva sia umana che tecnica.</p><p>Probabilmente potresti conoscere quella strana sensazione quando le cose funzionano bene fin dall'inizio senza errori. Questo è fantastico e divertente, ma come sviluppatori siamo più abituati a cose che non funzionano correttamente. 😁</p><p>Lo stesso vale per la nostra API. Dovremmo gestire quelle situazioni nelle quali le cose potrebbero andare male oppure generare un errore. Questo contribuirà a rendere la nostra API più robusta.</p><p>Quando qualcosa non va (sia nella richiesta che all'interno della nostra API) restituiamo un codice di errore HTTP. Ho visto e usato API che ritornavano sempre il codice di errore 400 quando una richiesta conteneva errori senza alcun messaggio specifico sul PERCHÉ &nbsp;questo errore si era verificato o quale fosse. Pertanto il debug diventava problematico.</p><p>Ecco la ragione per la quale è sempre buona pratica ritornare il codice di errore HTTP appropriato per ciascun caso. Questo aiuta l'utilizzatore o lo sviluppatore che ha creato l'API a identificare il problema più facilmente.</p><p>Per migliorare l'esperienza possiamo anche inviare un veloce messaggio di errore assieme al codice dell'errore con la risposta. Ma come ho scritto nell'introduzione, questo non è sempre saggio e dovrebbe essere deciso dal programmatore stesso.</p><p>Per esempio, ci si dovrebbe pensare bene prima di ritornare qualcosa come <strong><strong>"</strong>Questo username ha già effettuato il login<strong>"</strong></strong> in quanto si forniscono informazioni sui tuoi utenti che andrebbero tenute nascoste.</p><p>Nella nostra API Crossfit esaminiamo la creazione di un endpoint e vediamo quali errori potrebbero verificarsi e come gestirli. Alla fine di questa sezione troverai nuovamente l'implementazione completa per gli altri endpoint.</p><p>Iniziamo con il metodo <code>createNewWorkout</code> all'interno del controller:</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
...

const createNewWorkout = (req, res) =&gt; {
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    return;
  }
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  const createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(201).send({ status: "OK", data: createdWorkout });
};

...</code></pre><p>Abbiamo già intercettato il caso nel quale il corpo della richiesta non è composto correttamente e mancano chiavi che sono richieste.</p><p>Questo sarebbe un buon esempio per ritornare un errore HTTP 400 con un relativo messaggio di errore che (tradotto - n.d.t.) dice: "Una delle seguenti chiavi è mancante o vuota nel corpo della richiesta: 'name', 'mode', 'equipment', 'exercises', 'trainerTips".</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
...

const createNewWorkout = (req, res) =&gt; {
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: {
          error:
            "One of the following key is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'",
        },
      });
    return;
  }
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  const createdWorkout = workoutService.createNewWorkout(newWorkout);
  res.status(201).send({ status: "OK", data: createdWorkout });
};

...</code></pre><p>Se cerchi di aggiungere un nuovo allenamento ma dimentichi di passare la proprietà "mode" nel corpo della richiesta, dovresti vedere un messaggio di errore assieme al codice di errore HTTP 400.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.17.21.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-15.17.21" width="600" height="400" loading="lazy"></figure><p>Uno sviluppatore che utilizza l'API è ora meglio informato su cosa cercare. Saprà immediatamente di dover cercare all'interno del corpo della richiesta per verificare se non sia stata fornita una delle proprietà richieste.</p><p>Lasciare questo messaggio di errore più generico per tutte le proprietà per ora va bene. In genere dovresti usare un validatore di schema per gestire questo.</p><p>Andiamo a un livello più profondo nel nostro servizio workout e vediamo quali potenziali errori si potrebbero verificare.</p><pre><code class="language-javascript">// In src/services/workoutService.js
...

const createNewWorkout = (newWorkout) =&gt; {
  const workoutToInsert = {
    ...newWorkout,
    id: uuid(),
    createdAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  const createdWorkout = Workout.createNewWorkout(workoutToInsert);
  return createdWorkout;
};

...</code></pre><p>Una cosa che potrebbe andare male è l'inserimento nel database con il metodo <strong><strong><code>Workout.createNewWorkout()</code>. </strong></strong>Mi piace incapsulare questa parte di codice in un blocco &nbsp;try/catch per intercettare l'errore quando si verifica.</p><pre><code class="language-javascript">// In src/services/workoutService.js
...

const createNewWorkout = (newWorkout) =&gt; {
  const workoutToInsert = {
    ...newWorkout,
    id: uuid(),
    createdAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  try {
    const createdWorkout = Workout.createNewWorkout(workoutToInsert);
    return createdWorkout;
  } catch (error) {
    throw error;
  }
};

...</code></pre><p>Ogni errore che si verifica all'interno del metodo <code>Workout.createNewWorkout()</code> verrà catturato all'interno del blocco catch. Lo reiteriamo semplicemente, in modo da poter modellare le nostre risposte successivamente all'interno del nostro controller.</p><p>Definiamo i nostri errori in Workout.js:</p><pre><code class="language-javascript">// In src/database/Workout.js
...

const createNewWorkout = (newWorkout) =&gt; {
  const isAlreadyAdded =
    DB.workouts.findIndex((workout) =&gt; workout.name === newWorkout.name) &gt; -1;
  if (isAlreadyAdded) {
    throw {
      status: 400,
      message: `Workout with the name '${newWorkout.name}' already exists`,
    };
  }
  try {
    DB.workouts.push(newWorkout);
    saveToDatabase(DB);
    return newWorkout;
  } catch (error) {
    throw { status: 500, message: error?.message || error };
  }
};

...</code></pre><p>Come puoi vedere, un errore consiste di due parti, uno stato e un messaggio. Sto usando semplicemente la parola chiave <code><strong>throw</strong></code><strong> </strong>per ritornare una struttura dati diversa da una stringa, che è richiesta se usi <strong><strong><code>throw new Error()</code></strong></strong>.</p><p>Un piccolo svantaggio nell'inviare l'errore con <code>throw</code> è che non si ha uno <a href="https://it.wikipedia.org/wiki/Stack_trace">stack trace</a>. Normalmente questa generazione dell'errore dovrebbe essere gestita da una libreria di terze parti di nostra scelta (per esempio Mongoose se usi un database MongoDB). Per lo scopo di questo tutorial questo dovrebbe essere sufficiente.</p><p>Ora siamo in grado di generare e catturare gli errori nel servizio e nel livello di accesso dati. Possiamo passare ora al controller, catturare anche qui gli errori e rispondere di conseguenza.</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
...

const createNewWorkout = (req, res) =&gt; {
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: {
          error:
            "One of the following keys is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'",
        },
      });
    return;
  }
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  // *** ADD ***
  try {
    const createdWorkout = workoutService.createNewWorkout(newWorkout);
    res.status(201).send({ status: "OK", data: createdWorkout });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

...</code></pre><p>Puoi fare un test aggiungendo un allenamento con lo stesso nome due volte oppure non fornire una proprietà richiesta all'interno del corpo della tua richiesta. Dovresti ricevere i codici di errore HTTP corrispondenti, oltre ai messaggi di errore.</p><p>Per ricapitolare e passare al prossimo suggerimento, puoi copiare l'intera implementazione dei metodi nei seguenti file oppure puoi provare da solo:</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
const workoutService = require("../services/workoutService");

const getAllWorkouts = (req, res) =&gt; {
  try {
    const allWorkouts = workoutService.getAllWorkouts();
    res.send({ status: "OK", data: allWorkouts });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

const getOneWorkout = (req, res) =&gt; {
  const {
    params: { workoutId },
  } = req;
  if (!workoutId) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: { error: "Parameter ':workoutId' can not be empty" },
      });
  }
  try {
    const workout = workoutService.getOneWorkout(workoutId);
    res.send({ status: "OK", data: workout });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

const createNewWorkout = (req, res) =&gt; {
  const { body } = req;
  if (
    !body.name ||
    !body.mode ||
    !body.equipment ||
    !body.exercises ||
    !body.trainerTips
  ) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: {
          error:
            "One of the following keys is missing or is empty in request body: 'name', 'mode', 'equipment', 'exercises', 'trainerTips'",
        },
      });
    return;
  }
  const newWorkout = {
    name: body.name,
    mode: body.mode,
    equipment: body.equipment,
    exercises: body.exercises,
    trainerTips: body.trainerTips,
  };
  try {
    const createdWorkout = workoutService.createNewWorkout(newWorkout);
    res.status(201).send({ status: "OK", data: createdWorkout });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

const updateOneWorkout = (req, res) =&gt; {
  const {
    body,
    params: { workoutId },
  } = req;
  if (!workoutId) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: { error: "Parameter ':workoutId' can not be empty" },
      });
  }
  try {
    const updatedWorkout = workoutService.updateOneWorkout(workoutId, body);
    res.send({ status: "OK", data: updatedWorkout });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

const deleteOneWorkout = (req, res) =&gt; {
  const {
    params: { workoutId },
  } = req;
  if (!workoutId) {
    res
      .status(400)
      .send({
        status: "FAILED",
        data: { error: "Parameter ':workoutId' can not be empty" },
      });
  }
  try {
    workoutService.deleteOneWorkout(workoutId);
    res.status(204).send({ status: "OK" });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
  getRecordsForWorkout,
};
</code></pre><pre><code class="language-javascript">// In src/services/workoutService.js
const { v4: uuid } = require("uuid");
const Workout = require("../database/Workout");

const getAllWorkouts = () =&gt; {
  try {
    const allWorkouts = Workout.getAllWorkouts();
    return allWorkouts;
  } catch (error) {
    throw error;
  }
};

const getOneWorkout = (workoutId) =&gt; {
  try {
    const workout = Workout.getOneWorkout(workoutId);
    return workout;
  } catch (error) {
    throw error;
  }
};

const createNewWorkout = (newWorkout) =&gt; {
  const workoutToInsert = {
    ...newWorkout,
    id: uuid(),
    createdAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
  };
  try {
    const createdWorkout = Workout.createNewWorkout(workoutToInsert);
    return createdWorkout;
  } catch (error) {
    throw error;
  }
};

const updateOneWorkout = (workoutId, changes) =&gt; {
  try {
    const updatedWorkout = Workout.updateOneWorkout(workoutId, changes);
    return updatedWorkout;
  } catch (error) {
    throw error;
  }
};

const deleteOneWorkout = (workoutId) =&gt; {
  try {
    Workout.deleteOneWorkout(workoutId);
  } catch (error) {
    throw error;
  }
};

module.exports = {
  getAllWorkouts,
  getOneWorkout,
  createNewWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><pre><code class="language-javascript">// In src/database/Workout.js
const DB = require("./db.json");
const { saveToDatabase } = require("./utils");

const getAllWorkouts = () =&gt; {
  try {
    return DB.workouts;
  } catch (error) {
    throw { status: 500, message: error };
  }
};

const getOneWorkout = (workoutId) =&gt; {
  try {
    const workout = DB.workouts.find((workout) =&gt; workout.id === workoutId);
    if (!workout) {
      throw {
        status: 400,
        message: `Can't find workout with the id '${workoutId}'`,
      };
    }
    return workout;
  } catch (error) {
    throw { status: error?.status || 500, message: error?.message || error };
  }
};

const createNewWorkout = (newWorkout) =&gt; {
  try {
    const isAlreadyAdded =
      DB.workouts.findIndex((workout) =&gt; workout.name === newWorkout.name) &gt; -1;
    if (isAlreadyAdded) {
      throw {
        status: 400,
        message: `Workout with the name '${newWorkout.name}' already exists`,
      };
    }
    DB.workouts.push(newWorkout);
    saveToDatabase(DB);
    return newWorkout;
  } catch (error) {
    throw { status: error?.status || 500, message: error?.message || error };
  }
};

const updateOneWorkout = (workoutId, changes) =&gt; {
  try {
    const isAlreadyAdded =
      DB.workouts.findIndex((workout) =&gt; workout.name === changes.name) &gt; -1;
    if (isAlreadyAdded) {
      throw {
        status: 400,
        message: `Workout with the name '${changes.name}' already exists`,
      };
    }
    const indexForUpdate = DB.workouts.findIndex(
      (workout) =&gt; workout.id === workoutId
    );
    if (indexForUpdate === -1) {
      throw {
        status: 400,
        message: `Can't find workout with the id '${workoutId}'`,
      };
    }
    const updatedWorkout = {
      ...DB.workouts[indexForUpdate],
      ...changes,
      updatedAt: new Date().toLocaleString("en-US", { timeZone: "UTC" }),
    };
    DB.workouts[indexForUpdate] = updatedWorkout;
    saveToDatabase(DB);
    return updatedWorkout;
  } catch (error) {
    throw { status: error?.status || 500, message: error?.message || error };
  }
};

const deleteOneWorkout = (workoutId) =&gt; {
  try {
    const indexForDeletion = DB.workouts.findIndex(
      (workout) =&gt; workout.id === workoutId
    );
    if (indexForDeletion === -1) {
      throw {
        status: 400,
        message: `Can't find workout with the id '${workoutId}'`,
      };
    }
    DB.workouts.splice(indexForDeletion, 1);
    saveToDatabase(DB);
  } catch (error) {
    throw { status: error?.status || 500, message: error?.message || error };
  }
};

module.exports = {
  getAllWorkouts,
  createNewWorkout,
  getOneWorkout,
  updateOneWorkout,
  deleteOneWorkout,
};
</code></pre><h3 id="evitare-verbi-nei-nomi-degli-endpoint">Evitare verbi nei nomi degli endpoint</h3><p>Non ha molto senso usare verbi all'interno degli endpoint, in effetti è piuttosto inutile. Generalmente ogni URL dovrebbe puntare verso una risorsa (ricorda l'esempio della scatola fatto in precedenza). Niente di più e niente di meno.</p><p>Usare un verbo all'interno di un URL mostra un certo comportamento che la risorsa stessa non può avere.</p><p>Abbiamo già implementato gli endpoint correttamente senza usare verbi all'interno degli URL, tuttavia diamo un'occhiata a come sarebbero i nostri URL se avessimo usato i verbi.</p><pre><code class="language-javascript">// Implementazione corrente (senza verbi)
GET "/api/v1/workouts" 
GET "/api/v1/workouts/:workoutId" 
POST "/api/v1/workouts" 
PATCH "/api/v1/workouts/:workoutId" 
DELETE "/api/v1/workouts/:workoutId"  

// Implementazione usando verbi 
GET "/api/v1/getAllWorkouts" 
GET "/api/v1/getWorkoutById/:workoutId" 
CREATE "/api/v1/createWorkout" 
PATCH "/api/v1/updateWorkout/:workoutId" 
DELETE "/api/v1/deleteWorkout/:workoutId"</code></pre><p>Noti la differenza? Avere un URL completamente differente per ogni comportamento può generare confusione e inutile complessità piuttosto in fretta.</p><p>Immagina di avere 300 endpoint diversi. Usare un URL separato per ciascuno potrebbe essere un sovraccarico (compresa la documentazione) infernale.</p><p>Un'altra ragione che mi piacerebbe evidenziare per non usare verbi è che i verbi HTTP stessi indicano già l'azione (in lingua inglese - n.d.t.).</p><p>Cose come <strong><strong>"GET /api/v1/getAllWorkouts"</strong></strong> o <strong><strong>"DELETE api/v1/deleteWorkout/workoutId"</strong></strong> non sono necessarie.</p><p>Quando osservi la nostra implementazione corrente, diventa sempre più pulita in quanto stiamo usando solo due URL diversi e il comportamento effettivo è gestito tramite il verbo HTTP e il corrispondente <a href="https://it.wikipedia.org/wiki/Carico_utile_(informatica)">payload</a> della richiesta.</p><p>Ho sempre immaginato che il verbo HTTP descriva l'azione (quello che vorrei fare) e l'URL stesso (che punta verso una risorsa) l'obiettivo. <strong><strong>"GET /api/v1/workouts"</strong></strong> è anche più fluido come linguaggio umano (in inglese, naturalmente - n.d.t.).</p><!--kg-card-begin: markdown--><p><a name="raggruppare-risorse-associate"></a></p><h3>Raggruppare assieme le risorse (annidamento logico)</h3><p></p>
<!--kg-card-end: markdown--><p>Quando progetti la tua API, potrebbero esserci casi in cui disponi di risorse associate ad altre. È buona pratica raggrupparle in un unico endpoint e annidarle correttamente.</p><p>Considera che, nella nostra API, abbiamo anche un elenco di membri che si sono iscritti al nostro &nbsp;CrossFit box ("box" è il nome per una palestra CrossFit). Per motivare i nostri iscritti tracciamo i risultati complessivi dei box per ogni allenamento.</p><p>Ad esempio, c'è un allenamento in cui devi eseguire un certo ordine di esercizi il più rapidamente possibile. Registriamo i tempi per tutti i membri per avere un elenco del tempo impiegato per ogni membro che ha completato questo allenamento.</p><p>Ora, al frontend serve un endpoint che risponda con tutti i risultati per uno specifico allenamento affinché possa essere visualizzato nell'interfaccia utente.</p><p>Gli allenamenti, i membri e i risultati sono conservati in posti diversi nel database. Quindi quello che ci serve è una scatola (i risultati - records) all'interno di un'altra scatola (gli allenamenti - workout), giusto?</p><p>L'URI per quell'endpoint sarà <strong><strong>/api/v1/workouts/:workoutId/records</strong></strong>. Questa è una buona pratica che consente un annidamento logico dell'URL. L'URL stesso non deve necessariamente rispecchiare la struttura del database.</p><p>Iniziamo l'implementazione dell'endpoint.</p><p>Prima aggiungiamo una nuova tabella nel file &nbsp;<code>db.json</code> chiamata "members" (membri). &nbsp;La piazziamo sotto "workouts" (allenamenti).</p><pre><code class="language-json">{
  "workouts": [ ...
  ],
  "members": [
    {
      "id": "12a410bc-849f-4e7e-bfc8-4ef283ee4b19",
      "name": "Jason Miller",
      "gender": "male",
      "dateOfBirth": "23/04/1990",
      "email": "jason@mail.com",
      "password": "666349420ec497c1dc890c45179d44fb13220239325172af02d1fb6635922956"
    },
    {
      "id": "2b9130d4-47a7-4085-800e-0144f6a46059",
      "name": "Tiffany Brookston",
      "gender": "female",
      "dateOfBirth": "09/06/1996",
      "email": "tiffy@mail.com",
      "password": "8a1ea5669b749354110dcba3fac5546c16e6d0f73a37f35a84f6b0d7b3c22fcc"
    },
    {
      "id": "11817fb1-03a1-4b4a-8d27-854ac893cf41",
      "name": "Catrin Stevenson",
      "gender": "female",
      "dateOfBirth": "17/08/2001",
      "email": "catrin@mail.com",
      "password": "18eb2d6c5373c94c6d5d707650d02c3c06f33fac557c9cfb8cb1ee625a649ff3"
    },
    {
      "id": "6a89217b-7c28-4219-bd7f-af119c314159",
      "name": "Greg Bronson",
      "gender": "male",
      "dateOfBirth": "08/04/1993",
      "email": "greg@mail.com",
      "password": "a6dcde7eceb689142f21a1e30b5fdb868ec4cd25d5537d67ac7e8c7816b0e862"
    }
  ]
}</code></pre><p>Prima che tu me lo chieda, sì, alle password è stato applicato un hash. 😉</p><p>Successivamente aggiungiamo alcuni &nbsp;risultati ("records") sotto "members".</p><pre><code class="language-json">{
  "workouts": [ ...
  ],
  "members": [ ...
  ],
  "records": [
    {
      "id": "ad75d475-ac57-44f4-a02a-8f6def58ff56",
      "workout": "4a3d9aaa-608c-49a7-a004-66305ad4ab50",
      "record": "160 reps"
    },
    {
      "id": "0bff586f-2017-4526-9e52-fe3ea46d55ab",
      "workout": "d8be2362-7b68-4ea4-a1f6-03f8bc4eede7",
      "record": "7:23 minutes"
    },
    {
      "id": "365cc0bb-ba8f-41d3-bf82-83d041d38b82",
      "workout": "a24d2618-01d1-4682-9288-8de1343e53c7",
      "record": "358 reps"
    },
    {
      "id": "62251cfe-fdb6-4fa6-9a2d-c21be93ac78d",
      "workout": "4a3d9aaa-608c-49a7-a004-66305ad4ab50",
      "record": "145 reps"
    }
  ],
}</code></pre><p>Per essere sicuro che tu abbia gli stessi allenamenti con gli stessi miei identificativi, copia anche la sezione "workouts":</p><pre><code class="language-json">{
  "workouts": [
    {
      "id": "61dbae02-c147-4e28-863c-db7bd402b2d6",
      "name": "Tommy V",
      "mode": "For Time",
      "equipment": [
        "barbell",
        "rope"
      ],
      "exercises": [
        "21 thrusters",
        "12 rope climbs, 15 ft",
        "15 thrusters",
        "9 rope climbs, 15 ft",
        "9 thrusters",
        "6 rope climbs, 15 ft"
      ],
      "createdAt": "4/20/2022, 2:21:56 PM",
      "updatedAt": "4/20/2022, 2:21:56 PM",
      "trainerTips": [
        "Split the 21 thrusters as needed",
        "Try to do the 9 and 6 thrusters unbroken",
        "RX Weights: 115lb/75lb"
      ]
    },
    {
      "id": "4a3d9aaa-608c-49a7-a004-66305ad4ab50",
      "name": "Dead Push-Ups",
      "mode": "AMRAP 10",
      "equipment": [
        "barbell"
      ],
      "exercises": [
        "15 deadlifts",
        "15 hand-release push-ups"
      ],
      "createdAt": "1/25/2022, 1:15:44 PM",
      "updatedAt": "3/10/2022, 8:21:56 AM",
      "trainerTips": [
        "Deadlifts are meant to be light and fast",
        "Try to aim for unbroken sets",
        "RX Weights: 135lb/95lb"
      ]
    },
    {
      "id": "d8be2362-7b68-4ea4-a1f6-03f8bc4eede7",
      "name": "Heavy DT",
      "mode": "5 Rounds For Time",
      "equipment": [
        "barbell",
        "rope"
      ],
      "exercises": [
        "12 deadlifts",
        "9 hang power cleans",
        "6 push jerks"
      ],
      "createdAt": "11/20/2021, 5:39:07 PM",
      "updatedAt": "4/22/2022, 5:49:18 PM",
      "trainerTips": [
        "Aim for unbroken push jerks",
        "The first three rounds might feel terrible, but stick to it",
        "RX Weights: 205lb/145lb"
      ]
    },
    {
      "name": "Core Buster",
      "mode": "AMRAP 20",
      "equipment": [
        "rack",
        "barbell",
        "abmat"
      ],
      "exercises": [
        "15 toes to bars",
        "10 thrusters",
        "30 abmat sit-ups"
      ],
      "trainerTips": [
        "Split your toes to bars in two sets maximum",
        "Go unbroken on the thrusters",
        "Take the abmat sit-ups as a chance to normalize your breath"
      ],
      "id": "a24d2618-01d1-4682-9288-8de1343e53c7",
      "createdAt": "4/22/2022, 5:50:17 PM",
      "updatedAt": "4/22/2022, 5:50:17 PM"
    }
  ],
  "members": [ ...
  ],
  "records": [ ...
  ]
}</code></pre><p>Va bene, prendiamoci qualche minuto per pensare all'implementazione.</p><p>Abbiamo una risorsa chiamata "workouts" (gli allenamenti) da una parte e un'altra chiamata "records" (i risultati) dall'altra.</p><p>Per continuare nella nostra architettura sarebbe consigliabile creare un altro controller, un altro servizio e un'altra collezione di metodi di database che sono responsabili per i risultati.</p><p>È molto probabile che dobbiamo implementare gli endpoint CRUD anche per i risultati, perché anch'essi dovrebbero essere aggiunti, aggiornati o eliminati in futuro. Ma questo non sarà il compito principale per ora.</p><p>Avremo anche bisogno di un router per &nbsp;gestire le richieste specifiche per i risultati, ma non ne abbiamo bisogno al momento. Questa potrebbe essere una grande opportunità per te per implementare le operazioni CRUD per i record con le proprie rotte ed esercitarti un po'.</p><pre><code class="language-bash"># Crea il controller per i risultati
touch src/controllers/recordController.js 

# Crea il servizio per i risultati 
touch src/services/recordService.js 

# Crea i metodi del database per i risultati
touch src/database/Record.js</code></pre><p>Questo era facile. Passiamo oltre, partiamo dalla fine implementando i metodi del database.</p><pre><code class="language-javascript">// In src/database/Record.js
const DB = require("./db.json");

const getRecordForWorkout = (workoutId) =&gt; {
  try {
    const record = DB.records.filter((record) =&gt; record.workout === workoutId);
    if (!record) {
      throw {
        status: 400,
        message: `Can't find workout with the id '${workoutId}'`,
      };
    }
    return record;
  } catch (error) {
    throw { status: error?.status || 500, message: error?.message || error };
  }
};
module.exports = { getRecordForWorkout };
</code></pre><p>Piuttosto semplice, giusto? Filtriamo tutti i record che sono relativi all'allenamento il cui codice identificativo riceviamo come parametro di query.</p><p>Il prossimo è il servizio per i risultati:</p><pre><code class="language-javascript">// In src/services/recordService.js
const Record = require("../database/Record");

const getRecordForWorkout = (workoutId) =&gt; {
  try {
    const record = Record.getRecordForWorkout(workoutId);
    return record;
  } catch (error) {
    throw error;
  }
};
module.exports = { getRecordForWorkout };</code></pre><p>Anche qui niente di nuovo.</p><p>Ora siamo in grado di creare una nuova rotta nel router e dirigere la richiesta verso il servizio per i risultati.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
const express = require("express");
const workoutController = require("../../controllers/workoutController");
// *** AGGIUNGI ***
const recordController = require("../../controllers/recordController");

const router = express.Router();

router.get("/", workoutController.getAllWorkouts);

router.get("/:workoutId", workoutController.getOneWorkout);

// *** AGGIUNGI ***
router.get("/:workoutId/records", recordController.getRecordForWorkout);

router.post("/", workoutController.createNewWorkout);

router.patch("/:workoutId", workoutController.updateOneWorkout);

router.delete("/:workoutId", workoutController.deleteOneWorkout);

module.exports = router;
</code></pre><p>Grande! Facciamo un test con il browser.</p><p>Per prima cosa recuperiamo tutti gli allenamenti per ricavare l'id dell'allenamento.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.36.48.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-15.36.48" width="600" height="400" loading="lazy"></figure><p>Vediamo se possiamo recuperare tutti i record per quell'id:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.36.32.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-15.36.32" width="600" height="400" loading="lazy"></figure><p>Come puoi vedere, l'annidamento logico ha senso se hai risorse che possono essere in relazione tra loro. In teoria puoi annidare in profondità a piacimento, ma nella pratica è meglio non superare i tre livelli di annidamento al massimo.</p><p>Se vuoi annidare più in profondità, potresti fare una piccola modifica al database. Ti mostro un piccolo esempio.</p><p>Immagina che al frontend serva anche un endpoint per ottenere informazioni relative a quale membro esattamente detenga il record corrente e vuole ricevere metadati al proposito.</p><p>Naturalmente potremmo implementare l'URI seguente:</p><pre><code class="language-javascript">GET /api/v1/workouts/:workoutId/records/members/:memberId</code></pre><p>L'endpoint ora diventa meno gestibile mano a mano che aggiungiamo livelli di annidamento. Pertanto è buona pratica inserire l'URI per ricevere informazioni su un dato membro direttamente nel record.</p><p>Considera quanto segue all'interno del database:</p><pre><code class="language-json">{
  "workouts": [ ...
  ],
  "members": [ ...
  ],
  "records": [ ... {
      "id": "ad75d475-ac57-44f4-a02a-8f6def58ff56",
      "workout": "4a3d9aaa-608c-49a7-a004-66305ad4ab50",
      "record": "160 reps",
      "memberId": "11817fb1-03a1-4b4a-8d27-854ac893cf41",
      "member": "/members/:memberId"
    },
  ]
}</code></pre><p>Come puoi vedere abbiamo aggiunto due proprietà: "memberId" e "member" per i nostri record all'interno del database. Questo presenta il grosso vantaggio che non dobbiamo annidare più in profondità il nostro endpoint esistente.</p><p>Il frontend deve semplicemente chiamare <strong><strong>GET /api/v1/workouts/:workoutId/records </strong></strong>per ricevere automaticamente tutti i risultati che sono relativi a questo allenamento.</p><p>Inoltre ottiene l'id del membro e l'endpoint per recuperare le informazioni su quel membro. Quindi, abbiamo evitato l'annidamento più profondo del nostro endpoint.</p><p>Naturalmente, questo funziona solo se siamo in grado di gestire le richieste a "/members/:memberId" 😁 Sembra un'ottima opportunità di formazione per te per implementare questa situazione!</p><h3 id="integrare-filtri-ordinamento-e-paginazione"><strong><strong>Integra</strong>r<strong>e </strong>filtri, ordinamento e paginazione</strong></h3><p>In questo momento siamo in grado di eseguire alcune operazioni con la nostra API. Questo è un grande progresso, ma c'è di più.</p><p>Durante le ultime sezioni ci siamo concentrati sul miglioramento della nostra esperienza di sviluppatore e su come sia possibile interagire con la nostra API. Ma le prestazioni complessive della nostra API sono un altro fattore chiave su cui dovremmo lavorare.</p><p>Ecco perché anche l'integrazione di filtri, ordinamento e paginazione è un fattore essenziale nella mia lista.</p><p>Immagina di avere 2.000 allenamenti, 450 record e 500 membri memorizzati nel nostro database. Quando chiamiamo il nostro endpoint per ottenere tutti gli allenamenti, non vogliamo inviare tutti i 2.000 &nbsp;contemporaneamente. Questa sarà una risposta molto lenta ovviamente, o farà crollare i nostri sistemi (forse con 200.000 😁).</p><p>Questo è il motivo per cui il filtro e la paginazione sono importanti. Il filtro, come dice già il nome, è utile perché ci consente di ottenere dati specifici da tutta la nostra collezione. Ad esempio tutti gli allenamenti che hanno la modalità "For Time".</p><p>La paginazione è un altro meccanismo per suddividere la nostra intera raccolta di allenamenti in più "pagine" in cui ogni pagina è composta solo da venti allenamenti, ad esempio. Questa tecnica ci aiuta ad assicurarci di non inviare più di venti allenamenti contemporaneamente con la nostra risposta al client.</p><p>L'ordinamento può essere un compito complesso. Quindi è più efficace farlo nella nostra API e inviare i dati ordinati al client.</p><p>Cominciamo con l'integrazione di alcuni meccanismi di filtro nella nostra API. Miglioreremo il nostro endpoint che invia tutti gli allenamenti accettando parametri per il filtro. Normalmente in una richiesta GET aggiungiamo i criteri di filtro come parametro di query.</p><p>Il nostro nuovo URI sarà simile a questo, quando vorremmo ottenere solo gli allenamenti che sono nella modalità di "AMRAP" (As Many Rounds As Possible - tante ripetizioni quante possibile): <strong>/api/v1/workouts?mode=amrap</strong>.</p><p>Per renderlo più divertente dobbiamo aggiungere altri allenamenti. Incolla questi allenamenti nella tua raccolta "workouts" all'interno di db.json:</p><pre><code class="language-json">{
  "name": "Jumping (Not) Made Easy",
  "mode": "AMRAP 12",
  "equipment": [
    "jump rope"
  ],
  "exercises": [
    "10 burpees",
    "25 double-unders"
  ],
  "trainerTips": [
    "Scale to do 50 single-unders, if double-unders are too difficult"
  ],
  "id": "8f8318f8-b869-4e9d-bb78-88010193563a",
  "createdAt": "4/25/2022, 2:45:28 PM",
  "updatedAt": "4/25/2022, 2:45:28 PM"
},
{
  "name": "Burpee Meters",
  "mode": "3 Rounds For Time",
  "equipment": [
    "Row Erg"
  ],
  "exercises": [
    "Row 500 meters",
    "21 burpees",
    "Run 400 meters",
    "Rest 3 minutes"
  ],
  "trainerTips": [
    "Go hard",
    "Note your time after the first run",
    "Try to hold your pace"
  ],
  "id": "0a5948af-5185-4266-8c4b-818889657e9d",
  "createdAt": "4/25/2022, 2:48:53 PM",
  "updatedAt": "4/25/2022, 2:48:53 PM"
},
{
  "name": "Dumbbell Rower",
  "mode": "AMRAP 15",
  "equipment": [
    "Dumbbell"
  ],
  "exercises": [
    "15 dumbbell rows, left arm",
    "15 dumbbell rows, right arm",
    "50-ft handstand walk"
  ],
  "trainerTips": [
    "RX weights for women: 35-lb",
    "RX weights for men: 50-lb"
  ],
  "id": "3dc53bc8-27b8-4773-b85d-89f0a354d437",
  "createdAt": "4/25/2022, 2:56:03 PM",
  "updatedAt": "4/25/2022, 2:56:03 PM"
}</code></pre><p>Tutto quello che dobbiamo fare è accettare e gestire i parametri di query. Il nostro controller che gestisce gli allenamenti sarà il posto giusto da cui partire:</p><pre><code class="language-javascript">// In src/controllers/workoutController.js
...

const getAllWorkouts = (req, res) =&gt; {
  // *** ADD ***
  const { mode } = req.query;
  try {
    // *** ADD ***
    const allWorkouts = workoutService.getAllWorkouts({ mode });
    res.send({ status: "OK", data: allWorkouts });
  } catch (error) {
    res
      .status(error?.status || 500)
      .send({ status: "FAILED", data: { error: error?.message || error } });
  }
};

...</code></pre><p>Estraiamo &nbsp;"mode" dall'oggetto &nbsp;<code>req.query</code> e ne passiamo il valore a <code>workoutService.getAllWorkouts</code>. Questo valore sarà un oggetto che contiene tutti i parametri di filtro.</p><p>Uso la sintassi scorciatoia qui, per creare una chiave chiamata <code>mode</code> all'interno dell'oggetto, il cui valore è qualunque cosa sia associata a <code>req.query.mode</code>. Potrebbe essere sia un valore <em>truthy </em>oppure <code>undefined</code> se non esiste un parametro di query chiamato <code>mode</code>. Possiamo estendere questo oggetto con ulteriori parametri di filtro che vorremmo accettare.</p><p>Nel servizio workout, passalo al tuo metodo di database:</p><pre><code class="language-javascript">// In src/services/workoutService.js
...

const getAllWorkouts = (filterParams) =&gt; {
  try {
    // *** AGGIUNGI ***
    const allWorkouts = Workout.getAllWorkouts(filterParams);
    return allWorkouts;
  } catch (error) {
    throw error;
  }
};

...</code></pre><p>Ora possiamo usare il nostro metodo di database e applicare il filtro:</p><pre><code class="language-javascript">// In src/database/Workout.js
...

const getAllWorkouts = (filterParams) =&gt; {
  try {
    let workouts = DB.workouts;
    if (filterParams.mode) {
      return DB.workouts.filter((workout) =&gt;
        workout.mode.toLowerCase().includes(filterParams.mode)
      );
    }
    // Altre istruzioni if vanno qui per gestire parametri differenti
    return workouts;
  } catch (error) {
    throw { status: 500, message: error };
  }
};

...</code></pre><p>Piuttosto semplice, giusto? Tutto quello che dobbiamo fare qui è verificare se abbiamo effettivamente un valore <em>truthy</em> per la chiave <code>mode</code> all'interno di <code>filterParams</code>. Se questo è vero, filtriamo tutti gli allenamenti che hanno lo stesso valore per <code>mode</code>, altrimenti non c'è un parametro di query con quel nome e ritorniamo tutti gli allenamenti in quanto non è necessario filtrarli.</p><p>Abbiamo dichiarato la variabile <code>workouts</code> con <code>let</code> poiché quando aggiungiamo ulteriori istruzioni if per diversi filtri possiamo sovrascrivere <code>workouts</code> e concatenare i filtri.</p><p>All'interno del tuo browser puoi visitare <strong>localhost:3000/api/v1/workouts?mode=amrap</strong> e riceverai tutti gli allenamenti nel database che hanno la proprietà "<code>mode</code>" uguale a &nbsp;"AMRAP":</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-30-um-15.48.57.png" class="kg-image" alt="Bildschirmfoto-2022-04-30-um-15.48.57" width="600" height="400" loading="lazy"></figure><p>Se ometti il parametro di query, dovresti ottenere tutti gli allenamenti come prima. Puoi provare ancora aggiungendo "for%20time" come valore per il parametro <code>mode</code> (ricorda --&gt; "%20" significa "spazio") e ora dovresti ricevere tutti gli allenamenti che hanno il valore di <code>mode</code> uguale a "For Time", se esistono nel database.</p><p>Se digiti un valore che non è nel database, dovresti ricevere un array vuoto.</p><p>I parametri per ordinare e la paginazione seguono la stessa filosofia. Diamo un'occhiata ad alcune funzionalità che potremmo implementare:</p><ul><li>Ricevere tutti gli allenamenti che richiedono un barbell (bilanciere): <strong><strong>/api/v1/workouts?equipment=barbell</strong></strong></li><li>Ottenere solo 5 allenamenti: <strong><strong>/api/v1/workouts?length=5</strong></strong></li><li>Quando usiamo la paginazione ricevere la seconda pagina: <strong><strong>/api/v1/workouts?page=2</strong></strong></li><li>Ordinare gli allenamenti nella risposta in ordine discendente, per data di creazione: <strong><strong>/api/v1/workouts?sort=-createdAt</strong></strong></li><li>Puoi anche combinare i parametri, per ottenere gli ultimi 10 allenamenti aggiornati, per esempio: <strong><strong>/api/v1/workouts?sort=-updatedAt&amp;length=10</strong></strong></li></ul><h3 id="usare-cache-dei-dati-per-migliorare-le-prestazioni"><strong><strong>Us</strong>are cache dei dati per migliorare le prestazioni</strong></h3><p>Anche utilizzare una cache per i dati è una ottima pratica per migliorare l'esperienza complessiva e le prestazioni della nostra API.</p><p>Ha molto senso usare una cache dalla quale servire i dati, quando i dati provengono da una risorsa richiesta di frequente e/o quando l'interrogazione di quei dati dal database è un'operazione molto pesante e potrebbe richiedere più secondi.</p><p>Puoi conservare questo tipo di dati all'interno della tua cache e servirli da lì invece di interrogare ogni volta il database per ottenere i dati.</p><p>Una cosa importante che devi tenere a mente è che quando si servono dati da una cache, potrebbero essere diventati obsoleti. Quindi devi assicurarti che i dati all'interno della cache siano sempre aggiornati.</p><p>Ci sono molte soluzioni diverse a disposizione. Un esempio appropriato è usare <a href="https://www.npmjs.com/package/redis">redis</a> o il middleware di express <a href="https://www.npmjs.com/package/apicache">apicache</a>.</p><p>Preferirei usare apicache, ma se vuoi usare Redis, consiglio caldamente che tu dia un'occhiata alla loro ottima <a href="https://docs.redis.com/latest/rs/references/client_references/client_nodejs/">documentazione</a>.</p><p>Pensiamo un secondo a uno scenario nella nostra API nel quale una cache avrebbe senso. Penso che le richieste per ottenere tutti gli allenamenti potrebbero essere esaudite con efficacia all'interno della nostra cache.</p><p>Per prima cosa installiamo il nostro middleware:</p><pre><code class="language-bash">npm i apicache</code></pre><p>Ora dobbiamo importarlo nel router che gestisce gli allenamenti e configurarlo.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
const express = require("express");
// *** AGGIUNGI ***
const apicache = require("apicache");
const workoutController = require("../../controllers/workoutController");
const recordController = require("../../controllers/recordController");

const router = express.Router();
// *** AGGIUNGI ***
const cache = apicache.middleware;

// *** AGGIUNGI ***
router.get("/", cache("2 minutes"), workoutController.getAllWorkouts);

router.get("/:workoutId", workoutController.getOneWorkout);

router.get("/:workoutId/records", recordController.getRecordForWorkout);

router.post("/", workoutController.createNewWorkout);

router.patch("/:workoutId", workoutController.updateOneWorkout);

router.delete("/:workoutId", workoutController.deleteOneWorkout);

module.exports = router;
</code></pre><p>È piuttosto semplice impostarla, vero? Possiamo definire una nuova cache chiamando <strong><strong><code>apicache.middleware</code> </strong></strong>e usarla come middleware all'interno della nostra rotta GET. Devi solo inserirla come parametro tra il percorso effettivo e il controller che gestisce gli allenamenti.</p><p>Lì dentro puoi definire per quanto tempo i tuoi dati dovrebbero rimanere nella cache. Per le esigenze di questo tutorial ho scelto due minuti. Il tempo dipende dalla velocità o dalla frequenza con cui cambiano i dati all'interno della cache.</p><p>Ora proviamo!</p><p>All'interno di Postman o di un altro client HTTP di tua scelta, definisci una nuova richiesta che ottiene tutti gli allenamenti. Fino ad ora l'ho fatto dal browser, ma vorrei meglio visualizzare il tempo di risposta per te. Ecco la ragione per la quale ora sto richiedendo la risorsa tramite Postman.</p><p>Eseguiamo la nostra richiesta per la prima volta:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-26-um-15.36.46-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-26-um-15.36.46-1" width="600" height="400" loading="lazy"></figure><p>Come puoi vedere la nostra API ha risposto in 22.93 ms. Una volta che la nostra cache viene nuovamente svuotata (dopo due minuti) deve essere riempita nuovamente. Questo succede con la nostra prima richiesta.</p><p>Quindi nel caso qui sopra, i dati NON sono stati serviti dalla nostra cache. Sono stati presi &nbsp;"normalmente" dal database e sono stati inseriti nella cache.</p><p>Ora con la nostra seconda richiesta riceviamo i dati con un tempo di risposta minore, in quanto i dati sono serviti direttamente dalla cache:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-26-um-15.36.59-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-26-um-15.36.59-1" width="600" height="400" loading="lazy"></figure><p>Siamo stati in grado di servire i dati in un terzo del tempo impiegato nella nostra richiesta precedente! Tutto grazie alla nostra cache.</p><p>Nel nostro esempio abbiamo usato la cache con una sola rotta, ma puoi anche utilizzarla su tutte le rotte con un'implementazione come questa:</p><pre><code class="language-javascript">// In src/index.js
const express = require("express");
const bodyParser = require("body-parser");
// *** AGGIUNGI ***
const apicache = require("apicache");
const v1WorkoutRouter = require("./v1/routes/workoutRoutes");

const app = express();
// *** AGGIUNGI ***
const cache = apicache.middleware;
const PORT = process.env.PORT || 3000;

app.use(bodyParser.json());
// *** AGGIUNGI ***
app.use(cache("2 minutes"));
app.use("/api/v1/workouts", v1WorkoutRouter);

app.listen(PORT, () =&gt; {
  console.log(`API is listening on port ${PORT}`);
});
</code></pre><p>C'è una cosa <strong><strong>important</strong>e</strong> che vorrei far notare qui per quanto riguarda la cache. Anche se sembra che ti risolva molti problemi, puoi anche portarne altri alla tua applicazione.</p><p>Alcune cose delle quali devi essere a conoscenza quando utilizzi una cache:</p><ul><li>devi sempre assicurarti che i dati all'interno della cache siano aggiornati in quanto tu non vuoi servire dati obsoleti</li><li>quando la prima richiesta viene elaborata e la cache sta per essere riempita e ci sono ulteriori richieste in arrivo, devi decidere se ritardarle e servire i dati dalla cache oppure se esse riceveranno i dati direttamente dal database come nella prima richiesta</li><li>è un altro componente da inserire all'interno della tua infrastruttura, se stai scegliendo una cache distribuita come Redis (quindi devi domandarti se ha veramente senso usarla)</li></ul><p>Ecco cosa faccio io in genere:</p><p>Vorrei partire il più semplice e pulito possibile con qualsiasi cosa stia creando. Lo stesso vale per le API.</p><p>Quando inizio la creazione di un'API e non ci sono ragioni particolari per usare una cache immediatamente, la tengo da parte e vedo cosa succede nel tempo. Se si verificano ragioni per le quali usare una cache, la implemento.</p><h3 id="buone-pratiche-di-sicurezza"><strong>Buone pratiche di sicurezza</strong></h3><p>Wow! Questo è stato un bel viaggio finora. Abbiamo toccato molti punti importanti e abbiamo esteso la nostra API di conseguenza.</p><p>Abbiamo parlato delle migliori pratiche per accrescere l'usabilità e le prestazioni della nostra API. Anche la sicurezza è un fattore chiave per l'API. Puoi creare l'API migliore, ma quando si tratta di una parte di software vulnerabile in esecuzione in un server diventa inutile e pericolosa.</p><p>La prima indispensabile misura di sicurezza da includere è l'uso di SSL/TLS in quanto al giorno d'oggi è lo standard per quanto riguarda la comunicazione su internet. È ancora più importante dove i dati privati vengono scambiati tra il client e l'API.</p><p>Se hai risorse che dovrebbero essere disponibili solo a utenti autenticati, dovresti proteggerle con una verifica di autenticazione.</p><p>In Express, per esempio, puoi implementarla come middleware come abbiamo fatto per la nostra cache per determinate rotte e verificare prima se la richiesta è autenticata per accedere a una risorsa.</p><p>Potrebbero esserci risorse o interazioni con la nostra API che non vogliamo vengano richieste da qualunque utente. In questo caso dovresti impostare un sistema di ruoli per i tuoi utenti. Pertanto devi aggiungere altra logica di verifica per quella rotta e validare se l'utente ha il privilegio di accedere alla risorsa.</p><p>I ruoli utenti avrebbero senso anche nel nostro caso d'uso quando vogliamo che solo utenti specifici (come gli allenatori) possano creare, aggiornare ed eliminare gli allenamenti e i risultati. La lettura può essere aperta a tutti (anche ai membri "normali").</p><p>Si può gestire la cosa tramite un altro middleware che usiamo per le rotte che vogliamo proteggere. Per esempio la nostra richiesta POST per <strong>/api/v1/workouts</strong> per creare un nuovo allenamento.</p><p>All'interno del primo middleware verificheremo se l'utente è autenticato. In caso positivo passeremo al middleware successivo, vale a dire la verifica del ruolo dell'utente. Se l'utente ha il ruolo appropriato per accedere alla risorsa la richiesta viene passata al controller corrispondente.</p><p>All'interno del gestore delle rotte il codice sarà come questo:</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
...

// Middleware personalizzato
const authenticate = require("../../middlewares/authenticate");
const authorize = require("../../middlewares/authorize");

router.post("/", authenticate, authorize, workoutController.createNewWorkout);

...</code></pre><p>Per ulteriori informazioni e migliori pratiche su questo argomento, suggerisco di leggere <a href="https://restfulapi.net/security-essentials/">questo articolo</a> (in lingua inglese).</p><h3 id="documentare-correttamente-la-tua-api"><strong><strong>Document</strong>are correttamente la tua<strong> API</strong></strong></h3><p>So che la documentazione non è esattamente l'attività preferita dagli sviluppatori, ma è una cosa necessaria da fare. Specialmente quando si parla di API.</p><p>Qualcuno dice che:</p><blockquote>"Un'API è tanto buona quanto la sua documentazione"</blockquote><p>Credo che ci sia molto di vero in questa affermazione in quanto se un'API non è ben documentata non può essere usata adeguatamente, pertanto diventa inutile. La documentazione aiuta anche a rendere la vita degli sviluppatori molto più facile.</p><p>Ricorda sempre che la documentazione in genere è la prima interazione che gli utilizzatori hanno con la tua API. Più velocemente gli utenti saranno in grado di capire la documentazione, più velocemente potranno usare la tua API.</p><p>Pertanto è nostro compito implementare una documentazione esauriente e precisa. Ci sono degli ottimi strumenti a disposizione che ci faciliteranno la vita.</p><p>Come in altri campi dell'informatica, c'è una sorta di standard per documentare le API chiamata <a href="https://swagger.io/specification/">OpenAPI Specification</a> (Specifiche OpenAPI).</p><p>Vediamo come possiamo creare una qualche documentazione che giustifichi quelle specifiche. Useremo i pacchetti <a href="https://www.npmjs.com/package/swagger-ui-express">swagger-ui-express</a> e <a href="https://www.npmjs.com/package/swagger-jsdoc">swagger-jsdoc</a> per farlo. In un attimo resterai stupito di quanto sia fantastico!</p><p>Innanzitutto, impostiamo la struttura base per la nostra documentazione. Poiché abbiamo pianificato di avere diverse versioni della nostra API, anche i documenti saranno leggermente diversi. Questo è il motivo per cui vorrei definire il nostro file swagger per lanciare la nostra documentazione all'interno della cartella della versione corrispondente.</p><pre><code class="language-bash"># Installa i pacchetti npm richiesti 
npm i swagger-jsdoc swagger-ui-express 

# Crea un nuovo file per impostare i documenti swagger 
touch src/v1/swagger.js</code></pre><pre><code class="language-javascript">// In src/v1/swagger.js
const swaggerJSDoc = require("swagger-jsdoc");
const swaggerUi = require("swagger-ui-express");

// Meta Informazioni base sulla nostra API
const options = {
  definition: {
    openapi: "3.0.0",
    info: { title: "Crossfit WOD API", version: "1.0.0" },
  },
  apis: ["./src/v1/routes/workoutRoutes.js", "./src/database/Workout.js"],
};

// Documentazione in formato JSON
const swaggerSpec = swaggerJSDoc(options);

// Funzione per impostare la nostra documentazione
const swaggerDocs = (app, port) =&gt; {
  // Gestore della rotta per visitare la documentazione
  app.use("/api/v1/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));
  // Rendiamo disponibile la nostra documentazione in formato JSON
  app.get("/api/v1/docs.json", (req, res) =&gt; {
    res.setHeader("Content-Type", "application/json");
    res.send(swaggerSpec);
  });
  console.log(
    `Version 1 Docs are available on http://localhost:${port}/api/v1/docs`
  );
};

module.exports = { swaggerDocs };
</code></pre><p>L'impostazione è piuttosto semplice. Abbiamo definito qualche metadato base per la nostra API, creata la documentazione in formato JSON e creata una funzione che rende disponibile la nostra documentazione.</p><p>Per controllare se tutto è a posto e in esecuzione, registriamo un semplice messaggio alla console che indica dove possiamo trovare la documentazione.</p><p>Questa sarà la funzione che useremo nel file radice (index.js) dove abbiamo creato il server Express per assicurarci che anche la documentazione sia caricata.</p><pre><code class="language-javascript">// In src/index.js
const express = require("express");
const bodyParser = require("body-parser");
const v1WorkoutRouter = require("./v1/routes/workoutRoutes");
// *** AGGIUNGI ***
const { swaggerDocs: V1SwaggerDocs } = require("./v1/swagger");

const app = express();
const PORT = process.env.PORT || 3000;

app.use(bodyParser.json());
app.use("/api/v1/workouts", v1WorkoutRouter);

app.listen(PORT, () =&gt; {
  console.log(`API is listening on port ${PORT}`);
  /// *** AGGIUNGI ***
  V1SwaggerDocs(app, PORT);
});
</code></pre><p>Ora dovresti vedere quanto segue all'interno del terminale dove è in esecuzione il tuo server di sviluppo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-28-um-20.23.51-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-28-um-20.23.51-1" width="600" height="400" loading="lazy"></figure><p>Quando visiti &nbsp;<strong>localhost:3000/api/v1/docs </strong>nel browser, dovresti già vedere la nostra pagina di documentazione:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-28-um-20.25.00-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-28-um-20.25.00-1" width="600" height="400" loading="lazy"></figure><p>Ogni volta mi stupisco di quanto funzioni bene. Ora, la struttura di base è configurata e possiamo iniziare a implementare la documentazione per i nostri endpoint. Andiamo!</p><p>Quando dai un'occhiata al contenuto della chiave <strong><strong>options.apis</strong></strong> nel file <code>swagger.js</code>, vedrai che abbiamo incluso il percorso alle nostre rotte per l'allenamento e per il file degli allenamenti all'interno della cartella database. Questa è la cosa più importante da impostare per fare in modo che la magia si verifichi.</p><p>Avendo definito questi file all'interno delle opzioni swagger ci consente di usare commenti che fanno riferimento a OpenAPI e ad avere la sintassi come nei file <a href="https://it.wikipedia.org/wiki/YAML">yaml</a>, necessaria per l'impostazione della nostra documentazione.</p><p>Ora siamo pronti a creare la documentazione per il nostro primo endpoint! Facciamolo subito.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
...

/**
 * @openapi
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     type: object
 */
router.get("/", cache("2 minutes"), workoutController.getAllWorkouts);

...</code></pre><p>Questo è praticamente quanto serve per aggiungere un endpoint alla nostra documentazione swagger. Puoi vedere tutte le specifiche per descrivere un endpoint nella loro <a href="https://swagger.io/docs/specification/about/">ottima documentazione</a>.</p><p>Quando ricarichi la tua pagina di documentazione dovresti vedere quanto segue:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.21.51-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-07.21.51-1" width="600" height="400" loading="lazy"></figure><p>Questo dovrebbe esserti piuttosto familiare se hai già lavorato con API che hanno una documentazione secondo le specifiche OpenAPI. Questa è la vista dove sono elencati tutti gli endpoint e puoi estendere ciascuno di essi per ottenere maggiori informazioni.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.41.46-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-07.41.46-1" width="600" height="400" loading="lazy"></figure><p>Se osservi attentamente la nostra risposta, vedrai che non abbiamo definito il corretto valore di ritorno perché stiamo semplicemente dicendo che la nostra proprietà "data" sarà un array di oggetti vuoti.</p><p>Ecco quando entrano in gioco gli schemi.</p><pre><code class="language-javascript">// In src/databse/Workout.js
...

/**
 * @openapi
 * components:
 *   schemas:
 *     Workout:
 *       type: object
 *       properties:
 *         id: 
 *           type: string
 *           example: 61dbae02-c147-4e28-863c-db7bd402b2d6
 *         name: 
 *           type: string
 *           example: Tommy V  
 *         mode:
 *           type: string
 *           example: For Time
 *         equipment:
 *           type: array
 *           items:
 *             type: string
 *           example: ["barbell", "rope"]
 *         exercises:
 *           type: array
 *           items:
 *             type: string
 *           example: ["21 thrusters", "12 rope climbs, 15 ft", "15 thrusters", "9 rope climbs, 15 ft", "9 thrusters", "6 rope climbs, 15 ft"]
 *         createdAt:
 *           type: string
 *           example: 4/20/2022, 2:21:56 PM
 *         updatedAt: 
 *           type: string
 *           example: 4/20/2022, 2:21:56 PM
 *         trainerTips:
 *           type: array
 *           items:
 *             type: string
 *           example: ["Split the 21 thrusters as needed", "Try to do the 9 and 6 thrusters unbroken", "RX Weights: 115lb/75lb"]
 */

...</code></pre><p>Nell'esempio qui sopra abbiamo creato il nostro primo schema. Tipicamente questa definizione sarà all'interno del nostro file schema o modello dove hai definito i modelli del database.</p><p>Come puoi vedere è piuttosto semplice. Abbiamo definito tutte le proprietà che compongono un allenamento incluso il tipo e un esempio.</p><p>Puoi visitare la nostra pagina di documentazione nuovamente e riceverai un'altra sezione che contiene gli schemi.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.29.49-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-07.29.49-1" width="600" height="400" loading="lazy"></figure><p>Questo schema può ora essere referenziato nella risposta del nostro endpoint.</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
...

/**
 * @openapi
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     $ref: "#/components/schemas/Workout"
 */
router.get("/", cache("2 minutes"), workoutController.getAllWorkouts);

...</code></pre><p>Guarda attentamente al fondo della riga di commento sotto "items". Stiamo usando "$ref" per creare un riferimento e stiamo referenziando il percorso del nostro schema che abbiamo definito all'interno del file degli allenamenti.</p><p>Ora siamo in grado di mostrare un allenamento completo nella nostra risposta.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-07.44.12-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-07.44.12-1" width="600" height="400" loading="lazy"></figure><p>Abbastanza bello, vero? Potresti pensare che "digitare questi commenti a mano può essere un compito noioso".</p><p>Questo potrebbe essere vero, ma pensala in questo modo. Quei commenti che si trovano all'interno del tuo codice sono anche un'ottima documentazione per te stesso come sviluppatore dell'API. Non è necessario consultare sempre la documentazione quando si desidera conoscere le informazioni su un endpoint specifico. Puoi semplicemente cercarlo in un posto all'interno del tuo codice sorgente.</p><p>La documentazione degli endpoint ti aiuta anche a comprenderli meglio e ti "costringe" a pensare a qualsiasi cosa che potresti aver dimenticato di implementare.</p><p>Come vedi ho dimenticato davvero qualcosa. Mancano ancora le possibili risposte di errore e i parametri di query!</p><p>Risolviamolo:</p><pre><code class="language-javascript">// In src/v1/routes/workoutRoutes.js
...

/**
 * @openapi
 * /api/v1/workouts:
 *   get:
 *     tags:
 *       - Workouts
 *     parameters:
 *       - in: query
 *         name: mode
 *         schema:
 *           type: string
 *         description: The mode of a workout
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status:
 *                   type: string
 *                   example: OK
 *                 data:
 *                   type: array 
 *                   items: 
 *                     $ref: "#/components/schemas/Workout"
 *       5XX:
 *         description: FAILED
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 status: 
 *                   type: string
 *                   example: FAILED
 *                 data:
 *                   type: object
 *                   properties:
 *                     error:
 *                       type: string 
 *                       example: "Some error message"
 */
router.get("/", cache("2 minutes"),  workoutController.getAllWorkouts);

...</code></pre><p>Quando guardi la parte superiore del nostro commento sotto "tags", puoi vedere che ho aggiunto un'altra chiave chiamata "parameters", dove ho definito il nostro parametro di ricerca per il filtro.</p><p>La nostra documentazione ora lo visualizza correttamente:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-08.03.00-1.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-08.03.00-1" width="600" height="400" loading="lazy"></figure><p>Per documentare un possibile caso di errore, a questo punto stiamo generando solo un errore 5XX. Quindi sotto "responses" puoi vedere che ho anche definito un'altra documentazione per questo..</p><p>La nostra pagina di documentazione ora è come questa:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/04/Bildschirmfoto-2022-04-29-um-08.04.44-2.png" class="kg-image" alt="Bildschirmfoto-2022-04-29-um-08.04.44-2" width="600" height="400" loading="lazy"></figure><p>Fantastico! Abbiamo appena creato la documentazione completa per un endpoint. Ti consiglio vivamente di implementare il resto degli endpoint da solo per acquisire pratica. Imparerai molto mentre lo fai!</p><p>Come potresti aver visto, documentare la tua API non deve essere sempre un mal di testa. Penso che gli strumenti che ti ho presentato riducano il tuo sforzo complessivo e impostare tutto sia piuttosto semplice.</p><p>Quindi possiamo concentrarci sulla cosa importante, la documentazione stessa. A mio parere, la documentazione di swagger/OpenAPI è molto buona e ci sono molti ottimi esempi su internet.</p><p>Non avere una documentazione a causa del troppo lavoro "extra" non dovrebbe più essere una scusa.</p><h2 id="conclusione"><strong><strong>Conclusion</strong>e</strong></h2><p>Finalmente, è stata una corsa piuttosto divertente. Mi è davvero piaciuto scrivere questo articolo per te e ho anche imparato molto.</p><p>Potrebbero esserci migliori pratiche che sono importanti mentre altre potrebbero non essere applicabili alla tua situazione attuale. Va bene, perché come ho detto prima, è responsabilità di ogni sviluppatore scegliere le migliori pratiche che possono essere applicate alla propria situazione attuale.</p><p>Ho fatto del mio meglio per mettere insieme tutte quelle che ho attuato fino ad ora creando la nostra API lungo il percorso. Mi sono davvero divertito!</p><p>Mi piacerebbe ricevere un feedback di qualsiasi tipo. Se c'è qualcosa che vorresti dirmi (buona o cattiva), non esitare a contattarmi:</p><p>Ecco il mio <a href="https://www.instagram.com/jean_marc.dev/">Instagram</a> (puoi anche seguire il mio percorso di sviluppatore di software)</p><p>Ci vediamo alla prossima!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Programmazione Orientata agli Oggetti in C++ ]]>
                </title>
                <description>
                    <![CDATA[ La programmazione orientata agli oggetti, in breve OOP (Object Orienting Programming), mira a implementare entità del mondo reale come ereditarietà, incapsulamento e polimorfismo nella programmazione. Lo scopo principale della OOP è di tenere insieme dati e funzioni che operano su di essi in modo che nessuna altra parte di codice ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/programmazione-orientata-agli-oggetti-in-c/</link>
                <guid isPermaLink="false">6474b9241647bb059b5416bc</guid>
                
                    <category>
                        <![CDATA[ C++ ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Tue, 27 Jun 2023 09:18:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/05/5f9c9e69740569d1a4ca3cf0.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/object-oriented-programming-in-c/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Object Oriented Programming in C++</a>
      </p><p>La programmazione orientata agli oggetti, in breve OOP (Object Orienting Programming), mira a implementare entità del mondo reale come ereditarietà, incapsulamento e polimorfismo nella programmazione.</p><p>Lo scopo principale della OOP è di tenere insieme dati e funzioni che operano su di essi in modo che nessuna altra parte di codice possa accedere a tali dati eccetto queste funzioni.</p><p>Impareremo le diverse caratteristiche della programmazione orientata agli oggetti in linguaggio C++.</p><h3 id="oggetto"><strong>Oggetto</strong></h3><p>Gli oggetti costituiscono le entità base nella fase di esecuzione in un sistema orientato agli oggetti. Gli oggetti sono istanze di una classe, che è un tipo di dato definito dall'utente.</p><pre><code class="language-c++">class person
{
    char name[20];
    int id;
public:
    void getdetails(){}
};
 
int main()
{
   person p1; //p1 è un oggetto 
}</code></pre><p>Gli oggetti occupano spazio in memoria e hanno un indirizzo associato come un record in pascal o una struttura o union in C.</p><p>Quando un programma viene eseguito, gli oggetti interagiscono scambiandosi messaggi.</p><p>Ciascun oggetto contiene dei dati e del codice per manipolarli. Gli oggetti possono interagire senza aver bisogno di conoscere i dettagli o il codice di ciascun altro. È sufficiente sapere quale tipo di messaggio viene accettato e il tipo di risposta ritornata dagli oggetti.</p><h3 id="classe"><strong><strong><strong><strong>Class</strong></strong></strong>e</strong></h3><p>Una classe è un modello che rappresenta dati e funzioni o metodi. Una classe non occupa spazio.</p><pre><code class="language-c++">class nome_classe
{
  private:
     //dichiarazione di dati e funzioni membro
  public:
     //dichiarazione di dati e funzioni membro
  protected:
     //dichiarazione di dati e funzioni membro	
};</code></pre><p>Una classe è un tipo di dato definito dall'utente come le strutture e le union in C.</p><p>Nella modalità predefinita, le variabili nella classe sono private, ma in caso di struttura sono pubbliche, nell'esempio più sopra <code>person</code> è una classe.</p><h3 id="incapsulamento-e-astrazione-dati"><strong>Incapsulamento e Astrazione Dati</strong></h3><p>Tenere insieme (combinare) dati e funzioni in una singola unità è noto come incapsulamento. I dati non sono accessibili direttamente dal mondo esterno, ma solo tramite i metodi e le proprietà esposti dalla classe. Questo isolamento dei dati dall'accesso diretto da un programma viene detto occultamento di dati oppure occultamento di informazioni.</p><p>Per astrazione dati ci si riferisce al fatto che vengono fornite solo le informazioni necessarie al mondo esterno e vengono nascosti i dettagli dell'implementazione.</p><p>Per esempio considera una classe <code>Complex</code> che contenga le funzioni pubbliche <code>getReal()</code> e <code>getImag()</code>. Possiamo implementare la classe come un array di due elementi oppure come due variabili.</p><p>Il vantaggio dell'astrazione è che possiamo modificare l'implementazione in qualsiasi momento e gli utenti della classe <code>Complex</code> non saranno interessati visto che l'interfaccia dei nostri metodi rimane la stessa. Se l'implementazione fosse stata pubblica, non saremmo stati in grado di modificarla.</p><h3 id="ereditariet-"><strong>Ereditarietà</strong></h3><p>L'ereditarietà è il processo per il quale oggetti di una classe acquisiscono le proprietà di oggetti di un un'altra classe. Supporta il concetto di classificazione gerarchica.</p><p>L'ereditarietà fornisce riusabilità. Il che vuol dire che possiamo aggiungere caratteristiche a una classe esistente senza modificarla.</p><h3 id="polimorfismo"><strong><strong><strong><strong>Pol</strong></strong></strong>i<strong><strong><strong>mor</strong></strong></strong>f<strong><strong><strong>ism</strong></strong></strong>o</strong></h3><p>Il polimorfismo fa riferimento alla capacità di assumere più di una forma. Un'operazione potrebbe manifestare comportamenti diversi per istanze diverse. Il comportamento dipende dai tipi di dato usati nell'operazione.</p><p>C++ supporta il sovraccarico dell'operatore e della funzione. Il sovraccarico dell'operatore consiste nel fare in modo che un operatore assuma comportamenti diversi in istanze diverse. Il sovraccarico della funzione consiste nell'usare un singolo nome di funzione per eseguire tipi di compito differenti. Il polimorfismo è usato estensivamente nell'implementazione dell'ereditarietà.</p><h3 id="collegamento-dinamico"><strong>Collegamento Dinamico</strong></h3><p>Nel collegamento dinamico, il codice che deve essere eseguito in risposta alla chiamata di una funzione viene deciso in fase di esecuzione. &nbsp;C++ ha le funzioni virtuali che supportano questo.</p><h3 id="passaggio-di-messaggi"><strong>Passaggio di messaggi</strong></h3><p>Gli oggetti comunicano tra loro inviando e ricevendo informazioni da ciascun altro. Un messaggio per un oggetto è la richiesta che una certa procedura venga eseguita, pertanto verrà invocata una funzione nell'oggetto ricevente che genera i risultati attesi.</p><p>Il passaggio di messaggi implica l0 specificare il nome dell'oggetto, il nome della funzione e l'informazione da inviare.</p><h2 id="altre-risorse"><strong>Altre risorse</strong></h2><p><a href="https://www.freecodecamp.org/news/object-oriented-concepts/">Object Oriented Programming Concepts: How to go from Zero to One with Objects</a></p><p><a href="https://www.freecodecamp.org/italian/news/come-spiegare-concetti-di-programmazione-orientata-agli-oggetti-a-un-bambino-di-6-anni/">Come spiegare concetti di programmazione orientata agli oggetti a un bambino di 6 anni</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tipi di Dato in C - Interi, Virgola Mobile e Void Spiegati ]]>
                </title>
                <description>
                    <![CDATA[ Tipi di Dato in C Ci sono parecchi modi per conservare dati in C, e sono tutti diversi l'uno dall'altro. I tipi di dato in cui le informazioni possono essere archiviate sono chiamati "data types". C perdona molto meno rispetto ad altri linguaggi per quanto riguarda i tipi di dato. ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/tipi-di-dato-in-c-interi-virgola-mobile-e-void-spiegati/</link>
                <guid isPermaLink="false">6470595cd35921064af70aa2</guid>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Wed, 21 Jun 2023 05:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/05/5f9c9cf3740569d1a4ca3517.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/data-types-in-c-integer-floating-point-and-void-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Data Types in C - Integer, Floating Point, and Void Explained</a>
      </p><h2 id="tipi-di-dato-in-c"><strong>Tipi di Dato in C</strong></h2><p>Ci sono parecchi modi per conservare dati in C, e sono tutti diversi l'uno dall'altro. I tipi di dato in cui le informazioni possono essere archiviate sono chiamati "data types". C perdona molto meno rispetto ad altri linguaggi per quanto riguarda i tipi di dato. Ne consegue che è importante comprendere i tipi di dato esistenti, le loro capacità e i loro limiti.</p><p>Una stranezza dei tipi di dato in C è che dipendono interamente dall'hardware sul quale stai eseguendo il codice. Un <code>int</code> nel tuo laptop sarà più piccolo rispetto a un <code>int</code> in un supercomputer, quindi conoscere i limiti dell'hardware sul quale stai lavorando è importante. Questa è anche la ragione per la quale i tipi di dato sono definiti con valori limite minimi e massimi - un valore <code>int</code>, come imparerai, potrà contenere valori da &nbsp;-32767 a 32767; su certe macchine sarà però in grado di conservare valori anche eccedenti.</p><p>Ci sono due categorie in cui possiamo suddividere valori numerici: interi (integers) e in virgola mobile (floating points numbers). Gli interi sono numeri interi. Possono essere positivi, negativi oppure zero. Numeri come -321, 497, 19345, e -976812 sono tutti perfettamente validi, mentre 4.5 non lo è perché non è un numero intero.</p><p>I numeri in virgola mobile sono numeri con decimali. Comprendono anche i numeri interi, -321, 497, 19345, e -976812 che sono tutti validi, ma anche 4,5, 0,0004, -324,984, e altri numeri non interi sono validi.</p><p>C ci consente di scegliere tra parecchie opzioni per i nostri tipi di dato in quanto sono tutti conservati nel computer in modi diversi. Ne consegue che è importante conoscere limiti e capacità di ciascun tipo di dato per potere scegliere quello più appropriato.</p><h2 id="tipi-di-dato-interi"><strong><strong>Tipi di dato </strong>Interi</strong></h2><h3 id="caratteri-char"><strong>Caratteri: <code>char</code></strong></h3><p><code>char</code> contiene caratteri - cose come lettere, punteggiatura e spazi. In un computer i caratteri sono conservati come numeri, pertanto <code>char</code> contiene valori interi che rappresentano caratteri. L'effettiva transcodifica viene descritta dallo standard ASCII. <a href="http://www.asciitable.com/">Ecco una comoda tabella</a> per cercare corrispondenze.</p><p>La dimensione reale, come tutti gli altri tipi di dato in C, dipende dall'hardware sul quale stai lavorando. Come minimo è di 8 bit, quindi contiene valori da 0 a 127. In alternativa si può usare un <code>char</code> con segno (<code>signed char</code>) che può contenere valori da &nbsp;-128 a 127.</p><h3 id="interi-standard-int"><strong>Interi Standard: <code>int</code></strong></h3><p>La quantità di memoria che può utilizzare un singolo <code>int</code> dipende dall'hardware. Tuttavia puoi aspettarti che un <code>int</code> sia almeno di 16 bit. Il che vuol dire che può conservare valori da -32,768 a 32,767, o più a seconda dell'hardware.</p><p>Come per tutti gli altri tipi di dato c'è una variante senza segno (<code>unsigned</code>) che può essere usata. Il dato contenuto in un tipo <code>unsigned int</code> può essere positivo e zero ma non negativo, quindi può contenere valori da 0 a 65,535, o più a seconda dell'hardware.</p><h3 id="interi-corti-short"><strong>Interi Corti: <code>short</code></strong></h3><p>Questo tipo di dato non viene usato spesso, ma è meglio sapere che esiste. Come l'<code>int</code> può conservare valori da -32768 a 32767. Diversamente da <code>int</code>, tuttavia, queste sono tutte le sue capacità. Ogniqualvolta puoi usare <code>short</code>, puoi anche usare <code>int</code>.</p><h3 id="interi-lunghi-long"><strong>Interi Lunghi: <code>long</code></strong></h3><p>Il tipo di dato <code>long</code> conserva interi come il tipo <code>int</code>, ma offre una gamma di valori maggiore al costo di più memoria. <code>long</code> usa almeno 32 bit, e può quindi contenere valori da -2,147,483,648 a 2,147,483,647. In alternativa puoi usare <code>unsigned long</code> per una gamma di valori da 0 a 4,294,967,295.</p><h3 id="interi-ancora-pi-lunghi-long-long"><strong>Interi Ancora Più Lunghi: <code>long long</code></strong></h3><p>Il tipo di dato <code>long long</code> è esagerato per quasi tutte le applicazioni, ma C ti consente comunque di usarlo. È in grado di conservare valori da &nbsp;−9,223,372,036,854,775,807 a 9,223,372,036,854,775,807. In alternativa, esagerando ulteriormente, c'è il tipo senza segno <code>unsigned long long</code>, che conserva valori da 0 a 18,446,744,073,709,551,615.</p><h2 id="tipi-di-dato-in-virgola-mobile"><strong>Tipi di Dato in Virgola Mobile</strong></h2><h3 id="numeri-in-virgola-mobile-base-float"><strong>Numeri in Virgola Mobile Base: <code>float</code></strong></h3><p><code>float</code> richiede almeno 32 bit per conservare il dato, ma offre fino a 6 cifre decimali da 1.2E-38 a 3.4E+38.</p><h3 id="doppi-double"><strong>Doppi: <code>double</code></strong></h3><p><code>double</code> richiede il doppio di memoria rispetto a <code>float</code> (quindi almeno 64 bit). In cambio può offrire fino a 15 cifre decimali da 2.3E-308 a 1.7E+308.</p><h3 id="ottenere-una-gamma-pi-ampia-di-double-long-double"><strong>Ottenere una gamma più ampia di <code>double</code>: <code>long double</code></strong></h3><p><code>long double</code> richiede almeno 80 bit. Pertanto può contenere fino a 19 cifre decimali da 3.4E-4932 a 1.1E+4932.</p><h2 id="scegliere-il-tipo-di-dato-giusto"><strong>Scegliere il tipo di dato giusto</strong></h2><p>C ti fa scegliere il tipo di dato e ti fa essere molto specifico e intenzionale sul modo in cui lo fai. Questo ti dà molto potere sul tuo codice, ma è importante scegliere quello giusto.</p><p>In generale, dovresti scegliere il tipo minimo per il tuo scopo. Se sai che conterai interi da 1 a 10, non ti serve un <code>long</code> e neppure un <code>double</code>. Se sai che non avrai mai valori negativi, appoggiati alle varianti <code>unsigned</code> dei rispettivi tipi di dato. Fornendo questa funzionalità invece che facendolo automaticamente, C è in grado di produrre codice molto leggero ed efficiente. Tuttavia dipende da te, come programmatore, capire capacità e limiti e scegliere in modo appropriato.</p><p>Possiamo usare la funzione <code>sizeof()</code> per verificare la dimensione di una variabile. Dai un'occhiata al seguente programma in &nbsp;C che mostra l'utilizzo dei diversi tipi:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main()
{
    int a = 1;
    
    char b ='G';
    
    double c = 3.14;
    
    printf("Hello World!\n");
 
    //stampa le variabili definite qui sopra assieme alle loro dimensioni
    printf("Ciao! Sono un carattere. Il mio valore è %c e "
           "la mia dimensione è %lu byte.\n", b,sizeof(char));
    //puoi anche usare sizeof(b) qui sopra
 
    printf("Ciao! Sono un intero. Il mio valore è %d e "
           "la mia dimensione è %lu  byte.\n", a,sizeof(int));
    //puoi anche usare sizeof(a) qui sopra
 
    printf("Ciao! Sono una variabile in virgola mobile."
           " Il mio valore è %lf e la mia dimensione è %lu byte.\n",c,sizeof(double));
    //puoi anche usare sizeof(c) qui sopra
 
    printf("Ciao! A presto. :)\n");
    return 0;
}</code></pre><h3 id="risultato-"><strong>Risultato:</strong></h3><pre><code class="language-text">Hello World!
Ciao! Sono un carattere. Il mio valore è G e la mia dimensione è 1 byte.
Ciao! Sono un intero. Il mio valore è 1 e la mia dimensione è 4  byte.
Ciao! Sono una variabile in virgola mobile. Il mio valore è 3.140000 e la mia dimensione è 8 byte.
Ciao! A presto. :)</code></pre><h2 id="il-tipo-void"><strong>Il Tipo Void</strong></h2><p><code>void</code> specifica che non c'è un valore disponibile. Viene usato in tre tipi di situazione:</p><h3 id="1-funzione-che-ritorna-void"><strong>1. Funzione che ritorna <code>void</code></strong></h3><p>Ci sono varie funzioni in C che non restituiscono alcun valore oppure puoi dire che restituiscono <code>void</code>. Una funzione senza valore di ritorno ha il tipo di valore ritornato <code>void</code>. Per esempio, <code>void exit (int status);</code></p><h3 id="2-argomenti-di-funzione-come-void"><strong>2. Argomenti di funzione come <code>void</code></strong></h3><p>Diverse funzioni in C non accettano parametri. Una funzione senza parametri può accettare un <code>void</code>. Per esempio, <code>int rand(void);</code></p><h3 id="3-puntatori-a-void"><strong>3. Puntatori a <code>void</code></strong></h3><p>Un puntatore di tipo <code>void *</code> rappresenta l'indirizzo di un oggetto, ma non il suo tipo. Per esempio una funzione di allocazione di memoria <code>void *malloc( size_t size);</code> ritorna un puntatore a <code>void</code>, che può essere convertito in qualsiasi altro tipo di dato.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Puntatori in C Spiegati - Non Sono Così Difficili Come Pensi ]]>
                </title>
                <description>
                    <![CDATA[ I puntatori sono probabilmente la funzionalità di C più difficile da capire. Tuttavia sono una delle funzionalità che rendono C un linguaggio eccellente. In questo articolo, partiremo dagli aspetti base dei puntatori fino ad arrivare al loro utilizzo con array, funzioni e strutture. Quindi rilassati, prendi un caffè, e preparati ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/puntatori-in-c-spiegati-non-sono-cosi-difficili-come-pensi/</link>
                <guid isPermaLink="false">646098a5410a4d066241b20e</guid>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 12 Jun 2023 10:54:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/05/5f9c994c740569d1a4ca1ef5.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/pointers-in-c-are-not-as-difficult-as-you-think/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Pointers in C Explained – They're Not as Difficult as You Think</a>
      </p><p>I puntatori sono probabilmente la funzionalità di C più difficile da capire. Tuttavia sono una delle funzionalità che rendono C un linguaggio eccellente.</p><p>In questo articolo, partiremo dagli aspetti base dei puntatori fino ad arrivare al loro utilizzo con array, funzioni e strutture.</p><p>Quindi rilassati, prendi un caffè, e preparati per imparare tutto sui puntatori.</p><h2 id="sommario"><strong>Sommario</strong></h2><h5 id="a-fondamenti"><strong><strong>A. F</strong>ondamenti</strong></h5><ol><li><a href="#1-cosa-sono-esattamente-i-puntatori">Cosa sono esattamente i puntatori?</a></li><li><a href="#2-definizione-e-notazione">Definizione e Notazione</a></li><li><a href="#2-alcuni-puntatori-speciali">Alcuni Puntatori Speciali</a></li><li><a href="#4-puntatori-aritmetici">Puntatori Aritmetici</a></li></ol><h5 id="b-array-e-stringhe"><strong><strong>B. Array </strong>e<strong> String</strong>he</strong></h5><ol><li><a href="#1-perche-puntatori-e-array">Perché puntatori e array?</a></li><li><a href="#2-array-1-d">Array 1-D</a></li><li><a href="#3-array-2-d">Array 2-D</a></li><li><a href="#4-stringhe">Stringhe</a></li><li><a href="#5-array-di-puntatori">Array di Puntatori</a></li><li><a href="#6-puntatori-ad-array">Puntatori ad Array</a></li></ol><h5 id="c-funzioni"><strong><strong>C. Fu</strong>nz<strong>ion</strong>i</strong></h5><ol><li><a href="#1-chiamata-per-valore-vs-chiamata-per-riferimento">Chiamata per Valore vs. Chiamata per Riferimento</a></li><li><a href="#2-puntatori-come-argomenti-di-funzione">Puntatori come Argomenti di Funzione</a></li><li><a href="#3-puntatori-come-valori-di-ritorno-da-funzione">Puntatori come Valori di Ritorno da Funzione</a></li><li><a href="#4-puntatore-a-funzione">Puntatore a Funzione</a></li><li><a href="#5-array-di-puntatori-a-funzioni">Array di Puntatori a Funzioni</a></li><li><a href="#6-puntatore-a-funzione-come-argomento">Puntatore a Funzione come Argomento</a></li></ol><h5 id="d-strutture"><strong><strong>D. </strong>Strutture</strong></h5><ol><li><a href="#1-puntatore-a-struttura">Puntatore a Struttura</a></li><li><a href="#2-array-di-strutture">Array di Strutture</a></li><li><a href="#3-puntatore-a-struttura-come-argomento">Puntatore a Struttura come Argomento</a></li></ol><h5 id="e-puntatore-a-puntatore"><strong><strong>E. </strong><a href="#puntatore-a-puntatore"><strong>P</strong>untatore a Puntatore</a></strong></h5><h5 id="f-conclusione"><strong><strong>F. </strong><a href="#conclusione"><strong>Conclusion</strong>e</a></strong></h5><p></p><h2 id="a-fondamenti-1"><strong><strong>A. </strong>Fondamenti</strong></h2><h3 id="1-cosa-sono-esattamente-i-puntatori"><strong><strong>1. </strong>Cosa sono esattamente i puntatori<strong>?</strong></strong></h3><p>Prima di passare alla definizione di puntatori, cerchiamo di capire cosa avviene quando scriviamo il seguente codice:</p><pre><code class="language-c">int digit = 42;
</code></pre><p>Un blocco di memoria è riservato dal compilatore per conservare un valore <code>int</code>. Il nome del blocco è <code>digit</code> e il valore assegnato a questo blocco è <code>42</code>.</p><p>Ora, per ricordare il blocco, a esso viene assegnato un <strong>indirizzo </strong>o un numero di posizione (diciamo 24650).</p><p>Il valore del numero di posizione non è importante per noi, visto che è un valore casuale. Tuttavia possiamo accedere a questo indirizzo usando il carattere <code>&amp;</code> (e commerciale) o <strong>indirizzo </strong>dell'operatore.</p><pre><code class="language-c">printf("Indirizzo di digit = %d.",&amp;digit);
 /* stampa "Indirizzo di digit = 24650. */
</code></pre><p>Possiamo ottenere il valore della variabile <code>digit</code> dal suo indirizzo usando un altro operatore, <code>*</code> (asterisco)<em>, </em>chiamato operatore di<em> </em><strong>riferimento indiretto </strong>o <strong>dereferenziazione</strong> o <strong>valore all'indirizzo</strong>.</p><pre><code class="language-c">printf("Valore di digit = %d.", *(&amp;digit);
 /* stampa "Valore di digit = 42. */
</code></pre><h3 id="2-definizione-e-notazione"><strong><strong>2. Defini</strong>z<strong>ion</strong>e<strong> </strong>e<strong> Nota</strong>z<strong>ion</strong>e</strong></h3><p>L'indirizzo di una variabile può essere conservato in un'altra variabile nota come variabile puntatore. La sintassi per conservare l'indirizzo di una variabile in un puntatore è:</p><pre><code class="language-c">tipoDato *nomeVariabilePuntatore = &amp;nomeVariabile;
</code></pre><p>Per la nostra variabile <code>digit</code>, ciò si può scrivere in questo modo:</p><pre><code class="language-c">int *addressOfDigit = &amp;digit;
</code></pre><p>oppure:</p><pre><code class="language-c">int *addressOfDigit;
addressOfDigit= &amp;digit;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/08/456d4568d6e2c00e377b9dfae76e1809.gif" class="kg-image" alt="Declaration and Definition" width="600" height="400" loading="lazy"></figure><p>Questo si può leggere come &nbsp;- <em>Un puntatore a<em> <code>int</code> (inte</em>ro<em>) <code>addressOfDigit</code></em> conserva l'<em> </em>indirizzo (<code>addressOf(&amp;)</code>) della variabile <em><code>digit</code>.</em></em></p><h4 id="alcuni-punti-da-capire-"><strong>Alcuni punti da capire:</strong></h4><p><code>tipoDato</code> – Dobbiamo dire al computer quale tipo di dato conterrà la variabile il cui indirizzo andremo a conservare. In questo caso <code>int</code> era il tipo di dato di &nbsp;<code>digit</code>.</p><p>Questo <strong>non</strong> vuol dire che <code>addressOfDigit</code> conserverà un valore di tipo <code>int</code>. Un puntatore a intero (come <code>addressOfDigit</code>) può <strong>solo</strong> conservare l'indirizzo di variabili di tipo <code>int</code>.</p><pre><code class="language-c">int variable1;
int variable2;
char variable3;
int *addressOfVariables;
</code></pre><p><code>*</code> – Una variabile puntatore è una variabile <em>speciale </em>nel senso che viene usata per conservare un indirizzo di un'altra variabile. Per differenziarla dalle altre variabili che non conservano un indirizzo, usiamo <code>*</code> come simbolo nella dichiarazione.</p><p>Qui possiamo assegnare l'indirizzo di &nbsp;<code>variable1</code> e <code>variable2</code> al puntatore di interi <code>addressOfVariables</code> ma non <code>variable3</code> visto che è di tipo <code>char</code>. Ci serverebbe una variabile puntatore a carattere per contenere il suo indirizzo.</p><p>Possiamo usare la nostra variabile puntatore <code>addressOfDigit</code> per stampare l'indirizzo e il valore di &nbsp;<code>digit</code> in questo modo:</p><pre><code class="language-c">printf("Indirizzo di digit = %d.", addressOfDigit);
 /* stampa "Indirizzo di digit = 24650." */
printf("Valore di digit = %d.", *addressOfDigit);
 /* stampa "Valore di digit = 42. */
</code></pre><p>Qui, <code>*addressOfDigit</code> può essere letto come <em>il valore all'indirizzo conservato in</em> <em><em><code>addressOfDigit</code>.</em></em></p><p>Nota che abbiamo usato <code>%d</code> come <strong>identificatore di formato </strong>per <code>addressOfDigit</code>. In effetti questo non è completamente corretto. L'identificatore corretto sarebbe <code>%p</code>.</p><p>Usando <code>%p</code>, l'indirizzo viene visualizzato come valore esadecimale. Un indirizzo di memoria può tuttavia essere visualizzato anche come intero oppure come valore ottale. Per questo, visto che non è il modo <em>interamente corretto,</em> viene mostrato un avvertimento.</p><pre><code class="language-c">int num = 5;
int *p = &amp;num;
printf("Indirizzo usando %%p = %p",p);
printf("Indirizzo usando %%d = %d",p);
printf("Indirizzo usando %%o = %o",p);
</code></pre><p>Questo il risultato in base al compilatore che sto usando:</p><pre><code class="language-c">Indirizzo usando %p = 000000000061FE00
Indirizzo usando %d = 6422016
Indirizzo usando %o = 30377000
</code></pre><blockquote>Questo è l'avvertimento mostrato quando usi &nbsp;%d - " warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' " ("avvertimento: format %d si aspetta argomenti di tipo 'int', ma l'argomento 2 è di tipo 'int *').</blockquote><h3 id="3-alcuni-puntatori-speciali"><strong><strong>3. </strong>Alcuni Puntatori Speciali</strong></h3><h4 id="il-puntatore-selvaggio"><strong>Il Puntatore Selvaggio</strong></h4><pre><code class="language-c">char *alphabetAddress; /* non inizializzato o puntatore selvaggio */
char alphabet = "a";
alphabetAddress = &amp;alphabet; /* ora non più puntatore selvaggio */
</code></pre><p>Quando abbiamo definito il nostro puntatore a carattere <code>alphabetAddress</code>, non lo abbiamo inizializzato.</p><p>Tali puntatori sono noti come <strong>puntatori selvaggi</strong> (wild pointers). Conservano un valore spazzatura (vale a dire l'indirizzo di memoria) di un byte che non sappiamo se sia riservato o meno (ricorda <code>int digit = 42;</code>, abbiamo riservato un indirizzo di memoria quando l'abbiamo dichiarata).</p><p>Supponiamo di dereferenziare un puntatore selvaggio e di assegnare un valore all'indirizzo di memoria al quale sta puntando. Questo provocherà un comportamento inatteso visto che andremo a scrivere dati in un blocco di memoria che potrebbe essere libero oppure riservato.</p><h4 id="puntatore-null"><strong>Puntatore Null</strong></h4><p>Per assicurarci di non avere un puntatore selvaggio, possiamo inizializzare un puntatore con un valore <code>NULL</code> , rendendolo un <strong>puntatore null </strong>(null pointer).</p><pre><code class="language-c">char *alphabetAddress = NULL /* Puntatore null */ 
</code></pre><p>Un puntatore null punta al nulla, oppure a un indirizzo di memoria al quale gli utenti non possono accedere.</p><h4 id="puntatore-void"><strong>Puntatore Void</strong></h4><p>Un <strong>puntatore void</strong> può essere usato per puntare a una variabile associata a qualsiasi tipo di dato. Può essere riutilizzato per puntare a qualsiasi tipo di dato vogliamo. Viene dichiarato in questo modo:</p><pre><code class="language-c">void *puntatoreANomeVariabile = NULL;
</code></pre><p>Vista la loro natura molto <em>generica</em>, sono anche noti come <strong>puntatori generici</strong> (<strong><strong>generic pointers</strong></strong>).</p><p>Con la loro flessibilità, i puntatori void sono anche dotati di qualche vincolo. I puntatori void <strong>non possono</strong> essere dereferenziati come qualsiasi altro puntatore. È necessaria un'appropriata conversione di tipo (<em>typecasting</em>).</p><pre><code class="language-c">void *pointer = NULL;
int number = 54;
char alphabet = "z";
pointer = &amp;number;
printf("Il valore di number = ", *pointer); /* Errore di compilazione */
/* Metodo corretto */
printf("Il valore di number = ", *(int *)pointer); /* stampa "Il valore di number = 54" */
pointer = &amp;alphabet;
printf("Il valore di alphabet = ", *pointer); /* Errore di compilazione */
printf("Il valore di alphabet = ", *(char *)pointer); /* stampa "Il valore di alphabet = z */
</code></pre><p>Allo stessa stregua, i puntatori void richiedono una conversione di tipo per eseguire operazioni aritmetiche.</p><p>I puntatori void sono di grande uso in C. Funzioni di libreria come <code>malloc()</code> e <code>calloc()</code> che allocano dinamicamente memoria, ritornano puntatori void. <code>qsort()</code>, una funzione integrata di ordinamento in C, riceve una funzione come suo argomento che a sua volta riceve puntatori void come suoi argomenti.</p><h4 id="puntatori-pendenti"><strong>Puntatori Pendenti</strong></h4><p>Un puntatore pendente (dangling pointer) punta a un indirizzo di memoria <strong>in uso</strong> per conservare una variabile. Visto che l'indirizzo a cui punta non è più riservato, l'uso potrebbe portare a risultati inaspettati.</p><pre><code class="language-c">main(){
  int *ptr;
  ptr = (int *)malloc(sizeof(int));
  *ptr = 1;
  printf("%d",*ptr); /* stampa 1 */
  free(ptr); /* deallocazione */
  *ptr = 5;
  printf("%d",*ptr); /* potrebbe o non potrebbe stampare 5 */
}
</code></pre><p>Anche se la memoria è stata deallocata da <code>free(ptr)</code>, il puntatore a intero <code>ptr</code> punta ancora a quell'indirizzo di memoria non più riservato.</p><h3 id="4-puntatori-aritmetici"><strong><strong>4. </strong>Puntatori Aritmetici</strong></h3><p>Ora sappiamo che i puntatori non sono come le altre variabili. Non conservano alcun valore, ma l'indirizzo di blocchi di memoria.</p><p>Pertanto dovrebbe essere piuttosto chiaro che non tutte le operazioni aritmetiche sarebbero valide con essi. Avrebbe senso moltiplicare o dividere due puntatori (<em>che contengono indirizzi)?</em></p><h4 id="i-puntatori-hanno-poche-ma-immensamente-utili-operazioni-valide-"><strong>I puntatori hanno poche ma immensamente utili operazioni valide<strong>:</strong></strong></h4><ol><li>Si può assegnare il valore di un puntatore a un altro solo se sono dello stesso tipo (a meno che non siano oggetto di conversione di tipo oppure uno di essi sia <code>void *</code>).</li></ol><pre><code class="language-c">int ManU = 1;
int *addressOfManU = &amp;ManU;
int *anotherAddressOfManU = NULL;
anotherAddressOfManU = addressOfManU; /* Valido */
double *wrongAddressOfManU = addressOfManU; /* Non Valido */
</code></pre><p>2. &nbsp; Puoi solo <strong>aggiungere</strong> o <strong>sottrarre interi</strong> ai puntatori.</p><pre><code class="language-c">int myArray = {3,6,9,12,15};
int *pointerToMyArray = &amp;myArray[0];
pointerToMyArray += 3; /* Valido */
pointerToMyArray *= 3; /* Non Valido */
</code></pre><p>Quando aggiungi (o sottrai) un intero (diciamo <code>n</code>) a un puntatore, <strong>non </strong>stai effettivamente aggiungendo (o sottraendo) <code>n</code> byte al valore del puntatore. Stai in realtà aggiungendo (o sottraendo) <em><code>n</code>-volte in byte la dimensione del tipo di dato della variabile puntata</em>.</p><pre><code class="language-c">int number = 5;
 /* Supponiamo che l'indirizzo di number sia 100 */
int *ptr = &amp;number;
int newAddress = ptr + 3;
 /* Uguale a ptr + 3 * sizeof(int) */
</code></pre><p>Il valore conservato in <code>newAddress</code> <strong>non</strong> sarà 103, ma <code>112</code>.</p><p>3. La <strong>sottrazione<strong> </strong></strong>e il<strong> confronto </strong>di puntatori è valida solo se entrambi sono membri dello stesso array. La sottrazione tra puntatori fornisce il numero di elementi che li separano.</p><pre><code class="language-c">int myArray = {3,6,9,12,15};
int sixthMultiple = 18;
int *pointer1 = &amp;myArray[0];
int *pointer2 = &amp;myArray[1];
int *pointer6 = &amp;sixthMuliple;
 /* Espressione valida */
if(pointer1 == pointer2)
pointer2 - pointer1;
 /* Espressione non valida */
if(pointer1 == pointer6)
pointer2 - pointer6
</code></pre><p>4. &nbsp;Puoi assegnare o confrontare un puntatore con &nbsp;<code>NULL</code>.</p><blockquote><em>L'unica eccezione alle regole qui sopra è che l'indirizzo del primo blocco di memoria dopo l'ultimo elemento di un array segua un puntatore aritmetico<em>.</em></em></blockquote><p>Puntatori e array coesistono. Queste valide manipolazioni di puntatori sono immensamente utili con gli array, e le discuteremo nella prossima sezione.</p><h2 id="b-array-e-stringhe-1"><strong><strong>B. Array </strong>e<strong> String</strong>he</strong></h2><!--kg-card-begin: markdown--><p><a name="1-perche-puntatori-e-array"></a></p>
<h3 id="1perchpuntatoriearray">1. Perché puntatori e array?</h3>
<!--kg-card-end: markdown--><p>In C, i puntatori e gli array hanno una relazione piuttosto forte.</p><p>La ragione per la quale <em>dovrebbero </em>essere discussi insieme è che quello che puoi ottenere con la notazione di array (<code>nomeArray[indice]</code>) può anche essere ottenuto con i puntatori, in genere più velocemente.</p><h3 id="2-array-1-d"><strong><strong>2. Array</strong> 1-D</strong></h3><p>Osserviamo cosa succede quando scriviamo <code>int myArray[5];</code>.</p><p>Cinque blocchi <strong>consecutivi</strong> di memoria a partire da <code>myArray[0]</code> fino a <code>myArray[4]</code> sono creati con valori spazzatura al loro interno. Ciascun blocco ha una dimensione di 4 byte.</p><p>Pertanto se l'indirizzo di <code>myArray[0]</code> è, diciamo, <code>100</code>, l'indirizzo dei restanti blocchi sarebbe <code>104</code>, <code>108</code>, <code>112</code> e <code>116</code>.</p><p>Dai un'occhiata al seguente codice:</p><pre><code class="language-c">int prime[5] = {2,3,5,7,11};
printf("Risultato usando &amp;prime = %d\n",&amp;prime);
printf("Risultato usando prime = %d\n",prime);
printf("Risultato usando &amp;prime[0] = %d\n",&amp;prime[0]);

/* Output */
Risultato usando &amp;prime = 6422016
Risultato usando prime = 6422016
Risultato usando &amp;prime[0] = 6422016
</code></pre><p>Quindi, <code>&amp;prime</code>, <code>prime</code>, e <code>&amp;prime[0]</code> danno tutti lo stesso indirizzo, giusto? Bene, aspetta e continua a leggere, perché avrai una sorpresa (e forse un po' di confusione).</p><p>Cerchiamo di incrementare &nbsp;<code>&amp;prime</code>, <code>prime</code>, e <code>&amp;prime[0]</code> di 1.</p><pre><code class="language-c">printf("Risultato usando &amp;prime = %d\n",&amp;prime + 1);
printf("Risultato usando prime = %d\n",prime + 1);
printf("Risultato usando &amp;prime[0] = %d\n",&amp;prime[0] + 1);

/* Output */
Risultato usando &amp;prime = 6422036
Risultato usando prime = 6422020
Risultato usando &amp;prime[0] = 6422020
</code></pre><p>Aspetta! Come mai il risultato di <code>&amp;prime + 1</code> è diverso dagli altri due? Perché <code>prime + 1</code> e <code>&amp;prime[0] + 1</code> sono ancora uguali? Rispondiamo a queste domande.</p><p><code>prime</code> e <code>&amp;prime[0]</code> puntano entrambi all'elemento 0 dell'array <code>prime</code>. Quindi il <strong>nome stesso di un array è a sua volta un puntatore all'elemento 0 dell'</strong> <strong><strong>array</strong></strong>.</p><p>Qui entrambi puntano al primo elemento di 4 byte di dimensione. Quando aggiungi 1 ad essi, ora puntano all'elemento con indice 1 dell'array. Ne consegue un aumento nell'indirizzo di 4.</p><p><code>&amp;prime</code>, d'altro canto, è un <strong>puntatore a un array <code>int</code> di dimensione 5</strong>. Conserva l'indirizzo base dell'array <code>prime[5]</code>, che è uguale all'indirizzo del primo elemento. Pertanto un aumento di 1 risulta in un indirizzo con un aumento di 5 x 4 = 20 byte.</p><p>In breve, <code>arrayName</code> e <code>&amp;arrayName[0]</code> puntano all'elemento 0 mentre &nbsp;<code>&amp;arrayName</code> punta all'intero array.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/08/09f8f82032f04a27fce46cc048644f8d.gif" class="kg-image" alt="1-D Array" width="600" height="400" loading="lazy"></figure><p>Possiamo accedere agli elementi dell'array usando variabili indicizzate come questa:</p><pre><code class="language-c">int prime[5] = {2,3,5,7,11};
for( int i = 0; i &lt; 5; i++)
{
  printf("indice = %d, indirizzo = %d, valore = %d\n", i, &amp;prime[i], prime[i]);
}
</code></pre><p>Possiamo fare la stessa cosa usando i puntatori che sono <strong>sempre</strong> più veloci rispetto all'uso dell'indicizzazione.</p><pre><code class="language-c">int prime[5] = {2,3,5,7,11};
for( int i = 0; i &lt; 5; i++)
{
  printf("indice = %d, indirizzo = %d, valore = %d\n", i, prime + i, *(prime + i));
}
</code></pre><p>Entrambi i metodi danno questo risultato:</p><pre><code class="language-c">indice = 0, indirizzo = 6422016, valore = 2
indice = 1, indirizzo = 6422020, valore = 3
indice = 2, indirizzo = 6422024, valore = 5
indice = 3, indirizzo = 6422028, valore = 7
indice = 4, indirizzo = 6422032, valore = 11</code></pre><p>Quindi <code>&amp;arrayName[i]</code> e <code>arrayName[i]</code> sono lo stesso di &nbsp;<code>arrayName + i</code> e &nbsp;<code>*(arrayName + i)</code>, rispettivamente.</p><h3 id="3-array-2-d"><strong><strong>3. Array</strong> <strong>2-D</strong></strong></h3><p>Gli array bidimensionali sono array di array.</p><pre><code class="language-c">int marks[5][3] = { { 98, 76, 89},
                    { 81, 96, 79},
                    { 88, 86, 89},
                    { 97, 94, 99},
                    { 92, 81, 59}
                  };
</code></pre><p>Si può pensare a <code>marks</code> come un array di 5 elementi, ognuno dei quali è un array monodimensionale che contiene 3 interi. Lavoreremo su una serie di programmi per comprendere le diverse espressioni di indicizzazione.</p><pre><code class="language-c">printf("L'indirizzo dell'intero array 2-D = %d\n", &amp;marks);
printf("L'aggiunta di 1 risulta in %d\n", &amp;marks +1);

/* Output */
L'indirizzo dell'intero array 2-D = 6421984
L'aggiunta di 1 risulta in 6422044
</code></pre><p>Come con gli array 1-D, <code>&amp;marks</code> punta all'intero array 2-D, <code>marks[5][3]</code>. Pertanto incrementando di 1 ( = 5 array x 3 interi ciascuno x 4 &nbsp;byte = 60) risulta un aumento di 60 byte.</p><pre><code class="language-c">printf("Indirizzo dell'array 0 = %d\n", marks);
printf("L'aggiunta di 1 risulta in %d\n", marks +1);
printf("Indirizzo dell'array 0 =%d\n", &amp;marks[0]);
printf("L'aggiunta di 1 risulta in %d\n", &amp;marks[0] + 1);

/* Output */
Indirizzo dell'array 0 = 6421984
L'aggiunta di 1 risulta in 6421996
Indirizzo dell'array 0 = 6421984
L'aggiunta di 1 risulta in 6421996</code></pre><p>Se <code>marks</code> fosse un array 1-D, <code>marks</code> e <code>&amp;marks[0]</code> avrebbero puntato allo stesso elemento <code>0</code> . <strong>Per un array 2-D, gli elementi ora sono array 1-D</strong>. Di conseguenza, <code>marks</code> e <code>&amp;marks[0]</code> puntano all'elemento dell'array con indice &nbsp;<code>0</code> , e l'aggiunta di 1 punta al primo array.</p><pre><code class="language-c">printf("Indirizzo dell'elemento 0 dell'array 0 = %d\n", marks[0]);
printf("L'aggiunta di 1 risulta in %d\n", marks[0] + 1);
printf("Indirizzo dell'elemento 0 del primo array = %d\n", marks[1]);
printf("L'aggiunta di 1 risulta in %d\n", marks[1] + 1);

 /* Output */
Indirizzo dell'elemento 0 dell'array 0 = 6421984
L'aggiunta di 1 risulta in 6421988
Indirizzo dell'elemento 0 del primo array = 6421996
L'aggiunta di 1 risulta in 6422000
</code></pre><p>Ora viene la differenza. Per un array 1-D, <code>marks[0]</code> darebbe il valore dell'elemento 0. Un incremento di 1 aumenterebbe il valore di 1.</p><p>Ma in un array 2-D , <code>marks[0]</code> punta all'elemento <code>0</code> dell'array <code>0</code>. In modo simile, &nbsp;<code>marks[1]</code> punta all'elemento <code>0</code> del primo array. Un incremento di 1 punterebbe al primo elemento del primo array.</p><pre><code class="language-c">printf("Valore dell'elemento 0 dell'array 0 = %d\n", marks[0][0]);
printf("L'aggiunta di 1 risulta in %d", marks[0][0] + 1);

/* Output */
Valore dell'elemento 0 dell'array 0 = 98
L'aggiunta di 1 risulta in 99</code></pre><p>Questa è la parte nuova, &nbsp;<code>marks[i][j]</code> fornisce il valore dell'elemento <code>j</code> dell'array <code>i</code>. Un incremento a esso cambia il valore conservato in <code>marks[i][j]</code>. Ora proviamo a scrivere <code>marks[i][j]</code> in termini di puntatori.</p><p>Sappiamo dalla nostra precedente discussione che <code>marks[i] + j</code> punterebbe all'elemento <code>i</code> dell'array <code>j</code>. Dereferenziandolo significherebbe ottenere il valore a quell'indirizzo. Pertanto <strong><strong><code>marks[i][j]</code> </strong>è uguale a<strong> <code>*(marks[i] + j)</code></strong></strong>.</p><p>Dalla nostra discussione sugli array 1-D, <code>marks[i]</code> è uguale a <code>*(marks + i)</code>. Quindi <strong><strong><code>marks[i][j]</code> </strong>può essere scritto come<strong> <code>*(*(marks + i) + j)</code></strong></strong> in termini di puntatori.</p><p>Ecco un riepilogo delle notazioni a confronto per gli array monodimensionali e bidimensionali.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>ESPRESSIONE</th>
<th>ARRAY 1-D</th>
<th>ARRAY 2-D</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&amp;arrayName</code></td>
<td>punta all'indirizzo dell'intero array<br>aggiungendo 1 l'indirizzo aumenta di 1 x sizeof(arrayName)</td>
<td>punta all'indirizzo dell'intero array<br>aggiungendo 1 l'indirizzo aumenta di 1 x sizeof(arrayName)</td>
</tr>
<tr>
<td><code>arrayName</code></td>
<td>punta all'elemento 0<br>aggiungendo 1 aumenta l'indirizzo del primo elemento</td>
<td>punta all'elemento 0 (array)<br>aggiungendo 1 aumenta l'indirizzo del primo elemento (array)</td>
</tr>
<tr>
<td><code>&amp;arrayName[i]</code></td>
<td>punta all'elemento i<br>aggiungendo 1 aumenta l'indirizzo all'elemento (i+1)</td>
<td>punta all'elemento i (array)<br>aggiungendo 1 aumenta l'indirizzo dell'elemento (i+1) (array)</td>
</tr>
<tr>
<td><code>arrayName[i]</code></td>
<td>fornisce il valore dell'elemento i<br>aggiungendo 1 aumenta dell'elemento i</td>
<td>punta all'elemento 0 dell'array i<br>aggiungento 1 aumenta l'indirizzo del primo elemento dell'array i</td>
</tr>
<tr>
<td><code>arrayName[i][j]</code></td>
<td>Nulla</td>
<td>fornisce il valore dell'elemento j dell'array i<br>aggiungendo 1 aumenta il valore dell'elemento j dell'array i</td>
</tr>
<tr>
<td>Espressione di Puntatore per Accedere agli Elementi</td>
<td><code>*( arrayName + i)</code></td>
<td><code>*( *( arrayName + i) + j)</code></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="4-stringhe"><strong><strong>4. String</strong>he</strong></h3><p>Una stringa è un array monodimensionale di caratteri che finisce con un carattere null <code>(\0)</code>. Quando scriviamo <code>char name[] = "Srijan";</code>, ciascun carattere occupa un byte di memoria con l'ultimo che è sempre <code>\0</code>.</p><p>In modo simile agli array visti in precedenza, <code>name</code> e <code>&amp;name[0]</code> puntano al carattere a indice <code>0</code> nella stringa mentre <code>&amp;name</code> punta all'intera stringa. Inoltre, &nbsp;<code>name[i]</code> può essere scritto come <code>*(name + i)</code>.</p><pre><code class="language-c">/* Array di Stringhe */
char top[6][15] = {
                    "Liverpool",
                    "Man City",
                    "Man United",
                    "Chelsea",
                    "Leicester",
                    "Tottenham"
                  };

printf("Puntatore a un array 2-D = %d\n", &amp;top);
printf("L'aggiunta di 1 risulta in %d\n", &amp;top + 1);

 /* Output */
// Puntatore a un array 2-D = 6421952
// L'aggiunta di 1 risulta in 6422042

printf("Puntatore all'indice 0 della stringa = %d\n", &amp;top[0]);
printf("L'aggiunta di 1 risulta in %d\n", &amp;top[0] + 1);

 /* Output */
// Puntatore all'indice 0 della stringa = 6421952
// L'aggiunta di 1 risulta in 6421967

printf("Puntatore all'indice 0 della stringa = %d\n", top);
printf("L'aggiunta di 1 risulta in %d\n", top + 1);

 /* Output */
// Puntatore all'indice 0 della stringa = 6421952
// L'aggiunta di 1 risulta in 6421967

printf("Puntatore all'elemento a indice 0 della quarta stringa = %d\n", top[4]);
printf("Puntatore al primo elemento della quarta stringa = %c\n", top[4] + 1);

 /* Output */
// Puntatore all'elemento a indice 0 della quarta stringa = 6422012
// Puntatore al primo elemento della quarta stringa = 6422013

printf("Valore del primo carattere della terza stringa = %c\n", top[3][1]);
printf("Lo stesso usando puntatori = %c\n", *(*(top + 3) + 1));

 /* Output */
// Valore del primo carattere della terza stringa = h
// Lo stesso usando puntatori = h
</code></pre><p>Si può accedere e manipolare anche un array di caratteri bidimensionale oppure un array di stringhe come discusso prima.</p><pre><code class="language-c">/* Array di Stringhe */
char top[6][15] = {
                    "Liverpool",
                    "Man City",
                    "Man United",
                    "Chelsea",
                    "Leicester",
                    "Tottenham"
                  };

printf("Puntatore a un array 2-D = %d\n", &amp;top);
printf("L'aggiunta di 1 risulta in %d\n", &amp;top + 1);

 /* Output */
// Puntatore a un array 2-D = 6421952
// L'aggiunta di 1 risulta in 6422042

printf("Puntatore all'indice 0 della stringa = %d\n", &amp;top[0]);
printf("L'aggiunta di 1 risulta in %d\n", &amp;top[0] + 1);

 /* Output */
// Puntatore all'indice 0 della stringa = 6421952
// L'aggiunta di 1 risulta in 6421967

printf("Puntatore all'indice 0 della stringa = %d\n", top);
printf("L'aggiunta di 1 risulta in %d\n", top + 1);

 /* Output */
// Puntatore all'indice 0 della stringa = 6421952
// L'aggiunta di 1 risulta in 6421967

printf("Puntatore all'elemento a indice 0 della quarta stringa = %d\n", top[4]);
printf("Puntatore al primo elemento della quarta stringa = %c\n", top[4] + 1);

 /* Output */
// Puntatore all'elemento a indice 0 della quarta stringa = 6422012
// Puntatore al primo elemento della quarta stringa = 6422013

printf("Valore del primo carattere della terza stringa = %c\n", top[3][1]);
printf("Lo stesso usando puntatori = %c\n", *(*(top + 3) + 1));

 /* Output */
// Valore del primo carattere della terza stringa = h
// Lo stesso usando puntatori = h
</code></pre><h3 id="5-array-di-puntatori"><strong><strong>5. Array </strong>di Puntatori</strong></h3><p>Oltre agli array di tipo &nbsp;<code>int</code> e &nbsp;<code>char</code>, esiste anche un array di puntatori. Questo tipo di array sarebbe semplicemente una collezione di indirizzi. Questi indirizzi potrebbero puntare a variabili singole oppure a un altro array.</p><p>La sintassi per dichiarare un <strong>array di puntatori </strong>è la seguente:</p><pre><code class="language-c">tipoDato *nomeVariabile[dimensione];

/* Esempi */
int *example1[5];
char *example2[8];
</code></pre><p>Seguendo la <a href="http://unixwiz.net/techtips/reading-cdecl.html">precedenza degli operatori</a>, il primo esempio potrebbe essere letto come - &nbsp;<em><em><code>example1</code> </em>è un array<em>(<code>[]</code>) </em>di 5 puntatori a<em> <code>int</code></em></em>. In modo simile, <em><em><code>example2</code> </em>è un<em> array </em>di<em> 8 </em>puntatori a<em> <code>char</code></em></em>.</p><p>Possiamo conservare un array di stringhe bidimensionale <code>top</code> usando un array di puntatori, risparmiando anche della memoria.</p><pre><code class="language-c">char *top[] = {
                    "Liverpool",
                    "Man City",
                    "Man United",
                    "Chelsea",
                    "Leicester",
                    "Tottenham"
                  };
</code></pre><p><code>top</code> conterrà gli indirizzi base di tutti i rispettivi nomi. L'indirizzo base di &nbsp;<code>"Liverpool"</code> sarà conservato in <code>top[0]</code>, <code>"Man City"</code> in <code>top[1]</code>, e così via.</p><p>Nella dichiarazione precedente, abbiamo richiesto 90 byte per conservare i nomi. Qui servono solo ( 58 (somma dei byte dei nomi) + 12 ( byte richiesti per conservare l'indirizzo nell'array) ) 70 byte.</p><p>La manipolazione di stringhe o interi diventa molto più facile quando si usa un array di puntatori.</p><p>Se proviamo a inserire <code>"Leicester"</code> davanti a <code>"Chelsea"</code>, dobbiamo solo invertire i valori di &nbsp;<code>top[3]</code> e <code>top[4]</code> in questo modo:</p><pre><code class="language-c">char *temporary;
temporary = top[3];
top[3] = top[4];
top[4] = temporary;
</code></pre><p>Senza puntatori, avremmo dovuto scambiare ogni carattere delle stringhe, il che avrebbe richiesto più tempo. Ecco perché le stringhe sono generalmente dichiarate usando i &nbsp;puntatori.</p><h3 id="6-puntatori-ad-array"><strong><strong>6. P</strong>untatori ad<strong> Array</strong></strong></h3><p>Come i puntatori a <code>int</code> o i puntatori a <code>char</code>, abbiamo anche puntatori ad array. Questo puntatore punta all'intero array invece che ai suoi elementi.</p><p>Ricordi che abbiamo discusso di come <code>&amp;arrayName</code> punti all'intero array? Ecco, si tratta di un puntatore ad array.</p><p>Un puntatore ad array può essere dichiarato in questo modo:</p><pre><code class="language-c">tipoDato (*nomeVariabile)[dimensione];

/* Esempi */
int (*ptr1)[5];
char (*ptr2)[15];
</code></pre><p>Nota le parentesi. Senza di esse, avremmo un array di puntatori. Il primo esempio può essere letto come &nbsp;- <em><em><code>ptr1</code> </em>è un puntatore a un array di<em> 5 <code>int</code></em> <em>(</em>interi<em>)</em></em>.</p><pre><code class="language-c">int goals[] = { 85,102,66,69,67};
int (*pointerToGoals)[5] = &amp;goals;
printf("Indirizzo conservato in pointerToGoals %d\n", pointerToGoals);
printf("Dereferenziandolo, otteniamo %d\n",*pointerToGoals);

/* Output */
Indirizzo conservato in pointerToGoals 6422016
Dereferenziandolo, otteniamo 6422016
</code></pre><p>Quando dereferenziamo un puntatore, otteniamo il valore a quell'indirizzo. Alla stessa stregua, dereferenziando un puntatore ad array, otteniamo l'array e il nome al quale punta l'array che punta all'indirizzo base. Possiamo confermare che <code>*pointerToGoals</code> fornisce l'array <code>goals</code> se troviamo la sua dimensione.</p><pre><code class="language-c">printf("Dimensione di goals[5] = %d, *pointerToGoals);

/* Output */
Dimensione di goals[5] = 20
</code></pre><p>Se lo dereferenziamo nuovamente, otterremo il valore conservato in quell'indirizzo. Possiamo stampare tutti gli elementi usando <code>pointerToGoals</code>.</p><pre><code class="language-c">for(int i = 0; i &lt; 5; i++)
  printf("%d ", *(*pointerToGoals + i));

/* Output */
85 102 66 69 67
</code></pre><p>I puntatori e puntatori ad array sono piuttosto utili se accoppiati a funzioni. A seguire nella prossima sezione!</p><h2 id="c-funzioni-1"><strong><strong>C. Fun</strong>z<strong>ion</strong>i</strong></h2><h3 id="1-chiamata-per-valore-vs-chiamata-per-riferimento"><strong><strong>1. C</strong>hiamata per Valore vs. Chiamata per Riferimento</strong></h3><p>Dai un'occhiata al programma qui sotto:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int multiply(int x, int y){
  int z;
  z = x * y;
  return z;
}

main(){
  int x = 3, y = 5; 
  int product = multiply(x,y);
  printf("Prodotto = %d\n", product);
  /* stampa "Prodotto = 15" */
}
</code></pre><p>La funzione <code>multiply()</code> riceve due argomenti <code>int</code> e ritorna il loro prodotto come &nbsp;<code>int</code>.</p><p>Nella chiamata a <code>multiply(x,y)</code>, passiamo i valori di <code>x</code> e <code>y</code> (assegnati in <code>main()</code>), che sono gli <em>effettivi argomenti</em>, per <code>multiply()</code>.</p><p>I valori degli effettivi argomenti sono passati o copiati negli <em>argomenti formali </em><code>x</code> e <code>y</code> ( di <code>multiply()</code>). &nbsp;<code>x</code> e <code>y</code> di <code>multiply()</code> sono diversi da quelli di <code>main()</code>. Questo si può verificare stampando i loro indirizzi.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int multiply(int x, int y){
  printf("Indirizzo di x in multiply() = %d\n", &amp;x);
  printf("Indirizzo di y in multiply() = %d\n", &amp;y);
  int z;
  z = x * y;
  return z;
}

main(){
  int x = 3, y = 5;
  printf("Indirizzo di x in main() = %d\n", &amp;x);
  printf("Indirizzo di y in main() = %d\n", &amp;y);
  int product = multiply(x,y);
  printf("Prodotto = %d\n", product);
}

/* Output */
Indirizzo di x in main() = 6422040
Indirizzo di y in main() = 6422036
Indirizzo di x in multiply() = 6422000
Indirizzo di y in multiply() = 6422008
Prodotto = 15
</code></pre><p>Visto che abbiamo creato valori conservati un una nuova posizione, ci costa memoria. Non sarebbe meglio se potessimo eseguire la stessa operazione senza sprecare spazio?</p><p>La <strong>chiamata per riferimento </strong>ci consente di farlo. Passiamo gli indirizzi o riferimenti delle variabili alla funzione, la quale non crea una copia. Usando l'operatore di dereferenziazione <code>*</code>, possiamo avere accesso al valore conservato in quegli indirizzi.</p><p>Possiamo anche riscrivere il programma qui sopra usando una chiamata per riferimento.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int multiply(int *x, int *y){
  int z;
  z = (*x) * (*y);
  return z;
}

main(){
  int x = 3, y = 5; 
  int product = multiply(&amp;x,&amp;y);
  printf("Prodotto = %d\n", product);
   /* Stampa "Prodotto = 15" */
}</code></pre><h3 id="2-puntatori-come-argomenti-di-funzione"><strong><strong>2. P</strong>untatori come Argomenti di Funzione</strong></h3><p>In questa sezione, esamineremo vari programmi nei quali passiamo valori di tipo <code>int</code>, <code>char</code>, array e stringhe come argomenti usando puntatori.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

void add(float *a, float *b){
 float c = *a + *b;
 printf("L'addizione fornisce %.2f\n",c);
}

void subtract(float *a, float *b){
 float c = *a - *b;
 printf("La sottrazione fornisce %.2f\n",c);
}

void multiply(float *a, float *b){
 float c = *a * *b;
 printf("La moltiplicazione fornisce %.2f\n",c);
}

void divide(float *a, float *b){
 float c = *a / *b;
 printf("La divisione fornisce %.2f\n",c);
}

main(){
    printf("Digita due numeri :\n");
    float a,b;
    scanf("%f %f",&amp;a,&amp;b);
    printf("Cosa vuoi fare con questi numeri?\nAggiungi : a\nSottrai : s\nMoltiplica : m\nDividi : d\n");
    char operation = '0';
    scanf(" %c",&amp;operation);
    printf("\nEseguo...\n\n");
    switch (operation) {
    case 'a':
        add(&amp;a,&amp;b);
        break;
    case 's':
        subtract(&amp;a,&amp;b);
        break;
    case 'm':
        multiply(&amp;a,&amp;b);
        break;
    case 'd':
        divide(&amp;a,&amp;b);
        break;
    default:
        printf("Input non valido!!!\n");

  }

}
</code></pre><p>Abbiamo creato quattro funzioni, &nbsp;<code>add()</code>, <code>subtract()</code>, <code>multiply()</code> e <code>divide()</code> per eseguire operazioni aritmetiche su due numeri, &nbsp;<code>a</code> e <code>b</code>.</p><p>Gli indirizzi di <code>a</code> e <code>b</code> sono passati alle funzioni. All'interno della funzione, usando &nbsp;<code>*</code> abbiamo accesso ai valori e stampiamo il risultato.</p><p>In modo simile, possiamo passare array come argomenti usando un puntatore al loro primo elemento.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

void greatestOfAll( int *p){
  int max = *p;
  for(int i=0; i &lt; 5; i++){
    if(*(p+i) &gt; max)
       max = *(p+i);
  }
  printf("L'elemento più grande è %d\n",max);
}
main(){
  int myNumbers[5] = { 34, 65, -456, 0, 3455};
  greatestOfAll(myNumbers);
   /* Stampa :L'elemento più grande è 3455" */
}
</code></pre><p>Visto che il nome dell'array è esso stesso un puntatore al primo elemento, lo passiamo come argomento alla funzione <code>greatestOfAll()</code>. Nella funzione qui sopra, iteriamo attraverso l'array tramite un ciclo e un puntatore.</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

void wish(char *p){
 printf("Buona giornata, %s",p);
}

main(){
 printf("Digita il tuo nome : \n");
 char name[20];
 gets(name);
 wish(name);
}
</code></pre><p>Qui sopra passiamo la stringa <code>name</code> a <code>wish()</code> tramite un puntatore e stampiamo il messaggio.</p><h3 id="3-puntatori-come-valori-di-ritorno-da-funzione"><strong><strong>3. P</strong>untatori come Valori di Ritorno da Funzione</strong></h3><pre><code class="language-c">#include &lt;stdio.h&gt;

int* multiply(int *a, int *b){
  int c = *a * *b;
  return &amp;c;
}

main(){
  int a= 3, b = 5;
  int *c = multiply (&amp;a,&amp;b);
  printf("Prodotto = %d",*c);
}
</code></pre><p>La funzione <code>multiply()</code> riceve due parametri a &nbsp;<code>int</code>. Anch'essa ritorna un puntatore a &nbsp;<code>int</code> che conserva l'indirizzo nel quale il prodotto viene salvato.</p><p>È molto facile pensare che il risultato sia 15. Ma non lo è!</p><p>Quando viene chiamata <code>multiply()</code>, l'esecuzione di &nbsp;<code>main()</code> viene messa in pausa e ora la memoria viene allocata per l'esecuzione di <code>multiply()</code>. Dopo che l'esecuzione è completata, la memoria allocata a &nbsp;<code>multiply()</code> viene deallocata.</p><p>Pertanto, sebbene <code>c</code> ( locale a <code>main()</code>) conservi l'indirizzo del prodotto, <strong>non c'è garanzia</strong> che il dato sia ancora presente visto che la memoria è stata deallocata.</p><p>Quindi significa che i puntatori non possono essere ritornati da una funzione? No!</p><p>Possiamo fare due cose. Conservare l'indirizzo nello <a href="https://it.wikipedia.org/wiki/Gestione_della_memoria">heap</a> o sezione globale oppure dichiarare la variabile statica (<code>static</code>) in modo che il suo valore persista.</p><p>Le variabili statiche possono essere create semplicemente usando la <em>parola chiave</em> <code>static</code> prima del tipo di dato in fase di dichiarazione della variabile.</p><p>Per conservare indirizzi nello heap, possiamo usare le funzioni di libreria <code>malloc()</code> e <code>calloc()</code> che allocano memoria dinamicamente.</p><p>Il programma seguente spiega entrambi i metodi, che ritornano il risultato di 15.</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

/* Usando malloc() */

int* multiply(int *a, int *b){
  int *c = malloc(sizeof(int));
  *c = *a * *b;
  return c;
}

main(){
  int a= 3, b = 5;
  int *c = multiply (&amp;a,&amp;b);
  printf("Prodotto = %d",*c);
}

/* Usando la parola chiave static */
#include &lt;stdio.h&gt;

int* multiply(int *a, int *b){
  static int c;
  c = *a * *b;
  return &amp;c;
}

main(){
  int a= 3, b = 5;
  int *c = multiply (&amp;a,&amp;b);
  printf("Prodotto = %d",*c);
}
</code></pre><h3 id="4-puntatore-a-funzione"><strong><strong>4. </strong>Puntatore a Funzione</strong></h3><p>Come un puntatore a diversi tipi di dati, abbiamo anche un puntatore a funzione.</p><p>Un puntatore a funzione (<strong><strong>function pointer</strong>)</strong> conserva l'indirizzo di una funzione. Tuttavia non punta ad alcun dato. Punta alla prima istruzione nella funzione.</p><p>La sintassi per dichiarare un puntatore a funzione è la seguente:</p><pre><code class="language-c"> /* Dichiarazione di un funzione */
tipoRitornato nomeFunzione(tipoParametro1, tipoParametro2, ...);

 /* Dichiarazione di un puntatore a funzione */
tipoRitornato (*nomePuntatore)(tipoParametro1, tipoParametro2, ...);
nomePuntatore = &amp;nomeFunzione; /* oppure nomePuntatore = nomefunzione; */
</code></pre><p>L'esempio che segue chiarisce:</p><pre><code class="language-c">int* multiply(int *a, int *b)
{
    int *c = malloc(sizeof(int));
    *c = *a * *b;
    return c;
}

main()
{ 
    int a=3,b=5;
    int* (*p)(int*, int*) = &amp;multiply; /* oppure int* (*p)(int*, int*) = multiply; */
    int *c = (*p)(&amp;a,&amp;b); /* oppure int *c = p(&amp;a,&amp;b); */
    printf("Prodotto = %d",*c);
}
</code></pre><p>La dichiarazione per il puntatore &nbsp;<code>p</code> alla funzione <code>multiply()</code> può essere letto come (seguendo la <a href="http://unixwiz.net/techtips/reading-cdecl.html">precedenza degli operatori</a>) - <em><em><code>p</code> </em>è un puntatore a funzione con due puntatori di tipo <em> <code>int</code>( o</em>ppure due puntatori a<em> <code>int</code>) </em>come parametri che ritorna un puntatore a <em> <code>int</code></em></em>.</p><p>Visto che il nome della funzione è anche un puntatore alla funzione, l'uso di <code>&amp;</code> non è necessario. Inoltre l'eliminazione di <code>*</code> dalla chiamata alla funzione non influisce sul programma.</p><h3 id="5-array-di-puntatori-a-funzioni"><strong><strong>5. Arra</strong>y di Puntatori a Funzioni</strong></h3><p>Abbiamo visto come creare un array di puntatori a &nbsp;<code>int</code>, <code>char</code>, e così via. Allo stesso modo, possiamo creare un array di puntatori a funzione.</p><p>In questo array, ogni elemento conserverà un indirizzo di una funzione, dove tutte le funzioni sono dello stesso tipo. Vale a dire che hanno lo stesso numero di parametri e tipo dato di ritorno.</p><p>Andremo a modificare un programma che abbiamo esaminato in precedenza in questa sezione. Conserveremo gli indirizzi di <code>add()</code>, <code>subtract()</code>, <code>multiply()</code> e <code>divide()</code> in un array facendo una chiamata a funzione tramite indicizzazione.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

void add(float *a, float *b){
 float c = *a + *b;
 printf("L'addizione fornisce %.2f\n",c);
}

void subtract(float *a, float *b){
 float c = *a - *b;
 printf("La sottrazione fornisce %.2f\n",c);
}

void multiply(float *a, float *b){
 float c = *a * *b;
 printf("La moltiplicazione fornisce %.2f\n",c);
}

void divide(float *a, float *b){
 float c = *a / *b;
 printf("La divisione fornisce %.2f\n",c);
}

main(){
    printf("Digita due numeri :\n");
    float a,b;
    scanf("%f %f",&amp;a,&amp;b);
    printf("Cosa vuoi fare con questi numeri?\nAggiungi : a\nSottrai : s\nMoltiplica : m\nDividi : d\n");
    char operation = '0';
    scanf(" %c",&amp;operation);
    void (*p[])(float* , float*) = {add,subtract,multiply,divide};
    printf("\nEseguo...\n\n");
    switch (operation) {
    case 'a':
        p[0](&amp;a,&amp;b);
        break;
    case 's':
        p[1](&amp;a,&amp;b);
        break;
    case 'm':
        p[2](&amp;a,&amp;b);
        break;
    case 'd':
        p[3](&amp;a,&amp;b);
        break;
    default:
        printf("Input non valido!!!\n");

  }

}
</code></pre><p>Qui la dichiarazione può essere letta come - <em><em><code>p</code> </em>è un array di puntatori a funzione con due puntatori <em><code>float</code> </em>come parametri e valore di ritorno <em><code>void</code></em></em>.</p><h3 id="6-puntatore-a-funzione-come-argomento"><strong><strong>6. P</strong>untatore a Funzione come Argomento</strong></h3><p>Come qualsiasi altro puntatore, i puntatori a funzione possono anche essere passati a un'altra funzione, nota come <strong>funzione <strong>callback</strong></strong>. La funzione dalla quale viene passata è nota come <strong>funzione chiamante</strong>.</p><p>Un modo migliore per capire sarebbe dare uno sguardo a <code>qsort()</code>, che è una funzione integrata in C. Viene usata per ordinare un array di interi, stringhe, strutture e così via. La dichiarazione per <code>qsort()</code> è:</p><pre><code class="language-c">void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *));
</code></pre><p><code>qsort()</code> riceve quattro argomenti:</p><ol><li>un puntatore <code>void</code> verso l'inizio dell'array da ordinare</li><li>il numero di elementi</li><li>la dimensione di ciascun elemento</li><li>un puntatore a funzione che riceve due puntatori <code>void</code> come argomenti e ritorna un <code>int</code></li></ol><p>Il puntatore a funzione punta a una <em>funzione di confronto</em> che ritorna un intero maggiore di zero se il primo argomento è maggiore del secondo, un intero minore di zero se il secondo argomento è maggiore del primo e zero se sono uguali.</p><p>Il programma seguente mostra il suo utilizzo:</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int compareIntegers(const void *a, const void *b)
{
  const int *x = a;
  const int *y = b;
  return *x - *y;
}

main(){

  int myArray[] = {97,59,2,83,19,97};
  int numberOfElements = sizeof(myArray) / sizeof(int);

  printf("Prima dell'ordinamento - \n");
  for(int i = 0; i &lt; numberOfElements; i++)
   printf("%d ", *(myArray + i));

  qsort(myArray, numberOfElements, sizeof(int), compareIntegers);

  printf("\n\nDopo l'ordinamento - \n");
  for(int i = 0; i &lt; numberOfElements; i++)
    printf("%d ", *(myArray + i));
 }

/* Output */

Prima dell'ordinamento -
97 59 2 83 19 97

Dopo l'ordinamento -
2 19 59 83 97 97
</code></pre><p>Visto che il nome di una funzione è esso stesso un puntatore, possiamo passare <code>compareIntegers</code> come quarto argomento.</p><h2 id="d-strutture-1"><strong><strong>D. Stru</strong>t<strong>ture</strong></strong></h2><h3 id="1-puntatore-a-struttura"><strong><strong>1. P</strong>untatore a Struttura</strong></h3><p>Come i puntatori a intero, ad array e a funzione, abbiamo anche puntatori a struttura.</p><pre><code class="language-c">struct records {
    char name[20];
    int roll;
    int marks[5];
    char gender;
};

struct records student = {"Alex", 43, {76, 98, 68, 87, 93}, 'M'};

struct records *ptrStudent = &amp;student;
</code></pre><p>Qui abbiamo dichiarato un puntatore <code>ptrStudent</code> di tipo <code>struct records</code> e abbiamo assegnato l'indirizzo di <code>student</code> a <code>ptrStudent</code>.</p><p><code>ptrStudent</code> conserva l'indirizzo base di &nbsp;<code>student</code>, che è l'indirizzo base del primo membro della struttura. Incrementando di 1 si incrementerebbe l'indirizzo di <code>sizeof(student)</code> byte.</p><pre><code class="language-c">printf("Indirizzo della struttura = %d\n", ptrStudent);
printf("Indirizzo del membro `name` = %d\n", &amp;student.name);
printf("L'incremento di 1 risulta in %d\n", ptrStudent + 1);

/* Output */
Indirizzo della struttura = 6421984
Indirizzo del membro `name` = 6421984
L'incremento di 1 risulta in 6422032
</code></pre><p>Possiamo accedere ai membri di <code>student</code> usando <code>ptrStudent</code> in due modi: con il nostro vecchio amico<code>*</code> oppure usando <code>-&gt;</code> ( <strong><strong>infix o</strong>ppure<strong> operator</strong>e freccia</strong>).</p><p>Con <code>*</code>, continueremo a usare <code>.</code>(operatore punto) laddove con <code>-&gt;</code> non avremo bisogno dell'operatore punto.</p><pre><code class="language-c">printf("Nome senza usare ptrStudent : %s\n", student.name);
printf("Nome usando ptrStudent e * : %s\n", ( *ptrStudent).name);
printf("Nome usando ptrStudent e -&gt; : %s\n", ptrStudent-&gt;name);

/* Output */
Nome senza usare ptrStudent: Alex
Nome usando ptrStudent e *: Alex
Nome usando ptrStudent e -&gt;: Alex
</code></pre><p>Allo stesso modo possiamo accedere e modificare anche altri membri. Nota che le parentesi sono necessarie quando si usa <code>*</code> visto che l'operatore punto (<code>.</code>) ha maggiore precedenza rispetto a <code>*</code>.</p><h3 id="2-array-di-strutture"><strong><strong>2. Array </strong>di<strong> Stru</strong>t<strong>ture</strong></strong></h3><p>Possiamo creare un array di tipo <code>struct records</code> e usare un puntatore per accedere agli elementi e ai loro membri.</p><pre><code class="language-c">struct records students[10];

 /* Puntatore al primo elemento (struttura) dell'array */
struct records *ptrStudents1 = &amp;students;

 /* Puntatore a un array di 10 struct records */
struct records (*ptrStudents2)[10] = &amp;students;
</code></pre><p>Nota che <code>ptrStudent1</code> è un puntatore a <code>student[0]</code> laddove <code>ptrStudent2</code> è un puntatore all'intero array di 10 <code>struct records</code>. Aggiungendo 1 a <code>ptrStudent1</code> punterebbe a <code>student[1]</code>.</p><p>Possiamo usare <code>ptrStudent1</code> con un ciclo per iterare sugli elementi e i loro membri.</p><pre><code class="language-c">
for( int i = 0; i &lt;  10; i++)
  printf("%s, %d\n", ( ptrStudents1 + i)-&gt;name, ( ptrStudents1 + i)-&gt;roll);
</code></pre><h3 id="3-puntatore-a-struttura-come-argomento"><strong><strong>3. P</strong>untatore<strong> </strong>a<strong> Stru</strong>t<strong>tur</strong>a come Argomento</strong></h3><p>Possiamo anche passare l'indirizzo di una variabile di tipo struttura a una funzione.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

struct records {
    char name[20];
    int roll;
    int marks[5];
    char gender;
};

main(){
 struct records students = {"Alex", 43, {76, 98, 68, 87, 93}, 
'M'};
 printRecords(&amp;students);
}

void printRecords( struct records *ptr){
  printf("Name: %s\n", ptr-&gt;name);
  printf("Roll: %d\n", ptr-&gt;roll);
  printf("Gender: %c\n", ptr-&gt;gender);
  for( int i = 0; i &lt; 5; i++)
   printf("Marks in %dth subject: %d\n", i, ptr-&gt;marks[i]);
}

 /* Output */
Name: Alex
Roll: 43
Gender: M
Marks in 0th subject: 76
Marks in 1th subject: 98
Marks in 2th subject: 68
Marks in 3th subject: 87
Marks in 4th subject: 93
</code></pre><p>Nota che la struttura <code>struct records</code> viene dichiarata all'esterno di <code>main()</code>. Questo per assicurarsi che sia disponibile globalmente e possa essere usata da <code>printRecords()</code>.</p><p>Se la struttura venisse definita all'interno di <code>main()</code>, il suo ambito sarebbe limitato a <code>main()</code>. Inoltre una struttura <strong>deve</strong> essere dichiarata prima della dichiarazione della funzione.</p><blockquote>Come per le strutture, possiamo avere puntatori a union e possiamo accedere ai membri tramite l'operatore freccia(<code>-&gt;</code>).</blockquote><!--kg-card-begin: markdown--><p><a name="puntatore-a-puntatore"></a></p>
<h2 id="epuntatoreapuntatore">E. Puntatore a Puntatore</h2>
<!--kg-card-end: markdown--><p>Finora abbiamo esaminato puntatori per diversi tipi di dato, array, stringhe, funzioni, strutture e unioni.</p><p>La domanda che sorge spontanea è - ma un puntatore a puntatore?</p><p>Ho buone notizie per te! Esistono anche quelli.</p><pre><code class="language-c">int var = 6;
int *ptr_var = &amp;var;

printf("Indirizzo di var = %d\n", ptr_var);
printf("Indirizzo di ptr_var = %d\n", &amp;ptr_var);

/* Output */
Indirizzo di var = 6422036
Indirizzo di ptr_var = 6422024
</code></pre><p>Per conservare l'indirizzo della variabile <code>var</code> di tipo <code>int</code>, abbiamo un puntatore a &nbsp;<code>int</code> <code>ptr_var</code>. Avremmo bisogno di un altro puntatore per conservare l'indirizzo di <code>ptr_var</code>.</p><p>Visto che <code>ptr_var</code> è di tipo <code>int *</code>, per conservare il suo indirizzo avremmo dovuto creare un puntatore a <code>int *</code>. Il codice che segue mostra come deve essere fatto.</p><pre><code class="language-c">int * *ptr_ptrvar = &amp;ptr_var; /* oppure int* *ppvar oppure int **ppvar */
</code></pre><p>Possiamo usare <code>ptr_ptrvar</code> per accedere all'indirizzo di <code>ptr_var</code> e usare la doppia dereferenziazione per accedere al valore di <code>var</code>.</p><pre><code class="language-c">printf("Indirizzo di ptr_var = %d\n", ptr_ptrvar);
printf("Indirizzo di var = %d\n", *ptr_ptrvar);
printf("Valore di var = %d\n", *(*ptr_ptrvar));

/* Output */
Indirizzo di ptr_var = 6422024
Indirizzo di var = 6422036
Valore di var = 6
</code></pre><p>Non sono richieste le parentesi quando si dereferenzia <code>ptr_ptrvar</code>, ma è buona pratica usarle. Possiamo creare un altro puntatore a <code>ptr_ptrptrvar</code>, che conserverà l'indirizzo di <code>ptr_ptrvar</code>.</p><p>Visto che <code>ptr_ptrvar</code> è di tipo <code>int**</code>, la dichiarazione di <code>ptr_ptrptrvar</code> sarà:</p><pre><code class="language-c">int** *ptr_ptrptrvar = &amp;ptr_ptrvar;
</code></pre><p>Possiamo ancora accedere a &nbsp;<code>ptr_ptrvar</code>, <code>ptr_var</code> e <code>var</code> usando <code>ptr_ptrptrvar</code>.</p><pre><code class="language-c">printf("Indirizzo di ptr_ptrvar = %d\n", ptr_ptrptrvar);
printf("Valore per ptr_ptrvar = %d\n",*ptr_ptrptrvar);
printf("Indirizzo di ptr_var = %d\n", *ptr_ptrptrvar);
printf("Valore per ptr_var = %d\n", *(*ptr_ptrptrvar));
printf("Indirizzo di var = %d\n", *(*ptr_ptrptrvar));
printf("Valore per var = %d\n", *(*(*ptr_ptrptrvar)));

/* Output */
Indirizzo di ptr_ptrvar = 6422016
Valore per ptr_ptrvar = 6422024
Indirizzo di ptr_var = 6422024
Valore per ptr_var = 6422036
Indirizzo di var = 6422036
Valore per var = 6
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/08/1534533aefc96880ba542070037d147b.gif" class="kg-image" alt="Pointer to Pointer" width="600" height="400" loading="lazy"></figure><p>Se modifichiamo il valore di un qualsiasi puntatore usando <code>ptr_ptrptrvar</code> oppure <code>ptr_ptrvar</code>, il puntatore non punterebbe più alla variabile.</p><!--kg-card-begin: markdown--><p><a name="conclusione"></a></p>
<h2 id="fconclusione">F. Conclusione</h2>
<!--kg-card-end: markdown--><p>Bene! Sì, abbiamo finito. Siamo partiti dai puntatori e abbiamo finito con i puntatori (per così dire). Non dicono che la <em>curva di apprendimento è un cerchio?</em></p><p>Cerca di ricapitolare tutti i sotto argomenti che hai letto. Se li ricordi, ben fatto! Rileggi quelli che non riesci a ricordare.</p><p>Questo articolo è terminato, ma non dovresti smettere con i puntatori, fai esperimenti. Successivamente, potresti dare un'occhiata alla <em>Allocazione dinamica della memoria (<em>Dynamic Memory Allocation</em>)</em> per conoscere meglio i puntatori<em><em>.</em></em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Come Scrivere Unit Test per Funzioni Python ]]>
                </title>
                <description>
                    <![CDATA[ Questa guida ti insegnerà come scrivere unit test per funzioni Python. Ma perché dovresti prendere in considerazione la scrittura di unit test? Quando si lavora su un grande progetto, spesso dovrai aggiornare certi moduli e svolgere operazioni di refactoring sul codice secondo necessità. Tuttavia queste modifiche potrebbero avere conseguenze indesiderate ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/come-scrivere-unit-test-per-funzioni-python/</link>
                <guid isPermaLink="false">645dfdc7410a4d066241aff7</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 29 May 2023 09:18:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/05/cover-image-unit-tests-python.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/how-to-write-unit-tests-for-python-functions/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Write Unit Tests for Python Functions</a>
      </p><p>Questa guida ti insegnerà come scrivere unit test per funzioni Python. Ma perché dovresti prendere in considerazione la scrittura di unit test?		</p><p>Quando si lavora su un grande progetto, spesso dovrai aggiornare certi moduli e svolgere operazioni di refactoring sul codice secondo necessità. Tuttavia queste modifiche potrebbero avere conseguenze indesiderate su altri moduli che usano al loro interno il modulo aggiornato. Questo talvolta può rompere delle funzionalità esistenti.</p><p>Come sviluppatore, dovresti testare il tuo codice per assicurarti che tutti i moduli in un'applicazione funzionino a dovere. Gli unit test ti consentono di verificare se piccole, isolate, unità di codice funzionano correttamente e fanno sì che tu possa correggere incongruenze che potrebbero sorgere dopo aggiornamenti e operazioni di refactoring. </p><p>Questa guida ti aiuterà a iniziare con lo unit testing in Python. Imparerai come usare il modulo Python integrato <code>unittest</code> per impostare ed eseguire gli unit test e scrivere casi di test per funzioni Python. Imparerai anche come testare funzioni che danno eccezioni.</p><p>Iniziamo!</p><h2 id="test-in-python-primi-passi"><strong><strong>Test in Python – </strong>Primi Passi</strong></h2><p>Inizieremo definendo una <a href="https://www.freecodecamp.org/news/functions-in-python-a-beginners-guide/">funzione Python</a> e scriveremo degli unit test per verificare se funziona come previsto. Per focalizzarci su come impostare gli unit test, utilizzeremo una semplice funzione, <code>is_prime()</code> , che riceve un numero e verifica se è un numero primo oppure no.</p><pre><code class="language-python">import math

def is_prime(num):
    '''Verifica se num è un numero primo o no.'''
    for i in range(2, int(math.sqrt(num))+1):
        if num % i == 0:
            return False
    return True
</code></pre><p>Facciamo partire il REPL di Python, chiamiamo la funzione <code>is_prime()</code> con alcuni argomenti e verifichiamo i risultati.</p><pre><code class="language-python">&gt;&gt;&gt; from prime_number import is_prime
&gt;&gt;&gt; is_prime(3)
True
&gt;&gt;&gt; is_prime(5)
True
&gt;&gt;&gt; is_prime(12)
False
&gt;&gt;&gt; is_prime(8)
False
&gt;&gt;&gt; assert is_prime(7) == True</code></pre><p>Puoi anche usare l'istruzione <code>assert</code> per verificare che <code>is_prime()</code> restituisca il valore booleano previsto, come mostrato sopra. Se il valore di ritorno della funzione è diverso da quello previsto, viene sollevata un'eccezione <code>AssertionError</code>.</p><p>Questo tipo di <strong>test manuali</strong> <em>non è efficiente</em> qualora tu voglia verificare in modo esaustivo la tua funzione con un elenco di argomenti molto più grande. Potresti voler impostare test automatici che eseguono e validano il risultato della funzione contro casi di test definiti nella suite di test.</p><h2 id="come-usare-il-modulo-python-unittest"><strong>Come Usare il Modulo Python<strong> <code>unittest</code></strong></strong></h2><p>Python è dotato del modulo <code>unittest</code> che ti consente di configurare test automatizzati per le funzioni e le classi nella tua applicazione. La procedura generica per impostare unit test in Python è la seguente:</p><pre><code class="language-python"># &lt;nome-modulo&gt;.py

import unittest
from &lt;modulo&gt; import &lt;funzione_da_testare&gt;
# tutte le voci tra &lt;&gt; sono segnaposti

class TestClass(unittest.TestCase):
	def test_&lt;nome_1&gt;(self):
		# verifica funzione_da_testare

	def test_&lt;nome_2&gt;(self):
		# verifica funzione_da_testare
	:
	:
	:

	def test_&lt;nome_n&gt;(self):
		# verifica funzione_da_testare
</code></pre><p>Il codice qui sopra in <code>&lt;nome-modulo&gt;.py</code> fa quanto segue:</p><ul><li>Importa il modulo integrato di Python <code>unittest</code>.</li><li>Importa la funzione Python da testare dal modulo nel quale è definita, <code>&lt;modulo&gt;</code>.</li><li>Crea una classe di test (<code>TestClass</code>) che eredita dalla classe <code>unittest.TestCase</code>.</li><li>Ciascun test che dovrebbe essere eseguito andrà definito come metodo all'interno della classe di test.</li><li>💡 <strong><strong>Not</strong>a</strong>: Affinché il modulo <code>unittest</code> possa identificare questi metodi come test ed eseguirli, i nomi di questi metodi dovrebbero iniziare con &nbsp;<code>test_</code>.</li><li>La classe <code>TestCase</code> del modulo <code>unittest</code> fornisce utili metodi di asserzione per verificare se la funzione oggetto di test ritorni i valori previsti.</li></ul><p>I più comuni metodi di asserzione sono elencati qui sotto, ne useremo alcuni in questo tutorial.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>METODO</th>
<th>DESCRIZIONE</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>assertEqual(valore_atteso, valore_effettivo)</code></td>
<td>Asserisce che <code>valore_atteso == valore_effettivo</code></td>
</tr>
<tr>
<td><code>assertTrue(risultato)</code></td>
<td>Asserisce che <code>bool(risultato)</code> è <code>True</code></td>
</tr>
<tr>
<td><code>assertFalse(risultato)</code></td>
<td>Asserisce che <code>bool(risultato)</code> è <code>False</code></td>
</tr>
<tr>
<td><code>assertRaises(eccezione, funzione, *args, **kwargs)</code></td>
<td>Asserisce che <code>funzione(*args, **kwargs)</code> <br>solleva la specifica <code>eccezione</code></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>📑 Per un elenco completo dei metodi di asserzione, fai riferimento alla <a href="https://docs.python.org/3/library/unittest.html">documentazione di unittest</a>.</p><p>Per eseguire questi test, dovresti eseguire unittest come modulo principale, usando il seguente comando:</p><pre><code class="language-bash">$ python -m unittest &lt;nome-modulo&gt;.py</code></pre><p>Possiamo aggiungere il costrutto condizionale <code>if __name__=='__main__'</code> per eseguire &nbsp;<code>unittest</code> come modulo 'main'.</p><pre><code class="language-python">if __name__=='__main__':
	unittest.main()</code></pre><p>Aggiungere il codice condizionale qui sopra, ti consente di eseguire i test direttamente eseguendo il modulo che contiene i test.</p><pre><code class="language-bash">$ python &lt;nome-modulo&gt;.py</code></pre><h2 id="come-definire-casi-di-test-per-funzioni-python"><strong>Come Definire Casi di Test per Funzioni Python</strong></h2><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/10/unittesting-101.png" class="kg-image" alt="unittesting-101" width="600" height="400" loading="lazy"></figure><p><br>In questa sezione, scriveremo unit test per la funzione <code>is_prime()</code> usando la sintassi che abbiamo appreso.<br><br>Per verificare che la funzione <code>is_prime()</code> restituisca un booleano possiamo usare i metodi <code>assertTrue()</code> e <code>assertFalse()</code>. Definiamo quattro metodi di test all'interno della classe <code>TestPrime</code> che eredita da <code>unittest.TestCase</code>.</p><pre><code class="language-python">import unittest

# importa la funzione is_prime
from prime_number import is_prime


class TestPrime(unittest.TestCase):

	def test_two(self):
        self.assertTrue(is_prime(2))
    
    def test_five(self):
    	self.assertTrue(is_prime(5))
    
    def test_nine(self):
    	self.assertFalse(is_prime(9))
    
    def test_eleven(self):
    	self.assertTrue(is_prime(11))
        
        
if __name__=='__main__':
	unittest.main()</code></pre><pre><code class="language-bash">$ python test_prime.py</code></pre><p>Nel risultato seguente, '.' indica un test che ha avuto successo.</p><pre><code>Output
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK</code></pre><p>Nel codice qui sopra ci sono quattro metodi di test, ognuno dei quali verifica un determinato input. Puoi invece definire un singolo metodo di test che asserisce se il risultato sia corretto, per tutti e quattro gli input.</p><pre><code class="language-python">import unittest

from prime_number import is_prime


class TestPrime(unittest.TestCase):

	def test_prime_not_prime(self):
        self.assertTrue(is_prime(2))
        self.assertTrue(is_prime(5))
        self.assertFalse(is_prime(9))
        self.assertTrue(is_prime(11))</code></pre><p>Dopo l'esecuzione del modulo <code>test_prime</code>, vediamo che è stato eseguito con successo un test. Se uno qualunque dei metodi di asserzione avesse sollevato un'eccezione, allora il test sarebbe fallito.</p><pre><code class="language-bash">$ python test_prime.py</code></pre><pre><code>Output
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK</code></pre><h2 id="come-scrivere-unit-test-per-verificare-eccezioni"><strong>Come Scrivere Unit Test per Verificare Eccezioni</strong></h2><p>Nella sezione precedente, abbiamo testato la funzione <code>is_prime()</code> con numeri primi e non primi come input. Nello specifico erano tutti numeri positivi interi.</p><p>Non abbiamo ancora imposto che gli argomenti per la chiamata della funzione <code>is_prime()</code> siano interi positivi. Puoi usare il type hinting per imporre tipi o sollevare eccezioni per input non validi.</p><p>Nel test della funzione <code>is_prime()</code>, non abbiamo tenuto conto di quanto segue:</p><ul><li>Se l'argomento è un valore a virgola mobile, <code>is_prime()</code> sarebbe comunque eseguita e restituirebbe <code>True</code> o <code>False</code>, il che non è corretto.</li><li>Per argomenti di altro tipo, ad esempio la stringa 'cinque' invece che il numero 5, la funzione dà un errore <strong><strong><code>TypeError</code></strong></strong>.</li><li>Se l'argomento è un intero negativo, allora la funzione <code>math.sqrt()</code> dà un <strong><strong><code>ValueError</code></strong></strong>. Le radici di tutti i numeri reali (positivi, negativi o zero) sono sempre non negative. Quindi la radice quadrata è definita solo per numeri non negativi.</li></ul><p>Verifichiamo quanto sopra affermato eseguendo qualche esempio nel REPL di Python.</p><pre><code class="language-python">&gt;&gt;&gt; from prime_number import is_prime

&gt;&gt;&gt; is_prime('five')
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in &lt;module&gt;
File "/home/bala/unit-test-1/prime_number.py", line 5, in is_prime
for i in range(2,int(math.sqrt(num))+1):
TypeError: must be real number, not str

&gt;&gt;&gt; is_prime(-10)
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in &lt;module&gt;
File "/home/bala/unit-test-1/prime_number.py", line 5, in is_prime
for i in range(2,int(math.sqrt(num))+1):
ValueError: math domain error

&gt;&gt;&gt; is_prime(2.5)
True</code></pre><h3 id="come-sollevare-eccezioni-per-input-non-validi"><strong>Come Sollevare Eccezioni per Input Non Validi</strong></h3><p>Per risolvere quanto sopra, validiamo il valore usato nella chiamata della funzione per <code>num</code> e solleviamo un'eccezione quando necessario.</p><ul><li>Verifichiamo se <code>num</code> sia un intero. In caso positivo, si procede alla prossima verifica, altrimenti viene sollevata un'eccezione <code>TypeError</code>.</li><li>Verifichiamo se <code>num</code> sia un numero negativo. Se lo è viene sollevata un'eccezione <code>ValueError</code>.</li></ul><p>Dopo la modifica della definizione della funzione per validare l'input e sollevare eccezioni il codice sarà:</p><pre><code class="language-python">import math

def is_prime(num):
    '''Verifica se num sia un numero primo oppure no.'''
    # solleva TypeError per un tipo in input non valido
    if type(num) != int:
        raise TypeError('il tipo di num non è non valido')
    # solleva ValueError per un valore negativo
    if num &lt; 0:
        raise ValueError('Verifica il valore di num; num è un valore non negativo?')
    # se l'input è valido si procede per verificare se num sia un numero primo
    for i in range(2, int(math.sqrt(num))+1):
        if num % i == 0:
        	return False
    return True</code></pre><p>Ora che abbiamo modificato la funzione affinché sollevi eccezioni <code>ValueError</code> e <code>TypeError</code> per input non validi, il prossimo passo è di verificare se queste eccezioni vengono sollevate.</p><h2 id="come-usare-il-metodo-assertraises-per-testare-eccezioni"><strong>Come Usare il Metodo<strong> <code>assertRaises()</code> </strong>per Testare Eccezioni</strong></h2><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/10/test-exceptions.png" class="kg-image" alt="test-exceptions" width="600" height="400" loading="lazy"></figure><p>Nella definizione della classe <code>TestPrime</code>, aggiungiamo metodi per verificare se le eccezioni vengono sollevate.</p><p>Definiamo i metodi <code>test_typeerror_1()</code> e <code>test_typeerror_2()</code> per verificare se l'eccezione <code>TypeError</code> viene sollevata, e il metodo <code>test_valueerror()</code> per verificare se viene sollevata l'eccezione <code>ValueError</code>.</p><p>📌 Per chiamare il metodo <code>assertRaises()</code> , possiamo usare la seguente sintassi generale:</p><pre><code class="language-python">def test_exception(self):
    self.assertRaises(nome-eccezione,nome-funzione,args)</code></pre><p>Possiamo anche usare il gestore di contesto con la seguente sintassi (che adotteremo nell'esempio successivo):</p><pre><code class="language-python">def test_exception(self):
    with self.assertRaises(nome-eccezione):
        nome-funzione(args)</code></pre><p>Aggiungendo i metodi di test per la verifica delle eccezioni, il codice sarà:</p><pre><code class="language-python">import unittest

from prime_number import is_prime


class TestPrime(unittest.TestCase):

	def test_prime_not_prime(self):
        self.assertTrue(is_prime(2))
        self.assertTrue(is_prime(5))
        self.assertFalse(is_prime(9))
        self.assertTrue(is_prime(11))
    
    def test_typeerror_1(self):
        with self.assertRaises(TypeError):
        	is_prime(6.5)
    
    def test_typeerror_2(self):
        with self.assertRaises(TypeError):
        	is_prime('five')
    
    def test_valueerror(self):
        with self.assertRaises(ValueError):
        	is_prime(-4)
            
if __name__=='__main__':
	unittest.main()</code></pre><p>Eseguiamo il modulo <code>test_prime</code> e osserviamo il risultato:</p><pre><code class="language-bash">$ python test_prime.py</code></pre><pre><code>Output
....
----------------------------------------------------------------------
Ran 4 tests in 0.002s
OK</code></pre><p>Nel codice degli esempi che abbiamo scritto fino a ora tutti i test hanno avuto successo. Modifichiamo uno dei metodi, diciamo <code>test_typeerror_2()</code>, in questo modo:</p><pre><code class="language-python">def test_typeerror_2(self):
    with self.assertRaises(TypeError):
    	is_prime(5)</code></pre><p>Chiamiamo la funzione <code>is_prime()</code> con il numero 5 come argomento. In questo caso, 5 è un input valido per il quale la funzione ritorna <code>True</code>. Pertanto la funzione non dà <code>TypeError</code>. Quando eseguiamo il test nuovamente, vedremo che ci sarà un test che fallisce.</p><pre><code class="language-bash">$ python test_prime.py</code></pre><pre><code>Output

..F.
======================================================================
FAIL: test_typeerror_2 (__main__.TestPrime)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_prime.py", line 17, in test_typeerror_2
is_prime(5)
AssertionError: TypeError not raised
----------------------------------------------------------------------
Ran 4 tests in 0.003s
FAILED (failures=1)</code></pre><h2 id="conclusione"><strong><strong>Conclusion</strong>e</strong></h2><p>Grazie per avere letto fino a qui! 😄 Spero che questo tutorial ti abbia aiutato a comprendere le basi per eseguire unit test in Python.</p><p>Hai imparato a impostare i test e verificare se una funzione si comporta come previsto oppure solleva un'eccezione — tutto questo usando il modulo integrato di Python <code>unittest</code>.</p><p>Continua a programmare, e ci vediamo al prossimo tutorial!👩🏽‍💻</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ L'Ambito di una Variabile in C – Ambito Locale e Globale Spiegato ]]>
                </title>
                <description>
                    <![CDATA[ Nella programmazione, dovrai spesso avere a che fare con l'ambito di una variabile. L'ambito di una variabile determina se è possibile o meno accedervi e modificarla all'interno di un blocco specifico di codice. In questo tutorial, imparerai l'ambito di una variabile nel linguaggio di programmazione C. Vedrai alcuni esempi di ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/lambito-di-una-variabile-in-c/</link>
                <guid isPermaLink="false">643d4d1388ecf5067c89171b</guid>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 15 May 2023 17:08:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/04/ambitodiunavariabileinc.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/scope-of-variables-in-c-local-and-global-scope-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Variable Scope in C – Local and Global Scope Explained</a>
      </p><p>Nella programmazione, dovrai spesso avere a che fare con l'ambito di una variabile. L'ambito di una variabile determina se è possibile o meno accedervi e modificarla all'interno di un blocco specifico di codice.</p><p>In questo tutorial, imparerai l'ambito di una variabile nel linguaggio di programmazione C. Vedrai alcuni esempi di codice per aiutarti a comprendere le differenze tra variabili locali e globali.</p><h2 id="cos-l-ambito-di-una-variabile">Cos'è l'ambito di una variabile<strong>?</strong></h2><p>Prima di proseguire per conoscere l'ambito locale e globale di una variabile, capiamo cosa significa <em>ambito.</em></p><blockquote><em>In termini semplici, l'ambito di una variabile è il suo</em> tempo di vita nel programma.</blockquote><p>Questo vuol dire che l'ambito di una variabile è il blocco di codice all'interno dell'intero programma dove la variabile è stata dichiarata, usata e può essere modificata.</p><p>Nella sezione successiva, imparerai cos'è l'ambito locale delle variabili.</p><h2 id="ambito-locale-delle-variabili-in-c-blocchi-annidati">Ambito Locale delle Variabili in C – Blocchi Annidati</h2><p>In questa sezione, imparerai come funzionano le variabili locali in C. Prima scriveremo del codice per un paio di esempi, quindi generalizzeremo il principio di ambito.</p><p>▶ Ecco il primo esempio:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main() 
{
    int my_num = 7;
    {
        //aggiunge 10 a my_num
        my_num = my_num +10;
        //oppure più brevemente my_num +=10
        printf("my_num è %d",my_num);
    }
    
    return 0;
}
</code></pre><p>Cerchiamo di capire cosa fa il programma qui sopra:</p><p>In C, un blocco di codice è delimitato da parentesi graffe: <code>{}</code>. Le parentesi graffe di apertura e chiusura indicano rispettivamente l'inizio e la fine di un blocco.</p><ul><li>La funzione <code>main()</code> ha una variabile di tipo intero <code>my_num</code> che viene inizializzata con il valore 7 nel blocco <em>più esterno</em>. </li><li>C'è un blocco <em>più interno</em> che cerca di aggiungere 10 alla variabile <code>my_num</code>.</li></ul><p>Ora, compilando ed eseguendo il programma qui sopra, si ottiene il risultato:</p><pre><code>//Output

my_num è 17</code></pre><p>Puoi notare quanto segue:</p><ul><li>Il blocco più interno è in grado di accedere al valore di <code>my_num</code> che è stato dichiarato nel blocco più esterno e modificarlo aggiungendo 7 al valore contenuto.</li><li>Il valore di <code>my_num</code> ora è 17, come indicato nel risultato.</li></ul><h2 id="ambito-locale-delle-variabili-in-c-blocchi-annidati-esempio-2">Ambito Locale delle Variabili in C – Blocchi Annidati Esempio 2</h2><p>▶ Ecco un altro esempio sull'argomento:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main() 
{
    int my_num = 7;
    {
        int new_num = 10;
    } 
    printf("new_num è %d",new_num); //questa è la riga 9
    return 0;
}</code></pre><ul><li>In questo programma, la funzione <code>main()</code> ha una variabile di tipo intero <code>my_num</code> nel blocco <em>più esterno</em>.</li><li>Un'altra variabile, <code>new_num</code> viene inizializzata nel blocco <em>più interno</em>, che è annidato nel blocco <em>più esterno</em>.</li><li>Stiamo cercando di accedere e stampare il valore della variabile del blocco <em>più interno</em> <code>new_num</code> dal blocco <em>più esterno</em>.</li></ul><p>Se cerchi di compilare il codice qui sopra, noterai che la compilazione non va a buon fine, e otterrai il seguente errore, il cui messaggio tradotto è "<code>errore: 'new_num' non dichiarata, (usata per la prima volta in questa funzione)</code>":</p><pre><code>Line   Message
9      error: 'new_num' undeclared (first use in this function)</code></pre><blockquote>Questo perché la variabile <code>new_num</code> è stata dichiarata nel blocco più interno e il suo ambito è limitato al suddetto blocco. In altre parole, è locale rispetto al blocco più interno e non può essere utilizzata nel blocco più esterno.</blockquote><p>In base alle osservazioni qui sopra, scriviamo il seguente principio generico per l'ambito locale delle variabili:</p><pre><code class="language-C">{
    /BLOCCO PIU' ESTERNO/
    
      {
        
        
        //Il contenuto del blocco più esterno che si trova immediatamente prima dell'inizio di questo blocco
        //è ACCESSIBILE qui
        
        /BLOCCO PIU' INTERNO/
        
        
      }
     
       //Il contenuto del blocco più interno NON è accessibile qui
 }
</code></pre><h2 id="ambito-locale-delle-variabili-in-c-blocchi-diversi">Ambito Locale delle Variabili in C – Blocchi Diversi</h2><p>Nell'esempio precedente, hai imparato che l'accesso da un blocco più esterno alle variabili annidate in un blocco più interno non è consentito.</p><p>In questa sezione, imparerai circa l'ambito locale di variabili dichiarate in blocchi diversi.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main()
{
    int my_num = 7;
    printf("%d",my_num);
    my_func();
    return 0;
}

void my_func()
{
    printf("%d",my_num);
}</code></pre><p>Nell'esempio qui sopra:</p><ul><li>La variabile di tipo intero <code>my_num</code> è dichiarata all'interno della funzione <code>main()</code>.</li><li>All'interno della funzione <code>main()</code>, il valore di <code>my_num</code> viene stampato.</li><li>C'è un'altra funzione, <code>my_func(),</code> che cerca di accedere e stampare il valore di <code>my_num</code>.</li><li>Quando inizia l'esecuzione del programma con la funzione <code>main()</code>, c'è una chiamata a <code>my_func()</code> all'interno della funzione <code>main()</code>.</li></ul><p>▶ Ora compila ed esegui il programma qui sopra. Otterrai il messaggio di errore qui sotto (traduzione: "<code>errore 'my_num' non dichiarata (primo uso in questa funzione)</code>):</p><pre><code>Line   Message
13     error: 'my_num' undeclared (first use in this function)</code></pre><p>Se noti, nella riga 13, la funzione <code>my_func()</code> tenta di accedere alla variabile <code>my_num</code> che è stata dichiarata e inizializzata all'interno della funzione <code>main()</code>.</p><blockquote>Pertanto l'ambito della variabile <code>my_num</code> è confinato alla funzione <code>main()</code>, e si dice che è locale alla funzione <code>main()</code>.</blockquote><p>Possiamo rappresentare genericamente questa nozione di ambito locale come segue:</p><pre><code class="language-C">{

    /BLOCCO 1/
    // da qui non si può accedere al contenuto del BLOCCO 2
    
}


{

    /BLOCCO 2/
    // da qui non si può accedere al contenuto del BLOCCO 1
    
} 
</code></pre><h2 id="ambito-globale-delle-variabili-in-c">Ambito Globale delle Variabili in C</h2><p>Finora, hai imparato a conoscere l'ambito locale delle variabili C. In questa sezione imparerai come dichiarare variabili globali in C.</p><p>▶ Iniziamo con un esempio.</p><pre><code class="language-c">#include &lt;stdio.h&gt;
int my_num = 7;

int main()
{
    printf("si può accedere a my_num da main() e il suo valore è %d\n",my_num);
    //chiama my_func
    my_func();
    return 0;
}

void my_func()
{
  printf("si può accedere a my_num anche da my_func() e il suo valore è %d\n",my_num);
} 
</code></pre><p>Nell'esempio qui sopra:</p><ul><li>La variabile <code>my_num</code> è dichiarata al di fuori delle funzioni <code>main()</code> e <code>my_func()</code>.</li><li>Cerchiamo di accedere a <code>my_num</code> all'interno della funzione <code>main()</code> e ne stampiamo il valore.</li><li>Chiamiamo la funzione <code>my_func()</code> all'interno della funzione <code>main()</code>.</li><li>La funzione <code>my_func()</code> cerca anche di accedere al valore di <code>my_num</code> per stamparlo.</li></ul><p>Questo programma si compila senza errori e il risultato è mostrato qui sotto:</p><pre><code>//Output
si può accedere a my_num da main() e il suo valore è 7
si può accedere a my_num anche da my_func() e il suo valore è 7</code></pre><p>In questo esempio, ci sono due funzioni &nbsp;– &nbsp;<code>main()</code> e <code>my_func()</code>.</p><p>Tuttavia la variabile <code>my_num</code> <em>non è locale</em> ad alcuna funzione nel programma. Una variabile di questo tipo, <em>non locale</em> ad alcuna funzione, ma si dice che ha un <em>ambito globale</em> e viene chiamata variabile <em>globale.</em></p><p>Questo principio di ambito globale delle variabili può essere riepilogato come segue:</p><pre><code class="language-C">//tutte le variabili globali sono dichiarate qui
function1()
    {
    
    // è possibile accedere a tutte le variabili globali dall'interno di function1
    
    }
function2()
    {
    
    // è possibile accedere a tutte le variabili globali dall'interno di function2
     
    } 
</code></pre><h2 id="riepilogo"><strong>Riepilogo</strong></h2><p>In questo tutorial, hai imparato la differenza tra ambito locale e globale. Questo è un tutorial di livello introduttivo sull'ambito delle variabili in C.</p><p>In C, esistono modificatori di accesso per controllare il livello di accessibilità di cui una variabile dispone. Puoi modificare la modalità di accesso usando le parole chiave corrispondenti quando dichiari le variabili.</p><p>Ci vediamo al prossimo tutorial. Fino ad allora, buona programmazione!<br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Form HTML – Esempi di Tipi di Input e Pulsanti di Invio ]]>
                </title>
                <description>
                    <![CDATA[ I form (moduli) sono una delle parti più importanti del web. Senza di essi, non ci sarebbe un modo facile per raccogliere dati, cercare risorse o effettuare un'iscrizione per ricevere informazioni preziose. Puoi inserire i form nelle pagine web con l'elemento HTML form. All'interno di questo elemento possono essere inseriti ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/form-html-esempi-di-tipi-di-input-e-pulsanti-di-invio/</link>
                <guid isPermaLink="false">6438239d88ecf5067c891236</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Mon, 08 May 2023 05:30:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/04/form-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/html-form-input-type-and-submit-button-example/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">HTML Form – Input Type and Submit Button Example</a>
      </p><p>I form (moduli) sono una delle parti più importanti del web. Senza di essi, non ci sarebbe un modo facile per raccogliere dati, cercare risorse o effettuare un'iscrizione per ricevere informazioni preziose.</p><p>Puoi inserire i form nelle pagine web con l'elemento HTML <code>form</code>. All'interno di questo elemento possono essere inseriti parecchi elementi <code>input</code>, noti anche come controlli del form.</p><p>In questo tutorial, esploreremo l'elemento HTML <code>form</code>, i vari tipi di elementi <code>input</code> che può contenere e come creare un pulsante di invio con il quale inviare i dati.</p><p>Alla fine, conoscerai il funzionamento dei form e sarai in grado di realizzarli con sicurezza.</p><h2 id="sintassi-base-per-un-form-html"><strong>Sintassi Base per un Form<strong> HTML</strong></strong></h2><pre><code class="language-html">&lt;form action="mywebsite.com" method="POST"&gt;
    &lt;!--Input di qualsiasi tipo ed elementi textarea vanno qui--&gt;
&lt;/form&gt;
</code></pre><h2 id="tipi-di-input-per-i-form-html"><strong>Tipi di Input per i Form <strong>HTML </strong></strong></h2><p>Si utilizza il tag <code>&lt;input&gt;</code> per creare diversi controlli in un form HTML. È un elemento in linea e riceve attributi come <code>type</code>, <code>name</code>, <code>minlength</code>, <code>maxlength</code>, <code>placeholder</code> e così via. Ciascuno di essi hanno specifici valori che possono ricevere.</p><p>L'attributo <code>placeholder</code> è importante in quanto aiuta l'utente a capire a cosa serve il campo di input prima che possa digitare qualcosa.</p><p>Ci sono 20 tipi di input diversi, e li esamineremo uno ad uno.</p><h3 id="tipo-text"><strong>Tipo<strong> Text</strong></strong></h3><p>Questo tipo di input ottiene il valore di &nbsp;“text” e crea una riga singola di testo da inserire.</p><pre><code class="language-html">&lt;input type="text" placeholder="Enter name" /&gt;
</code></pre><p>Un input di tipo text viene presentato come nella videata seguente:<br></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/textInput.png" class="kg-image" alt="textInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-password"><strong><strong>T</strong>ipo<strong> Password</strong></strong></h3><p>Come suggerisce il nome, questo tipo di input si utilizza per richiedere password. Rende automaticamente invisibile all'utente quanto sta digitando, a meno che l'elemento non venga manipolato tramite JavaScript.</p><pre><code class="language-html">&lt;input type="password" placeholder="Enter your password" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/passwordInput.png" class="kg-image" alt="passwordInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-email"><strong>Tipo<strong> Email</strong></strong></h3><p>Un input di tipo email definisce un campo per digitare un indirizzo email. L'input viene automaticamente validato per verificare la conformità con la sintassi di un indirizzo email.</p><pre><code class="language-html">&lt;input type="email" placeholder="Enter your email" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeEmail.png" class="kg-image" alt="typeEmail" width="600" height="400" loading="lazy"></figure><h3 id="tipo-number"><strong><strong>T</strong>ipo<strong> Number</strong></strong></h3><p>Questo tipo consente all'utente di inserire solamente numeri.</p><pre><code class="language-html">&lt;input type="number" placeholder="Enter a number" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/numberInput.png" class="kg-image" alt="numberInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-radio"><strong>Tipo<strong> Radio</strong></strong></h3><p>Talvolta gli utenti devono effettuare una scelta tra diverse opzioni. Questo tipo di input consente all'utente di scegliere un elemento tra quelli proposti.</p><pre><code class="language-html"> &lt;input type="radio" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeRadio.png" class="kg-image" alt="typeRadio" width="600" height="400" loading="lazy"></figure><h3 id="tipo-checkbox"><strong>Tipo<strong> Checkbox</strong></strong></h3><p>Con l'input di tipo radio gli utenti possono effettuare una scelta tra le opzioni proposte, ma se volessi rendere possibili tante scelte contemporaneamente? Ecco a cosa serve un input di tipo <code>checkbox</code>.</p><pre><code class="language-html">&lt;input type="checkbox" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeCheckbox.png" class="kg-image" alt="typeCheckbox" width="600" height="400" loading="lazy"></figure><h3 id="tipo-submit"><strong>Tipo<strong> Submit</strong></strong></h3><p>Questo tipo si usa per aggiungere un pulsante di invio a un form. Quando l'utente fa click sul pulsante, il form viene inviato. Riceve un attributo <code>value</code> che definisce il testo che appare all'interno del pulsante.</p><pre><code class="language-html">&lt;input type="submit" value="Enter to Win" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeSubmit.png" class="kg-image" alt="typeSubmit" width="600" height="400" loading="lazy"></figure><h3 id="tipo-button"><strong><strong>T</strong>ipo<strong> Button</strong></strong></h3><p>Questo tipo di input crea un pulsante, che può essere manipolato con JavaScript con un event listener per l'evento <code>onClick</code>. Crea un pulsante come il tipo <code>submit</code>, ma il valore del testo del pulsante deve essere specificato.</p><pre><code class="language-html">&lt;input type="button" value="Submit" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeButton.png" class="kg-image" alt="typeButton" width="600" height="400" loading="lazy"></figure><h3 id="tipo-file"><strong>Tipo<strong> File</strong></strong></h3><p>Definisce un campo per l'invio di uno o più file. Quando un utente fa click su questo controllo, gli viene richiesto di scegliere il file da inserire, che potrebbe essere un'immagine, un PDF e così via.</p><pre><code class="language-html">&lt;input type="file" /&gt;
</code></pre><p>Ecco come viene presentato un input di tipo file:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/fileInput.png" class="kg-image" alt="fileInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-color"><strong>Tipo<strong> Color</strong></strong></h3><p>Questo tipo di input è stato introdotto con HTML5. Con questo l'utente può scegliere un colore. Il nero (codice esadecimale <code>#000000</code>) è il valore predefinito, ma può essere modificato inserendo nel parametro <code>value</code> il colore desiderato in formato esadecimale.</p><p>Molti sviluppatori hanno usato questo elemento per poter scegliere le varie tonalità di colore nei formati RGB, HSL e alfanumerico</p><pre><code class="language-html">&lt;input type="color" /&gt;
</code></pre><p>Ecco come viene presentato questo tipo di input, una volta che l'utente ha fatto click sull'elemento:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/colorInput.png" class="kg-image" alt="colorInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-search"><strong>Tipo<strong> Search</strong></strong></h3><p>Questo tipo di input definisce un campo di testo, proprio come il tipo <code>text</code>. Ma ha il solo scopo di consentire all'utente di effettuare una ricerca. Un pulsante di cancellazione (una x) all'interno dell'elemento appare una volta che si è iniziato a digitare.</p><pre><code class="language-html">&lt;input type="search" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeSearch.png" class="kg-image" alt="typeSearch" width="600" height="400" loading="lazy"></figure><h3 id="tipo-url"><strong>Tipo<strong> URL</strong></strong></h3><p>Quando viene impostato un elemento input con questo attributo, viene mostrato un campo che può essere usato per digitare un URL.</p><pre><code class="language-html">&lt;input type="url" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeURL.png" class="kg-image" alt="typeURL" width="600" height="400" loading="lazy"></figure><h3 id="tipo-tel"><strong>Tipo<strong> Tel</strong></strong></h3><p>Questo tipo consente di ottenere numeri di telefono dagli utenti.</p><pre><code class="language-html">&lt;input type="tel" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/typeTel.png" class="kg-image" alt="typeTel" width="600" height="400" loading="lazy"></figure><h3 id="tipo-date"><strong>Tipo<strong> Date</strong></strong></h3><p>Potresti esserti registrato in un sito web che richiede l'inserimento di una data per un certo evento. Questo sito probabilmente usa un input di questo tipo.</p><pre><code class="language-html">&lt;input type="date" /&gt;
</code></pre><p>Ecco come viene presentato questo tipo di input:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/dateInput.png" class="kg-image" alt="dateInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-datetime-local"><strong>Tipo<strong> Datetime-local</strong></strong></h3><p>Funziona come il tipo <code>date</code>, ma consente all'utente anche di scegliere un orario oltre a una data.</p><pre><code class="language-html">&lt;input type="datetime-local" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/datelocalInput.png" class="kg-image" alt="datelocalInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-week"><strong>Tipo<strong> Week</strong></strong></h3><p>Questo tipo consente all'utente di selezionare una particolare settimana in un anno.</p><pre><code class="language-html">&lt;input type="week" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/weekInput.png" class="kg-image" alt="weekInput" width="600" height="400" loading="lazy"></figure><h3 id="tipo-month"><strong>Tipo<strong> Month</strong></strong></h3><p>Con questo tipo di input vengono presentati i mesi, affinché l'utente possa effettuare una scelta facendo click su uno di essi.</p><pre><code class="language-html">&lt;input type="month" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/monthInput.png" class="kg-image" alt="monthInput" width="600" height="400" loading="lazy"></figure><h3 id="textarea"><strong><strong>Textarea</strong></strong></h3><p>Ci sono situazioni nelle quali un utente deve riempire più righe di testo, pertanto il tipo di input <code>text</code> non sarebbe adatto, in quanto consente di riempire solo una riga di testo.</p><p><code>textarea</code> consente all'utente di inserire testo su più righe. Tramite gli attributi <code>cols</code> e <code>rows</code> consente di impostare rispettivamente il numero di colonne e di righe per l'elemento.</p><pre><code class="language-html">&lt;textarea cols="50" rows="20"&gt;&lt;/textarea&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/textarea.png" class="kg-image" alt="textarea" width="600" height="400" loading="lazy"></figure><h3 id="select"><strong><strong>Select</strong></strong></h3><p>È come avere le funzionalità di un elemento di tipo radio e di tipo checkbox assieme. Viene inserito nel form tramite due elementi, l'elemento <code>select</code> propriamente detto e, al suo interno, tanti elementi <code>option</code> quante sono le opzioni da offrire.</p><p>Nella modalità predefinita, l'utente può scegliere solo una opzione ma con l'attributo <code>multiple</code> è possibile selezionare più opzioni.</p><pre><code class="language-html">&lt;select&gt;
      &lt;option value="HTML"&gt;Select a Language&lt;/option&gt;
      &lt;option value="HTML"&gt;HTML&lt;/option&gt;
      &lt;option value="CSS"&gt;CSS&lt;/option&gt;
      &lt;option value="JavaScript"&gt;JavaScript&lt;/option&gt;
      &lt;option value="React"&gt;React&lt;/option&gt;
&lt;/select&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/selectDemo.gif" class="kg-image" alt="selectDemo" width="600" height="400" loading="lazy"></figure><h2 id="come-abbinare-un-etichetta-agli-elementi-input"><strong>Come Abbinare un Etichetta agli Elementi Input</strong></h2><p>Assegnare etichette ai controlli di un form con l'elemento <code>label</code> è importante. Quando sono correttamente abbinate al relativo campo di input tramite il loro attributo <code>for</code>, che deve essere valorizzato con il contenuto dell'attributo <code>id</code> dell'elemento input relativo, facilitano anche l'utente in quando può cliccare sull'etichetta stessa per accedere al controllo input relativo.</p><pre><code class="language-html">&lt;label for="name"&gt;Name&lt;/label&gt;
&lt;input type="text" id="name" /&gt; &lt;br /&gt;
&lt;label for="check"&gt;Agree with terms&lt;/label&gt;
&lt;input type="checkbox" id="check" /&gt;
</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/labelDemo.gif" class="kg-image" alt="labelDemo" width="600" height="400" loading="lazy"></figure><h2 id="come-funzionano-i-form-html"><strong>Come Funzionano i Form<strong> HTML</strong></strong></h2><p>Quando un utente riempie i campi di un form, poi fa click sul pulsante di invio, manda i dati contenuti nei controlli del form al server tramite una richiesta con un metodo HTTP <code>GET</code> o <code>POST</code> .</p><p>Quindi come viene specificato il server? L'elemento <code>form</code> riceve un attributo <code>action</code>, che deve avere come valore l'URL del server al quale inviare i dati. Riceve anche un attributo <code>method</code>, che indica il metodo HTTP usato per veicolare i valori al server specificato.</p><p>Questo metodo potrebbe essere &nbsp;<code>GET</code> o <code>POST</code>. Con il metodo <code>GET</code> i valori digitati dall'utente sono visibili nella stringa dell'URL quando viene inviato. Con il metodo <code>POST</code> i valori vengono inviati nel corpo della richiesta, di conseguenza non sono visibili nell'URL.</p><p>Se non viene usato l'attributo <code>method</code>, viene utilizzato il metodo <code>GET</code> come valore predefinito.</p><p>Quindi quando dovresti usare il metodo <code>GET</code> o <code>POST</code>? Usa <code>GET</code> per inviare dati non sensibili o per ottenere dati da un server (ad esempio durante una ricerca). Usa <code>POST</code> quando invii file o dati sensibili.</p><h2 id="mini-progetto-creare-un-form-di-contatto-di-base"><strong><strong>Mini Pro</strong>getto<strong>: </strong>Creare un Form di Contatto di Base</strong></h2><p>Utilizziamo quanto appreso sugli elementi di un form per creare un semplice form di contatto. Introdurrò anche alcuni concetti ulteriori mentre lo sviluppiamo.</p><h3 id="ecco-il-codice-html-"><strong>Ecco il Codice <strong>HTML:</strong></strong></h3><pre><code class="language-html">&lt;form action="example-server.com"&gt;
      &lt;fieldset&gt;
        &lt;legend&gt;Contact me&lt;/legend&gt;
        &lt;div class="form-control"&gt;
          &lt;label for="name"&gt;Name&lt;/label&gt;
          &lt;input type="name" id="name" placeholder="Enter your name" required /&gt;
        &lt;/div&gt;

        &lt;div class="form-control"&gt;
          &lt;label for="email"&gt;Email&lt;/label&gt;
          &lt;input
            type="email"
            id="email"
            placeholder="Enter your email"
            required
          /&gt;
        &lt;/div&gt;

        &lt;div class="form-control"&gt;
          &lt;label for="message"&gt;Message&lt;/label&gt;
          &lt;textarea
            id="message"
            cols="30"
            rows="10"
            placeholder="Enter your message"
            required
          &gt;&lt;/textarea&gt;
        &lt;/div&gt;
        &lt;input type="submit" value="Send" class="submit-btn" /&gt;
      &lt;/fieldset&gt;
&lt;/form&gt;
</code></pre><h4 id="cosa-succede-in-questo-codice-html"><strong>Cosa succede in questo codice<strong> HTML?</strong></strong></h4><p>Innanzitutto un elemento <code>form</code> racchiude tutti gli altri elementi. L'attributo <code>action</code> è impostato su <code>“example-server.com”,</code> un server fittizio dove saranno ricevuti i dati.</p><p>Dopo l'elemento <code>form</code>, ogni altro elemento è racchiuso tra un elemento <code>fieldset</code> al cui interno si trova un tag <code>legend</code>.</p><p>Usiamo l'elemento <code>fieldset</code> per raggruppare input correlati, il tag <code>legend</code> contiene un'intestazione che descrive quali dati verranno raccolti dalla sezione.</p><p>Gli elementi di input <code>name</code>, <code>email</code> e <code>textarea</code> sono tutti all'interno di un elemento <code>div</code> con la classe <code>form-control</code>, in modo che si comportino come un elemento di tipo blocco, per facilitare l'applicazione di uno stile CSS.</p><p>Sono anche validati con l'attributo <code>required</code>, pertanto il form non viene inviato se i campi caratterizzati con quell'attributo sono vuoti.</p><p>Dopo tutto questo, il form apparirà come nella videata seguente:<br></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/unstyledForm.png" class="kg-image" alt="unstyledForm" width="600" height="400" loading="lazy"></figure><p>Molto brutto, non è vero? Dobbiamo applicare qualche stile al form!</p><h3 id="ecco-il-codice-css-"><strong>Ecco il<strong> </strong>codice <strong>CSS:</strong></strong></h3><pre><code class="language-css">body {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    font-family: cursive;
  }

 input,
    textarea {
    width: 100%;
    padding: 5px;
    outline: none;
  }

  label {
    line-height: 1.9rem;
  }

  input[type="submit"] {
   transform: translate(2.2%);
   padding: 3px;
   margin-top: 0.6rem;
   font-family: cursive;
   font-weight: bold;
  }

 fieldset {
   padding: 20px 40px;
 }
</code></pre><h4 id="cosa-fa-questo-codice-css"><strong>Cosa fa questo codice CSS<strong>?</strong></strong></h4><p>Centriamo tutto orizzontalmente all'interno del tag <code>body</code> con Flexbox, e verticalmente dando un'altezza di viewport pari al 100%. Usiamo una famiglia di caratteri corsivi.</p><p>Diamo agli elementi di input e al <code>textarea</code> una larghezza del 100% in modo che si espandano orizzontalmente. Le etichette hanno un'altezza di riga minima di 1.9rem (30.4px), in modo che non siano troppo vicine ai loro rispettivi elementi input.</p><p>Abbiamo disegnato in modo specifico il pulsante (pulsante di tipo input) con la proprietà transform per spingerlo al centro, perché era un po' fuori centro. Gli abbiamo dato una spaziatura all'interno di 3px per avere più spazio attorno ad esso. Abbiamo quindi selezionato una famiglia di caratteri corsivi in grassetto.</p><p>Visto che il pulsante era troppo vicino all'elemento <code>textarea</code>, abbiamo impostato un margine superiore di 0.6rem per portarlo un poco più in basso.</p><p>All'elemento <code>fieldset</code> abbiamo applicato una spaziatura interna di 20px in alto e in basso e 40px a destra e sinistra per distanziarlo dal bordo che crea attorno all'elemento <code>form</code> nel quale è contenuto.</p><p>Alla fine di tutto questo, abbiamo questo bel form:<br></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/styledForm.png" class="kg-image" alt="styledForm" width="600" height="400" loading="lazy"></figure><h2 id="conclusione"><strong><strong>Conclusion</strong>e</strong></h2><p>Spero che questo tutorial ti abbia aiutato a capire come funzionano i form. Ora dovresti avere le conoscenze necessarie per integrare i form nei tuoi siti web, in modo da poter iniziare a raccogliere dati.</p><p>Grazie per la lettura e buona programmazione.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Introduzione a Linux - Parte 2 ]]>
                </title>
                <description>
                    <![CDATA[ In questo corso completo, imparerai molti degli strumenti utilizzati ogni giorno sia dagli Amministratori di Sistema di Linux che dai milioni di persone che eseguono distribuzioni Linux come Ubuntu sui loro PC. Questo corso ti insegnerà come spostarti nelle interfacce utente grafiche di Linux e nel potente ecosistema dello strumento ]]>
                </description>
                <link>https://www.freecodecamp.org/italian/news/introduzione-a-linux-parte-2/</link>
                <guid isPermaLink="false">641c16d902ca030845afbf4b</guid>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Roberto Pauletto ]]>
                </dc:creator>
                <pubDate>Thu, 04 May 2023 13:52:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/italian/news/content/images/2023/03/linux2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Articolo originale:</strong> <a href="https://www.freecodecamp.org/news/introduction-to-linux-part-2/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Introduction to Linux, Part 2</a>
      </p><p>In questo corso completo, imparerai molti degli strumenti utilizzati ogni giorno sia dagli Amministratori di Sistema di Linux che dai milioni di persone che eseguono distribuzioni Linux come Ubuntu sui loro PC. Questo corso ti insegnerà come spostarti nelle interfacce utente grafiche di Linux e nel potente ecosistema dello strumento di riga di comando.</p><p>Questa è la seconda parte. Prima leggi la prima parte:</p><p><a href="https://www.freecodecamp.org/italian/news/introduzione-a-linux/">https://www.freecodecamp.org/italian/news/introduzione-a-linux/</a><br></p><h2 id="capitolo-18-principi-di-sicurezza-locale"><strong><strong>C</strong>apitolo<strong> 18: </strong>Principi di Sicurezza Locale</strong></h2><h3 id="obiettivi-formativi"><strong>Obiettivi Formativi</strong></h3><p>Entro la fine di questo capitolo, dovresti essere in grado di:</p><ul><li>Avere una buona comprensione delle migliori pratiche e strumenti per rendere i sistemi Linux il più sicuri possibile.</li><li>Comprendere i poteri e i pericoli dell'utilizzo dell'account root (superuser).</li><li>Utilizzare il comando <strong>sudo</strong> per eseguire operazioni privilegiate limitando al massimo i poteri avanzati.</li><li>Spiegare l'importanza dell'isolamento del processo e dell'accesso all'hardware.</li><li>Lavorare con le password, incluso come impostarle e modificarle.</li><li>Descrivere come proteggere il processo di avvio e le risorse hardware.</li></ul><h3 id="account-utente"><strong><strong>Account</strong> Utente</strong></h3><p>Il kernel Linux consente agli utenti correttamente autenticati di accedere a file e applicazioni. Mentre ogni utente è identificato da un numero intero univoco (ID utente o UID), un database separato associa un nome utente con ogni UID. Al momento della creazione dell'account, le nuove informazioni dell'utente vengono aggiunte al database utenti e la directory home dell'utente deve essere creata e popolata con alcuni file essenziali. Programmi di riga di comando come <strong>useradd</strong> e <strong>userdel</strong> e gli strumenti GUI vengono utilizzati per la creazione e la rimozione degli account.</p><figure class="kg-card kg-image-card"><img src="https://courses.edx.org/assets/courseware/v1/5e3a5828edd1ac8364f2f744f8fa1942/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/etcpasswd.png" class="kg-image" alt="User Accounts: /etc/passwd" width="974" height="457" loading="lazy"></figure><p>Per ogni utente, i seguenti sette campi vengono conservati nel file <strong><code>/etc/passwd</code></strong>:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th><strong>Nome Campo</strong></th>
<th><strong>Dettagli</strong></th>
<th><strong>Osservazioni</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Username</strong></td>
<td>Nome di login utente</td>
<td>Dovrebbe essere lungo tra 1 e 32 caratteri</td>
</tr>
<tr>
<td><strong>Password</strong></td>
<td>Password utente (oppure il carattere <strong>x</strong> se la password è conservata nel file <strong><code>/etc/shadow</code></strong>) in formato crittografato</td>
<td>Non è mai mostrata in Linux quando viene digitata, mettendola al riparo da sguardi indiscreti</td>
</tr>
<tr>
<td><strong>User ID (UID)</strong></td>
<td>Ogni utente deve avere un ID (UID)</td>
<td>- UID 0 è riservato all'utente root<br>- Gli UID che vanno da 1 a 99 sono riservati per altri account predefiniti<br>- Gli UID che vanno da 100 a 999 sono riservati agli account di sistema e gruppi<br>- I normali utenti hanno UID che vanno da 1000 in su</td>
</tr>
<tr>
<td><strong>Group ID (GID)</strong></td>
<td>L'ID del gruppo primario (GID), conservato nel file <strong><code>/etc/group</code></strong></td>
<td>È stato trattato in dettaglio nel capitolo sui <em>Processi</em></td>
</tr>
<tr>
<td><strong>User Info</strong></td>
<td>Campo opzionale, consente l'inserimento di informazioni supplementari circa l'utente, come il suo nome</td>
<td>Per esempio:&nbsp;<strong>Rufus T. Firefly</strong></td>
</tr>
<tr>
<td><strong>Directory Home</strong></td>
<td>Il percorso assoluto della posizione della directory home dell'utente</td>
<td>Per esempio:&nbsp;<strong><code>/home/rtfirefly</code></strong></td>
</tr>
<tr>
<td><strong>Shell</strong></td>
<td>Il percorso assoluto della posizione della shell predefinita dell'utente</td>
<td>Per esempio: <strong><code>/bin/bash</code></strong></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="tipi-di-account"><strong>Tipi di <strong> Account</strong></strong></h3><p>Per impostazione predefinita, Linux distingue tra diversi tipi di account al fine di isolare i processi e i carichi di lavoro. Linux ha quattro tipi di account:</p><ul><li>root</li><li>Sistema</li><li>Normale</li><li>Rete</li></ul><p>Per un ambiente di lavoro sicuro, si consiglia di concedere i privilegi minimi possibili e necessari per gli account e rimuovere gli account inattivi. L'utilità <strong>last</strong>, che mostra l'ultima volta che ogni utente ha effettuato l'accesso al sistema, può essere utilizzata per aiutare a identificare account potenzialmente inattivi che sono candidati per la rimozione dal sistema.</p><p>Tieni presente che le pratiche che usi sui sistemi aziendali multiutente sono più severe delle pratiche che puoi utilizzare sui sistemi desktop personali che influiscono solo sull'utente casuale. Ciò è particolarmente vero per quanto riguarda la sicurezza. Speriamo di mostrarti pratiche applicabili ai server aziendali che puoi utilizzare su tutti i sistemi, ma comprendiamo che puoi scegliere di rendere meno rigide queste regole sul tuo sistema personale..</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/c74352d16a50f0bb625173f8f9c2abdb/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/lastoutput.png" class="kg-image" alt="last Utility" width="849" height="472" loading="lazy"><figcaption>L'utility last</figcaption></figure><h3 id="comprendere-l-account-root"><strong>Comprendere l'Account root</strong></h3><p><strong>root</strong> è l'account più privilegiato su un sistema Linux/Unix. Questo account ha la possibilità di gestire tutti gli aspetti dell'amministrazione del sistema, incluso l'aggiunta di account, la modifica delle password degli utenti, l'esame di file di log, l'installazione di software e così via. È necessario procedere con la massima cura quando si utilizza questo account. Non ha restrizioni di sicurezza imposte.</p><figure class="kg-card kg-image-card"><img src="https://courses.edx.org/assets/courseware/v1/36cc69851c8f812250c33fd23b642507/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch18_screen05.jpg" class="kg-image" alt="Tux the Pinguin with a crown and scepter" width="230" height="250" loading="lazy"></figure><p>Quando si accede come root o si agisce come root, il prompt della shell mostra '#' (se stai usando bash e non hai personalizzato il prompt, come abbiamo discusso in precedenza). Questa convenzione ha lo scopo di fungere da monito per te del potere assoluto di questo account.</p><h3 id="operazioni-che-richiedono-privilegi-di-root">Operazioni che Richiedono Privilegi di root</h3><p>I privilegi di root sono richiesti per eseguire operazioni come:</p><ul><li>Creazione, rimozione e gestione degli account utente</li><li>Gestione dei pacchetti software</li><li>Rimozione o modifica dei file di sistema</li><li>Riavvio dei servizi di sistema.</li></ul><p>Gli utenti di account normali delle distribuzioni Linux potrebbero essere autorizzati a installare pacchetti software, aggiornare alcune impostazioni, utilizzare alcuni dispositivi periferici e applicare vari tipi di modifiche al sistema. Tuttavia, è richiesto il privilegio di root per eseguire attività di amministrazione come il riavvio della maggior parte dei servizi, l'installazione manuale di pacchetti e la gestione di parti del filesystem che si trovano al di fuori delle directory dell'utente normale.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/aee73bd08cabfc1b26a7f7927df8317d/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch018_screen8.jpg" class="kg-image" alt="LFS01_ch018_screen8" width="472" height="305" loading="lazy"><figcaption>Operazioni che Richiedono Privilegi di root</figcaption></figure><h3 id="operazioni-che-non-richiedono-privilegi-di-root">Operazioni Che Non Richiedono Privilegi di root</h3><p>Un utente con account normale può eseguire alcune operazioni che richiedono autorizzazioni speciali; tuttavia, la configurazione del sistema deve consentire l'esercizio di tali funzionalità.</p><p><strong><a href="https://it.wikipedia.org/wiki/Setuid_e_setgid">SUID</a></strong> (<strong>S</strong>et owner <strong>U</strong>ser <strong>ID</strong> upon execution - simile alla funzionalità Windows "esegui come") è un tipo speciale di permesso fornito a un file. L'uso di SUID fornisce autorizzazioni temporanee a un utente per eseguire un programma con le autorizzazioni del <em>proprietario</em> del file (che potrebbe essere root) invece delle autorizzazioni detenute dall'<em>utente</em>.</p><p>La tabella fornisce esempi di operazioni che non richiedono privilegi di root:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th><strong>Operazioni che non richiedono privilegi di root</strong></th>
<th><strong>Esempi di questa operazione</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Esecuzione di un client di rete</td>
<td>Condivisione di un file tramite rete</td>
</tr>
<tr>
<td>Utilizzo di dispositivi come le stampanti</td>
<td>Stampa tramite rete</td>
</tr>
<tr>
<td>Operazioni su file per i quali l'utente ha autorizzazioni adeguate per accedere</td>
<td>Accesso ai file a cui puoi accedere o condivisione di dati tramite rete</td>
</tr>
<tr>
<td>Esecuzione di applicazioni SUID-root</td>
<td>Esecuzione di programmi come <strong>passwd</strong></td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="sudo-e-su-a-confronto"><strong><strong>sudo </strong>e<strong> su</strong> a Confronto</strong></h3><p>In Linux puoi usare sia <strong>su</strong> che <strong>sudo</strong> per concedere temporaneamente l'accesso come root a un utente normale. Tuttavia, questi metodi sono in realtà abbastanza diversi. Di seguito sono elencate le differenze tra i due comandi:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th><strong>su</strong></th>
<th><strong>sudo</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>Quando si aumentano i privilegi, è necessario inserire la password di root. Non si dovrebbe mai dare la password di root a un utente normale, mai e poi mai.</td>
<td>Quando si aumentano i privilegi, è necessario inserire la password dell'utente e non la password di root.</td>
</tr>
<tr>
<td>Una volta che un utente si eleva all'account root utilizzando <strong>su</strong>, può fare tutto ciò che l'utente root può fare per tutto il tempo che l'utente desidera, senza che gli venga chiesta nuovamente la password.</td>
<td>Offre più funzionalità ed è considerato più sicuro e più configurabile. Quello che l'utente può fare può essere esattamente controllato e limitato con precisione. Per impostazione predefinita, l'utente dovrà sempre continuare a dare la propria password per eseguire ulteriori operazioni con <strong>sudo</strong> o può evitare di farlo per un intervallo di tempo configurabile.</td>
</tr>
<tr>
<td>Il comando ha funzionalità di log limitate.</td>
<td>Il comando ha funzionalità di log dettagliate.</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h3 id="funzionalit-di-sudo">Funzionalità di sudo</h3><p><strong><strong><strong><strong>sudo </strong></strong></strong></strong>ha la capacità di tenere traccia dei tentativi falliti di ottenere l'accesso a root. L'autorizzazione per gli utenti all'utilizzo di <strong>sudo</strong> si basa sulle informazioni di configurazione conservate nel file <strong><code>/etc/sudoers</code></strong> e nella directory &nbsp;<strong><code>/etc/sudoers.d</code></strong>.</p><p>Un messaggio come il seguente apparirebbe in un file di log del sistema (in genere <strong>/var/log/secure</strong>) Quando si cerca di eseguire <strong>sudo</strong> per <strong>badperson</strong> senza ottenere una corretta autenticazione per l'utente:<br></p><p><strong><strong><strong><strong><code>badperson : user NOT in sudoers ; TTY=pts/4 ; PWD=/var/log ; USER=root ; COMMAND=/usr/bin/tail secure</code></strong></strong></strong></strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/221b78f7941bfa4846b7253289053ded/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch18_screen14b.jpg" class="kg-image" alt="sudo Features" width="273" height="240" loading="lazy"><figcaption>Funzionalità di sudo</figcaption></figure><h3 id="il-file-sudoers"><strong>Il File<strong> sudoers</strong></strong></h3><p>Ogniqualvolta <strong>sudo</strong> viene invocato, si attiva una ricerca nel file <strong><code>/etc/sudoers</code></strong> e nei file contenuti in <strong><code>/etc/sudoers.d</code></strong> per determinare se l'utente ha il diritto di utilizzare <strong>sudo</strong> e qual è la portata dei suoi privilegi. Richieste da utenti sconosciuti e richieste per eseguire operazioni non consentite all'utente anche con <strong>sudo</strong> vengono segnalate. La struttura di base delle voci in questi file è:</p><p><strong>chi dove = (per conto di) cosa</strong></p><p><strong><strong><strong><strong><code>/etc/sudoers</code></strong></strong></strong></strong> contiene molta documentazione sulla personalizzazione. La maggior parte delle distribuzioni Linux ora preferisce aggiungere un file nella directory <strong><code>/etc/sudoers.d</code></strong> con un nome che corrisponde allo username. Questo file contiene la configurazione <strong>sudo</strong> del singolo utente, mentre si dovrebbe lasciare inalterato il file di configurazione principale, eccetto per quanto riguarda le modifiche che riguardano tutti gli utenti.</p><p>Dovresti modificare uno di questi file di configurazione utilizzando <strong>visudo</strong>, che garantisce che solo una persona alla volta stia modificando il file, che abbia le autorizzazioni adeguate, e rifiuta di scrivere il file ed uscire se ci sono errori di sintassi nelle modifiche apportate. Le modifiche possono essere eseguite con un comando come quelli seguenti:</p><p><strong><strong><strong><strong><strong><strong><code># visudo /etc/sudoers</code></strong></strong></strong></strong></strong></strong><br><strong><strong><strong><strong><strong><strong><code># visudo -f /etc/sudoers.d/student</code></strong></strong></strong></strong></strong></strong></p><p>L'editor specifico effettivo che verrà aperto dipenderà dall'impostazione della variabile di ambiente <strong><code>EDITOR</code></strong>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/be9e3859dfc9da162c2aee89c1bb83f3/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/sudoerssuse.png" class="kg-image" alt="The sudoers File" width="837" height="806" loading="lazy"><figcaption>Il File sudoers</figcaption></figure><h3 id="registrare-i-comandi"><strong>Registrare i Comandi</strong></h3><p>Per impostazione predefinita, i comandi <strong>sudo</strong> effettuati ed eventuali errori sono registrati nel file <strong><code>/var/log/auth.log</code></strong> per quanto riguarda la famiglia di distribuzioni Debian, e in <strong><code>/var/log/messages</code></strong> e/o <strong><code>/var/log/secure</code></strong> negli altri sistemi. Questa è una misura di sicurezza importante per consentire il monitoraggio e la responsabilità dell'uso di <strong>sudo</strong>. Una voce tipica del messaggio di registrazione contiene:</p><ul><li>Nome utente del chiamante</li><li>Informazioni sul terminale</li><li>Directory di lavoro</li><li>Account utente chiamato</li><li>Comando con argomenti</li></ul><p>L'esecuzione di un comando come <strong><code>sudo whoami</code></strong> viene registrato come voce nel file di log in questo modo:</p><p><strong><strong><strong><strong><strong><strong><code>Dec 8 14:20:47 server1 sudo: op : TTY=pts/6 PWD=/var/log USER=root COMMAND=/usr/bin/whoami</code></strong></strong></strong></strong></strong></strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/e391446157bf3f88641e613c9e2a55f0/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/varlogsecure.png" class="kg-image" alt="varlogsecure" width="865" height="428" loading="lazy"><figcaption>Registrazione dei Comandi</figcaption></figure><h3 id="isolamento-del-processo"><strong>Isolamento del <strong>Processo</strong></strong></h3><p>Linux è considerato più sicuro di molti altri sistemi operativi in quanto i processi sono isolati in modo naturale l'uno dall'altro. Un processo normalmente non può accedere alle risorse di un altro processo, anche se questo processo è in esecuzione con gli stessi privilegi utente. Linux quindi rende difficile (anche se certamente non impossibile) ai virus e ai tentativi di penetrare la sicurezza, l'accesso e l'attacco casuale a risorse in un sistema.</p><p>Sono stati aggiunti recentemente altri meccanismi di sicurezza che limitano il rischio ulteriormente, tra i quali:</p><ul><li>Gruppi di Controllo (cgroup)<br>Consentono agli amministratori di sistema di raggruppare processi e associare risorse finite a ciascun cgroup.</li><li>Contenitori<br>Rendono possibile l'esecuzione di più sistemi Linux isolati (contenitori) su un singolo sistema facendo affidamento ai cgroup.</li><li>Virtualizzazione<br>L'hardware viene emulato in modo tale che non solo i processi possano essere isolati, ma interi sistemi possano essere eseguiti contemporaneamente come ospiti isolati (macchine virtuali) su un host fisico.</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/ab1acbfb43d22b02e75c9a7f46e50c27/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch18_screen18.jpg" class="kg-image" alt="Process Isolation" width="461" height="339" loading="lazy"><figcaption>Isolamento di Processi</figcaption></figure><h3 id="accesso-ai-dispositivi-hardware"><strong>Accesso ai Dispositivi <strong>Hardware</strong></strong></h3><p>Linux limita all'utente l'accesso a dispositivi hardware non di rete in modo estremamente simile all'accesso ai normali file. Le applicazioni interagiscono coinvolgendo il livello del filesystem (che è indipendente dall'effettivo dispositivo o hardware nel quale risiede). Questo livello aprirà quindi uno speciale file di dispositivo (spesso chiamato nodo di dispositivo) nella directory <strong><strong><strong><strong><code>/dev</code></strong></strong></strong></strong> che corrisponde al dispositivo al quale si accede. Ciascun file speciale di dispositivo ha normali permessi per proprietario, gruppo e altri. La sicurezza è applicata in modo naturale, allo stesso modo dell'accesso a file standard.</p><p>Gli hard disk, per esempio, sono rappresentati come &nbsp;<strong><strong><strong><strong><code>/dev/sd*</code></strong></strong></strong>. </strong>Un utente root può leggere e scrivere sul disco in modo grezzo, ad esempio eseguendo qualcosa come:</p><p><strong><strong><strong><strong><strong><strong><code># echo hello world &gt; /dev/sda1</code></strong></strong></strong></strong></strong></strong></p><p>I permessi standard così come sono mostrati nella videata qui sotto, rendono impossibile agli utenti normali fare questo. La scrittura verso un dispositivo fatta in quel modo può facilmente obliterare il filesystem che vi risiede in un modo che non consente una riparazione senza grossi sforzi, posto che ci si riesca. La normale lettura e scrittura di file su hard disk dalle applicazioni è fatta a un livello più alto tramite il filesystem e mai con accesso diretto al nodo di dispositivo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/f329a3cc179860717d2d0252d7a2a8c2/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/lsdevsdcentos.png" class="kg-image" alt="Hardware Device Access" width="865" height="314" loading="lazy"><figcaption>Accesso ai Dispositivi Hardware</figcaption></figure><h3 id="mantenere-il-sistema-aggiornato"><strong>Mantenere il Sistema Aggiornato</strong></h3><p>Quando sono individuati i problemi di sicurezza sia sul kernel Linux &nbsp;che su applicazioni e librerie, le distribuzioni Linux hanno una buona reputazione di agire velocemente, applicando le risoluzioni per tutti i sistemi, aggiornando i loro repository software e inviando notifiche che consigliano l'aggiornamento immediato. La stessa cosa vale anche per la risoluzione di bug e miglioramenti di prestazioni che non sono legati alla sicurezza.</p><figure class="kg-card kg-image-card"><img src="https://courses.edx.org/assets/courseware/v1/5e74db8d93ac146d9d1fdcbf8b1c9a05/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch018_screen20.jpg" class="kg-image" alt="Timely System Update" width="173" height="202" loading="lazy"></figure><p>Tuttavia, è ben noto che molti sistemi non vengono aggiornati con sufficiente frequenza e problemi per i quali esiste già la soluzione rimangono nei computer per molto tempo; questo è particolarmente vero con sistemi operativi proprietari dove gli utenti non sono informati o non si fidano della politica di applicazione delle risoluzioni dei problemi da parte dei gestori delle distribuzioni, in quanto talvolta gli aggiornamenti possono causare nuovi problemi e rompere cose che prima funzionavano. La maggior parte dei vettori di attacco più efficaci sfruttano buchi di sicurezza per i quali è già pronta la risoluzione ma non è stata universalmente distribuita.</p><p>Quindi la migliore pratica per trarre vantaggio del meccanismo di aggiornamenti automatici della tua distribuzione Linux è di applicarli tempestivamente, mai rimandarli. È estremamente raro che tali aggiornamenti possano causare nuovi problemi.</p><h3 id="come-sono-conservate-le-password"><strong>Come Sono Conservate le Password</strong></h3><p>Il sistema verifica l'autenticità e l'identità usando le credenziali utente.</p><p>In origine, le password criptate erano conservate nel file <strong><strong><strong><strong><strong><strong><code>/etc/passwd</code></strong></strong></strong></strong></strong></strong>, che era leggibile da tutti. Pertanto era piuttosto facile scoprire le password.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/d8b630982847322e8a30865f4af85767/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch18_screen21.jpg" class="kg-image" alt="How Passwords are Stored" width="446" height="464" loading="lazy"><figcaption>Come Sono Conservate le Password</figcaption></figure><p>Nei moderni sistemi, le password sono in realtà conservate in forma criptata in un file secondario chiamato <strong><strong><strong><strong><code>/etc/shadow</code></strong></strong></strong></strong>. Solo chi ha accesso come root può leggere o modificare questo file.</p><h3 id="algoritmo-della-password"><strong>Algoritmo della <strong>Password</strong></strong></h3><p>La protezione delle password è diventato un elemento cruciale di sicurezza. La maggior parte delle distribuzioni Linux fa affidamento su un moderno algoritmo di codifica delle password chiamato SHA-512 (Secure Hashing Algorithm 512 bits), sviluppato dall'Agenzia per la Sicurezza Nazionale degli Stati Uniti per la codifica delle password.</p><p>L'algoritmo SHA-512 è largamente usato per applicazione di sicurezza e protocolli. Questi includono TLS, SSL, PHP, SSH, S/MIME e IPSec. SHA-512 è uno degli algoritmi più testati.</p><p>Per esempio, se desideri fare esperimenti con la codifica SHA-512, la parola "test" può essere codificata usando il programma <strong><strong><strong><strong><strong><strong>sha512sum</strong></strong></strong></strong></strong></strong> per produrre il formato SHA-512 (vedi sotto):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/2b48e41c1608e121d66b9dbaf424a6c6/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/sha512rhel7.png" class="kg-image" alt="Password Encryption: sha512sum" width="685" height="105" loading="lazy"><figcaption>Codifica Password: sha512sum</figcaption></figure><h3 id="buone-pratiche-per-le-password"><strong>Buone Pratiche per le Password</strong></h3><p>I professionisti IT seguono parecchie buone pratiche per mettere in sicurezza i dati e la password di ciascun utente.</p><ul><li>La durata della password è un metodo per assicurarsi che l'utente venga avvisato quando è ora di creare una nuova password, trascorso uno specifico periodo di tempo. Questo assicura che le password, se scoperte, saranno utilizzabili solo per un periodo limitato di tempo. Questa funzionalità è implementata usando <strong><strong><strong><strong><strong><strong>chage</strong></strong></strong></strong></strong></strong>, che configura l'informazione di password in scadenza per un utente.</li><li>Un altro metodo è di forzare gli utenti a creare password complesse usando i moduli <strong><strong><strong><strong>PAM</strong></strong></strong> </strong>(<strong><strong><strong><strong>P</strong></strong></strong></strong>luggable <strong><strong><strong><strong>A</strong></strong></strong></strong>uthentication <strong><strong><strong><strong>M</strong></strong></strong></strong>odules). PAM può essere configurato automaticamente per verificare che una password creata o modificata usando l'utility <strong><strong><strong><strong>passwd </strong></strong></strong></strong>sia sufficientemente complessa. La configurazione di PAM è implementata usando una libreria chiamata &nbsp;<strong><strong><strong><strong><strong><strong>pam_cracklib.so</strong></strong></strong></strong></strong></strong>, che può essere rimpiazzata da <strong><strong><strong><strong><strong><strong>pam_passwdqc.so</strong></strong></strong></strong></strong></strong> per potere usufruire di più opzioni.</li><li>È anche possibile installare un programma di cracking di password come &nbsp;<a href="http://www.openwall.com/john/">John The Ripper</a>, per mettere in sicurezza il file delle password e per rilevare voci di password deboli. Si raccomanda di ottenere un'autorizzazione scritta prima di installare detto strumento su qualsiasi sistema se non di proprietà.</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/0ccd66e7a1088ab8450cac69aa9918fb/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/chagesuse.png" class="kg-image" alt="Using chage" width="754" height="277" loading="lazy"><figcaption>Utilizzare chage</figcaption></figure><h3 id="richiedere-password-per-il-boot-loader"><strong>Richiedere Password per il <strong>Boot Loader</strong></strong></h3><p>Puoi mettere in sicurezza il processo di avvio con una password per evitare che qualcuno possa saltare il passaggio di autenticazione utente. Questo può funzionare assieme alla protezione con password del BIOS. Nota che anche se il solo uso di una password per il bootloader impedirà a un utente di modificare la configurazione del bootloader durante il processo di avvio, <strong>non </strong>impedirà a un utente l'avvio tramite un media alternativo, come dischi ottici e chiavi USB. Pertanto dovrebbe essere usata assieme a una password del BIOS per una protezione completa.</p><figure class="kg-card kg-image-card"><img src="https://courses.edx.org/assets/courseware/v1/e74988af521d832ff71a899660352371/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/password.png" class="kg-image" alt="Sign saying: Password Required" width="550" height="299" loading="lazy"></figure><p>Per il metodo di avvio meno recente GRUB 1, era relativamente facile impostare una password per <strong><strong><strong><strong>grub</strong></strong></strong></strong>.<strong><strong><strong><strong> </strong></strong></strong></strong>Tuttavia, per la versione GRUB 2 le cose sono diventate più complicate, anche se si ha maggiore flessibilità e si può trarre vantaggio da funzionalità più avanzate come password specifiche per utente (che possono anche essere quelle del loro normale login).</p><p>Inoltre non modificherai mai <strong><strong><strong><strong><strong><strong>grub.cfg</strong></strong></strong></strong></strong></strong> direttamente; invece puoi modificare i file di configurazione in <strong><strong><strong><strong><strong><strong><code>/etc/grub.d</code></strong></strong></strong></strong></strong></strong> e <strong><strong><strong><strong><strong><strong><code>/etc/defaults/grub</code></strong></strong></strong></strong></strong></strong>, poi eseguire <strong><strong><strong><strong><code>update-grub</code></strong></strong></strong></strong>, oppure <code><strong><strong><strong><strong>grub2-mkconfig</strong></strong></strong></strong></code> e salvare il nuovo file di configurazione.</p><p>Per saperne di più, leggi il post seguente (in inglese): <em><em><em><em><a href="https://help.ubuntu.com/community/Grub2/Passwords" rel="noopener">"GRUB 2 Password Protection"</a></em></em></em></em>.</p><h3 id="vulnerabilit-dell-hardware"><strong>Vulnerabilità dell'H<strong>ardware</strong></strong></h3><p>Quando l'hardware è accessibile fisicamente, la sicurezza può essere compromessa da:</p><ul><li>Key logging<br>La registrazione in tempo reale dell'attività di un computer, compreso i tasti premuti. I dati catturati possono essere salvati localmente oppure trasmessi a macchine remote.</li><li>Network sniffing<br>La cattura e la visualizzazione del livello dati dei pacchetti sulla tua rete.</li><li>Avvio da un disco di ripristino o una distribuzione live</li><li>Rimontaggio e modifica del contenuto del disco.</li></ul><p>La politica di sicurezza della tua struttura IT dovrebbe partire dai requisiti su come accedere fisicamente in modo corretto a server e workstation. L'accesso fisico a un sistema rende possibile per gli aggressori di sfruttare diversi vettori di attacco, in modo tale che tutte le precauzioni a livello di sistema operativo diventino irrilevanti.</p><p>Le linee guida della sicurezza sono:</p><ul><li>Bloccare workstation e server.</li><li>Proteggere i punti di collegamento alla rete in modo tale che possano accedere solo persone di tua fiducia.</li><li>Proteggere le tue tastiere dove vengono digitate le password per assicurarsi che le tastiere non possano essere manomesse.</li><li>Assicurarsi che una password protegga il BIOS in modo tale che il sistema non possa essere avviato con una chiave USB o una distribuzione live su DVD.</li></ul><p>Per computer usati da un solo utente e quelli in un ambiente domestico alcune delle protezioni sopra citate (come prevenire l'avvio da media rimovibili) possono essere eccessive e puoi evitare di implementarle. Tuttavia se nel tuo sistema ci sono informazioni sensibili che richiedono una accurata protezione dovresti adottare le linee guida sopra citate oppure toglierle dal computer.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://courses.edx.org/assets/courseware/v1/a45dcc426b70817110e0d810f4df83a7/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/LFS01_ch18_screen27.jpg" class="kg-image" alt="Hardware Vulnerability" width="389" height="154" loading="lazy"><figcaption>Vulnerabilità Hardware</figcaption></figure><h3 id="vulnerabilit-software"><strong>Vulnerabilità <strong>Software</strong></strong></h3><p>Come tutti i software, gli hacker trovano occasionalmente punti deboli nell'ecosistema Linux. La forza di Linux (e della comunità open source in generale) è la velocità con cui tali vulnerabilità sono esposte e riparate. La copertura specifica delle vulnerabilità va oltre lo scopo di questo corso, ma la commissione di discussione può essere utilizzata per svolgere ulteriori discussioni.</p><figure class="kg-card kg-image-card"><img src="https://courses.edx.org/assets/courseware/v1/3ece571940430dd1c4cef1bcacfbc8c7/asset-v1:LinuxFoundationX+LFS101x+2T2021+type@asset+block/soft_vuln.png" class="kg-image" alt="Cartoon penguin opening the door" width="236" height="252" loading="lazy"></figure><h2 id="riepilogo-del-capitolo"><strong>Riepilogo del Capitolo</strong></h2><p>Hai completato il Capitolo 18. Riassumiamo i concetti chiave trattati:</p><ul><li>L'account di root ha autorità sull'intero sistema.</li><li>I privilegi di root possono essere richiesti per compiti come il riavvio di servizi, l'installazione manuale di pacchetti e la gestione di parti del filesystem che sono al di fuori della directory home.</li><li>Per poter esegure qualsiasi operazione con alti privilegi come modifiche a livello di sistema, devi usare &nbsp;<strong><strong><strong><strong>su</strong></strong></strong></strong> oppure <strong><strong><strong><strong><strong><strong>sudo</strong></strong></strong></strong></strong></strong>.</li><li>La chiamata a <strong><strong><strong><strong><strong><strong>sudo</strong></strong></strong></strong></strong></strong> attiva una ricerca nel file &nbsp;<strong><strong><strong><strong><strong><strong><code>/etc/sudoers</code></strong></strong></strong></strong></strong></strong>, oppure nella directory <strong><strong><strong><strong><strong><strong><code>/etc/sudoers.d</code></strong></strong></strong></strong></strong></strong>, che prima controlla che l'utente chiamante possa usare <strong><strong><strong><strong><strong><strong>sudo</strong></strong></strong></strong></strong></strong> e che venga usato all'interno dell'ambito consentito.</li><li>Una delle più potenti funzionalità di <strong><strong><strong><strong><strong><strong>sudo</strong></strong></strong></strong></strong></strong> è la capacità di registrare tentativi falliti per l'acquisizione di accesso a root. Per impostazione predefinita, i comandi <strong><strong><strong><strong>sudo</strong></strong></strong></strong> e i fallimenti sono registrati in <strong><strong><strong><strong><code>/var/log/auth.log</code></strong></strong></strong></strong> per quanto riguarda la famiglia Debian e in <strong><strong><strong><strong><code>/var/log/messages</code></strong></strong></strong></strong> nelle altre famiglie di distribuzioni.</li><li>Un processo non può accedere alle risorse di un altro processo, anche se quel processo è in esecuzione con gli stessi privilegi utente.</li><li>Tramite l'uso delle credenziali utente, il sistema verifica autenticità e identità.</li><li>L'algoritmo SHA-512 viene usato tipicamente per codificare le password. Possono essere codificate ma non decodificate.</li><li>Si possono configurare i Pluggable Authentication Modules (PAM) per verificare automaticamente che le password create o modificate con l'utility <strong><strong><strong><strong>passwd</strong></strong></strong></strong> siano sufficientemente complesse (può anche essere configurato quanto abbastanza complesse debbano essere).</li><li>La politica di sicurezza della tua struttura IT dovrebbe partire dai requisiti su come mettere propriamente in sicurezza l'accesso fisico a server e workstations.</li><li>Mantenere i tuoi sistemi aggiornati è un importante passo per evitare attacchi di sicurezza</li></ul> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
