/static/index.html
https://code.google.com/p/go-tour-it/ · HTML · 2323 lines · 1986 code · 329 blank · 8 comment · 0 complexity · e6160f3d6dac728a3d2d7c04f0c4bf3b MD5 · raw file
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
- <title>Un Tour nel Go</title>
- <!-- jQuery -->
- <script src="static/jquery.js"></script>
- <!-- Fonts -->
- <link href='http://fonts.googleapis.com/css?family=Droid+Serif&v1' rel='stylesheet' type='text/css'>
- <link href='http://fonts.googleapis.com/css?family=Droid+Sans&v1' rel='stylesheet' type='text/css'>
- <link href='http://fonts.googleapis.com/css?family=Droid+Sans+Mono&v1' rel='stylesheet' type='text/css'>
- <!-- Playground -->
- <link rel="stylesheet" href="/static/codemirror/lib/codemirror.css">
- <script src="/static/codemirror/lib/codemirror.js"></script>
- <link rel="stylesheet" href="/static/codemirror/theme/default.css">
- <script src="static/playground.js"></script>
- <!-- Tour -->
- <link rel="stylesheet" href="static/tour.css" charset="utf-8">
- <script src="static/mode.js"></script>
- <script src="static/tour.js"></script>
- </head>
- <body class="loading">
- <!-- Top bar -->
- <h2 id="slidenum"></h2>
- <div id="topnav" class="nav">
- <button id="tocbtn">Indice</button>
- <button id="codetr">Correggi*</button>
- </div>
- <h1>Un Tour nel Go (traduzione: 30%)</h1>
- <!-- Loading message -->
- <div id="loading">
- Caricamento schede...
- </div>
- <!-- Table of Contents -->
- <ol id="toc"></ol>
- <div id="slides" class="slides"><!-- begin slides -->
- <div class="toc">Benvenuto</div>
- <div class="slide">
- <h2>Ciao, 世界</h2>
- <p>
- Benvenuto nel tour del
- <a target="_blank" href="http://golang.org/">Linguaggio di Programmazione Go</a>.
- <p>
- Il tour è diviso in tre sezioni. Alla fine di ogni sezione
- c'è una serie di esercizi da svolgere.
- <p>
- Il tour è interattivo. Clicca su Run (o premi Shift-Invio)
- per compilare e avviare il programma sul
- <span class="appengineMode">server remoto.</span>
- <span class="localMode">tuo computer.</span>
- Il risultato apparirà sotto il codice.
- <p>
- I programmi di esempio evidenziano i diversi aspetti di Go.
- I programmi nel tour sono punti di partenza per le tue sperimentazioni.
- <p>
- Modifica il programma e avvialo ancora.
- <p>
- Quando credi di essere pronto, clicca su Next o premi PageDown (Pag Giù).
- <div>
- package main
- import "fmt"
- func main() {
- fmt.Println("Ciao, 世界")
- }
- </div>
- </div>
- <div class="slide nocode appengineMode">
- <h2>Go offline</h2>
- <p>
- Questo tour è disponibile anche come programma indipendente,
- usabile senza connessione a internet.
- <p>
- Il tour offline è più veloce nell'avviare e gestire il codice di esempio
- e include esercizi che non sono disponibili nella versione online.
- <p>
- Prima di avviare il tour in locale
- <a target="_blank" href="http://golang.org/doc/install.html">installa Go</a> (l'ultima release, <code>release.r60</code>),
- quindi usa
- <a target="_blank" href="http://golang.org/cmd/goinstall/">goinstall</a>
- per installare
- <a target="_blank" href="http://code.google.com/p/go-tour/">gotour</a>:
- <pre> goinstall go-tour.googlecode.com/hg/gotour</pre>
- <p>
- e avvia l'eseguibile <code>gotour</code>.
- <p>
- Altrimenti, fai clic sul pulsante "Next" o premi PagGiù per continuare.
- <p>
- <i>(Puoi tornare a queste istruzioni in qualsiasi momento facendo clic sul pulsante "Indice")</i>
- </div>
- <div class="slide nocode appengineMode">
- <h2>Go nella tua lingua</h2>
- <p>
- Il tour è disponibile in altre lingue:
- <ul>
- <li><a href="http://go-tour-jp.appspot.com/">Giapponese — 日本語</a></li>
- <li><a href="http://go-tour-kr.appspot.com/">Coreano — 한국어</a></li>
- <li><a href="http://go-tour-it.appspot.com/">Italiano</a>
- <a href="http://code.google.com/p/go-tour-it/source/browse/static/index.html">(contribuisci)</a>
- </li>
- </ul>
- <p>
- (Se si desidera tradurre il tour in un'altra lingua, basta scaricare i sorgenti da<br>
- <code>https://go-tour.googlecode.com/hg</code>, tradurre <code>static/index.html</code> e
- distribuirlo su App Engine utilizzando le istruzioni nel file <code>appengine/README</code>.)
- <p>
- Fare clic sul pulsante "Next" o PagGiù per continuare.
- </div>
- <div class="toc">Introduzione</div>
- <div class="slide">
- <h2>Packages (Pacchetti)</h2>
- <p>
- Ogni programma Go è costituito da Pacchetti.
- <p>
- I programmi iniziano a caricarsi dal pacchetto <code>main</code>.
- <p>
- Questo programma utilizza i pacchetti <code>"fmt"</code> e <code>"math"</code>
- infatti sono nel percorso di importazione.
- <p>
- Per convenzione, il nome del pacchetto è lo stesso dell'ultimo
- elemento del percorso di importazione.(?)
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func main() {
- fmt.Println("Buon", math.Pi, "day")
- }
- </div>
- </div>
- <div class="slide">
- <h2>Imports</h2>
- <p>
- Questo codice raggruppa gli Imports in una parentesi, il metodo di importazione "scomposto".
- Si possono anche scrivere più istruzioni import, come:
- <pre>
- import "fmt"
- import "math"
- </pre>
- ma è di comune utilizzo il metodo "scomposto" per eliminare il disordine.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func main() {
- fmt.Printf("Adesso hai %g problemi.",
- math.Nextafter(2, 3))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exported Names</h2>
- <p>
- Dopo aver importato un pacchetto, è possibile fare riferimento ai suoi nomi.
- <p>
- In Go, un nome viene esportato se inizia con la lettera maiuscola.
- <p>
- <code>Pi</code> è un nome esportato, come <code>PI</code>.
- Il nome <code>pi</code> non è esportato.
- <p>
- Esegui il codice. Quindi rinomina <code>math.pi</code> in <code>math.Pi</code> e riprova.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func main() {
- fmt.Println(math.pi)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Funzioni</h2>
- <p>
- Una funzione può assumere zero o più argomenti.
- <p>
- In questo esempio, <code>add</code> accetta due parametri di tipo <code>int</code>.
- <p>
- Si noti che il tipo viene <i>dopo</i> il nome della variabile.
- <p>
- (Per maggiori informazioni sul funzionamento dei tipi, si veda questo <a target="_blank" href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">post del blog</a>)
- <div>
- package main
- import "fmt"
- func add(x int, y int) int {
- return x + y
- }
- func main() {
- fmt.Println(add(42, 13))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Funzioni</h2>
- <p>
- Quando due o più nomi consecutivi condividono il tipo,
- è possibile omettere il tipo da tutti tranne l'ultimo.
- <p>
- In questo esempio, abbiamo accorciato
- <pre>x int, y int</pre>
- <p>
- in
- <pre>x, y int</pre>
- <div>
- package main
- import "fmt"
- func add(x, y int) int {
- return x + y
- }
- func main() {
- fmt.Println(add(42, 13))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Funzioni</h2>
- <p>
- Una funzione può restituire qualsiasi numero di risultati.
- <p>
- Questa funzione restituisce due stringhe.
- <div>
- package main
- import "fmt"
- func swap(x, y string) (string, string) {
- return y, x
- }
- func main() {
- a, b := swap("ciao", "mondo")
- fmt.Println(a, b)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Funzioni</h2>
- <p>
- Le funzioni prendono parametri; in Go i risultati possono essere nominati e
- si comportano come variabili; questi sono chiamati "result parameters".
- <p>
- Se i "result parameters" sono stati nominati, un <code>return</code> senza argomenti
- restituisce i valori correnti dei risultati.
- <div>
- package main
- import "fmt"
- func split(sum int) (x, y int) {
- x = sum * 4/9
- y = sum - x
- return
- }
- func main() {
- fmt.Println(split(17))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Variabili</h2>
- <p>
- L' istruzione <code>var</code> dichiara una lista di variabili.<br>
- Come negli elenchi di argomenti delle funzioni, il tipo è alla fine.
- <div>
- package main
- import "fmt"
- var x, y, z int
- var c, python, java bool
- func main() {
- fmt.Println(x, y, z, c, python, java)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Variabili</h2>
- <p>
- Una dichiarazione var può includere gli inizializzatori, uno per ogni variabile.
- <p>
- Se un initializer è presente, il tipo può essere omesso;
- la variabile prenderà il tipo dell' inizializer.
- <div>
- package main
- import "fmt"
- var x, y, z int = 1, 2, 3
- var c, python, java = true, false, "no!"
- func main() {
- fmt.Println(x, y, z, c, python, java)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Variabili</h2>
- <p>
- All'interno di una funzione, l'istruzione di assegnazione breve <code>:=</code>
- può essere usata al posto della dichiarazione breve <code>var</code>.
- <p>
- (Al di fuori di una funzione, ogni costrutto inizia con una
- parola chiave mentre l'istruzione := non è disponibile).
- <div>
- package main
- import "fmt"
- func main() {
- var x, y, z int = 1, 2, 3
- c, python, java := true, false, "no!"
- fmt.Println(x, y, z, c, python, java)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Constanti</h2>
- <p>
- Le constanti vengono dichiarate come le variabili, ma con la parola-chiave <code>const</code>.
- <p>
- Le costanti possono essere stringhe, boolean o valori numerici.
- <div>
- package main
- import "fmt"
- const Pi = 3.14
- func main() {
- const World = "世界"
- fmt.Println("Hello", World)
- fmt.Println("Happy", Pi, "Day")
- const Truth = true
- fmt.Println("Go rules?", Truth)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Costanti numeriche</h2>
- <p>
- Le costanti numeriche sono <i>valori</i> ad alta precisione.
- <p>
- Una costante senza tipo prende il tipo necessario dal suo contesto.
- <p>
- Prova a stampare anche <code>needInt(Big)</code>.
- <div>
- package main
- import "fmt"
- const (
- Big = 1<<100
- Small = Big>>99
- )
- func needInt(x int) int { return x*10 + 1 }
- func needFloat(x float64) float64 {
- return x*0.1
- }
- func main() {
- fmt.Println(needInt(Small))
- fmt.Println(needFloat(Small))
- fmt.Println(needFloat(Big))
- }
- </div>
- </div>
- <div class="slide">
- <h2>For</h2>
- <p>
- Go ha solo un costrutto per le operazioni cicliche:<br>
- il ciclo <code>for</code>.
- <p>
- Il ciclo <code>for</code> appare come in C o Java, salvo che
- le parentesi tonde <code>( )</code> non esistono (non sono
- nemmeno opzionali) mentre le graffe <code>{ }</code> sono obbligatorie.
- <div>
- package main
- import "fmt"
- func main() {
- sum := 0
- for i := 0; i < 10; i++ {
- sum += i
- }
- fmt.Println(sum)
- }
- </div>
- </div>
- <div class="slide">
- <h2>For</h2>
- <p>
- Come in C o Java, è possibile lasciare le dichiarazioni pre e post vuote.
- <div>
- package main
- import "fmt"
- func main() {
- sum := 1
- for ; sum < 1000; {
- sum += sum
- }
- fmt.Println(sum)
- }
- </div>
- </div>
- <div class="slide">
- <h2>For</h2>
- <p>
- A questo punto è possibile eliminare i punti-virgola:
- Per ottenere ciò che in C avremmo scritto <code>while</code> in Go scriviamo <code>for</code>.
- <div>
- package main
- import "fmt"
- func main() {
- sum := 1
- for sum < 1000 {
- sum += sum
- }
- fmt.Println(sum)
- }
- </div>
- </div>
- <div class="slide">
- <h2>For</h2>
- <p>
- Se si omette la condizione del ciclo, il ciclo continua per sempre.
- <div>
- package main
- func main() {
- for ; ; {
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>For</h2>
- <p>
- E senza condizioni, i punti-virgola possono essere omessi.
- Ecco come appare un ciclo infinito compatto.
- <div>
- package main
- func main() {
- for {
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>If</h2>
- <p>
- L'istruzione <code>if</code> è si comporta come in C o Java,
- salvo che le parentesi tonde <code>( )</code> non esistono (non sono nemmeno opzionali)
- e le graffe <code>{ }</code> sono obbligatorie.
- <p>
- (Ti ricorda qualcosa?)
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func sqrt(x float64) string {
- if x < 0 {
- return sqrt(-x) + "i"
- }
- return fmt.Sprint(math.Sqrt(x))
- }
- func main() {
- fmt.Println(sqrt(2), sqrt(-4))
- }
- </div>
- </div>
- <div class="slide">
- <h2>If</h2>
- <p>
- Come <code>for</code>, l'istruzione <code>if</code> può iniziare
- con una breve dichiarazione da eseguire prima della condizione.
- <p>
- Le variabili dichiarate dalla dichiarazione sono disponibili solo fino alla fine del <code>if</code>.
- <p>
- (Prova ad usare <code>v</code> nell'ultima istruzione <code>return</code>.)
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func pow(x, n, lim float64) float64 {
- if v := math.Pow(x, n); v < lim {
- return v
- }
- return lim
- }
- func main() {
- fmt.Println(
- pow(3, 2, 10),
- pow(3, 3, 20),
- )
- }
- </div>
- </div>
- <div class="slide">
- <h2>If</h2>
- <p>
- Le variabili dichiarate all'interno di una istruzione <code>if</code>
- sono disponibili anche in una qualsiasi dei blocchi <code>else</code>.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func pow(x, n, lim float64) float64 {
- if v := math.Pow(x, n); v < lim {
- return v
- } else {
- fmt.Printf("%g >= %g\n", v, lim)
- }
- // can't use v here, though
- return lim
- }
- func main() {
- fmt.Println(
- pow(3, 2, 10),
- pow(3, 3, 20),
- )
- }
- </div>
- </div>
- <div class="slide">
- <h2>Tipi di base</h2>
- <p>
- I tipi di base di Go sono:
- <pre>
- bool
- string
- int int8 int16 int32 int64
- uint uint8 uint16 uint32 uint64 uintptr
- float32 float64
- complex64 complex128
- </pre>
- <div>
- package main
- import (
- "cmath"
- "fmt"
- )
- var (
- ToBe bool = false
- MaxInt uint64 = 1<<64 - 1
- z complex128 = cmath.Sqrt(-5+12i)
- )
- func main() {
- const f = "%T(%v)\n"
- fmt.Printf(f, ToBe, ToBe)
- fmt.Printf(f, MaxInt, MaxInt)
- fmt.Printf(f, z, z)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Structs (strutture)</h2>
- <p>
- Una <code>struct</code> è un insieme di campi.
- <p>
- (E le dichiarazioni <code>type</code> si comportano come vi aspettereste.)
- <div>
- package main
- import "fmt"
- type Vertex struct {
- X int
- Y int
- }
- func main() {
- fmt.Println(Vertex{1, 2})
- }
- </div>
- </div>
- <div class="slide">
- <h2>Struct Fields (Campi Struttura)</h2>
- <p>
- Un Struct field è accessibile tramite un punto.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- X int
- Y int
- }
- func main() {
- v := Vertex{1, 2}
- v.X = 4
- fmt.Println(v.X)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Pointers (Puntatori)</h2>
- <p>
- Go utilizza i puntatori, ma non l'aritmetica dei puntatori.
- <p>
- I campi struct sono accessibili tramite puntatori struct.<br>
- L'indirezione attraverso il puntatore è trasparente.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- X int
- Y int
- }
- func main() {
- p := Vertex{1, 2}
- q := &p
- q.X = 1e9
- fmt.Println(p)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Struct Literals (letterali)</h2>
- <p>
- Una struttura letterale denota un valore struct appena allocato elencando i valori dei suoi campi.
- <p>
- Si possono elencare solo un sottoinsieme di campi utilizzando la sintassi <code>Name:</code>.
- (L'ordine dei campi di nome è irrilevante)
- <p>
- Il prefisso specifico <code>&</code> costituisce un puntatore ad una struct letterale.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- X, Y int
- }
- var (
- p = Vertex{1, 2} // has type Vertex
- q = &Vertex{1, 2} // has type *Vertex
- r = Vertex{X: 1} // Y:0 is implicit
- s = Vertex{} // X:0 and Y:0
- )
- func main() {
- fmt.Println(p, q, r, s)
- }
- </div>
- </div>
- <div class="slide">
- <h2>La funzione <code>new</code></h2>
- <p>
- L'espressione new(T) alloca un valore T azzerato e restituisce un puntatore ad esso.
- <pre>var t *T = new(T)</pre>
- <p>
- oppure
- <pre>t := new(T)</pre>
- <div>
- package main
- import "fmt"
- type Vertex struct {
- X, Y int
- }
- func main() {
- v := new(Vertex)
- fmt.Println(v)
- v.X, v.Y = 11, 9
- fmt.Println(v)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Maps (Mappe)</h2>
- <p>
- Una map mappa (verbo mappare) chiavi per i valori.
- <p>
- <!-- TODO: empty part not true in compilers yet -->
- Le mappe devono essere creati con <code>make</code> (non <code>new</code>) prima dell'uso;
- il <code>nil</code> map è vuoto e non può essere assegnato.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- Lat, Long float64
- }
- var m map[string]Vertex
- func main() {
- m = make(map[string]Vertex)
- m["Bell Labs"] = Vertex{
- 40.68433, 74.39967,
- }
- fmt.Println(m["Bell Labs"])
- }
- </div>
- </div>
- <div class="slide">
- <h2>Maps (letterali)</h2>
- <p>
- Map literals sono come le strutture letterali, ma le chiavi sono obbligatore.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- Lat, Long float64
- }
- var m = map[string]Vertex{
- "Bell Labs": Vertex{
- 40.68433, -74.39967,
- },
- "Google": Vertex{
- 37.42202, -122.08408,
- },
- }
- func main() {
- fmt.Println(m)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Maps</h2>
- <p>
- Se il tipo primcipale è solo un nome del tipo,
- è possibile omettere dagli elementi del letterale.
- <div>
- package main
- import "fmt"
- type Vertex struct {
- Lat, Long float64
- }
- var m = map[string]Vertex{
- "Bell Labs": {40.68433, -74.39967},
- "Google": {37.42202, -122.08408},
- }
- func main() {
- fmt.Println(m)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Slices (Porzioni)</h2>
- <p>
- Una slice punta a un array di valori e comprende anche una lunghezza.
- <p>
- <code>[]T</code> è una slice con elementi del tipo <code>T</code>.
- <div>
- package main
- import "fmt"
- func main() {
- p := []int{2, 3, 5, 7, 11, 13}
- fmt.Println("p ==", p)
- for i := 0; i < len(p); i++ {
- fmt.Printf("p[%d] == %d\n",
- i, p[i])
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Slices</h2>
- <p>
- Le Slices possono essere ripartite a loro volta, la creazione di un nuovo
- valore slice che punta allo stesso array.
- <p>
- L'espressione
- <pre>s[lo:hi]</pre>
- <p>
- restituisce una slice di elementi da <code>lo</code> attraverso <code>hi-1</code>, estremi inclusi.
- In questo modo,
- <pre>s[lo:lo]</pre>
- <p>
- è vuota e
- <pre>s[lo:lo+1]</pre>
- <p>
- ha un valore.
- <div>
- package main
- import "fmt"
- func main() {
- p := []int{2, 3, 5, 7, 11, 13}
- fmt.Println("p ==", p)
- fmt.Println("p[1:4] ==", p[1:4])
- // l'assenza dell' indice basso implica 0
- fmt.Println("p[:3] ==", p[:3])
- // l'assenza dell' indice alto implica len(s)
- fmt.Println("p[4:] ==", p[4:])
- }
- </div>
- </div>
- <div class="slide">
- <h2>Slices</h2>
- <p>
- Le Slices si creano con la funzione <code>make</code>. Funziona allocando
- un array azzerato e restituendo una slice che fa riferimento a tale array:
- <pre>
- a := make([]int, 5) // len(a)=5
- </pre>
- Le Slices hanno lunghezza (len) e capacità (cap). La capacità di una slice è
- la lunghezza massima che la slice può raggiungere all'interno dell' array sottostante.
- <p>
- Per specificare una capacità, basta passare un terzo argomento a <code>make</code>:
- <p>
- <pre>
- b := make([]int, 0, 5)
- // len(b)=0, cap(b)=5
- </pre>
- Le Slices possono essere alimentate dal "re-slicing" (fino alla loro capacità):
- <p>
- <pre>
- b = b[:cap(b)] // len(b)=5, cap(b)=5
- b = b[1:] // len(b)=4, cap(b)=4
- </pre>
- <div>
- package main
- import "fmt"
- func main() {
- a := make([]int, 5)
- printSlice("a", a)
- b := make([]int, 0, 5)
- printSlice("b", b)
- c := b[:2]
- printSlice("c", c)
- d := c[2:5]
- printSlice("d", d)
- }
- func printSlice(s string, x []int) {
- fmt.Printf("%s len=%d cap=%d %v\n",
- s, len(x), cap(x), x)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Slices</h2>
- <p>
- The zero value of a slice is <code>nil</code>.
- <p>
- A nil slice has a length and capacity of 0.
- <p>
- <i>For more detail see the
- "<a target="_blank" href="http://blog.golang.org/2011/01/go-slices-usage-and-internals.html">Go Slices: usage and internals</a>"
- article.</i>
- <div>
- package main
- import "fmt"
- func main() {
- var z []int
- fmt.Println(z, len(z), cap(z))
- if z == nil {
- fmt.Println("nil!")
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Functions</h2>
- <p>
- Functions are values too.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- func main() {
- hypot := func(x, y float64) float64 {
- return math.Sqrt(x*x + y*y)
- }
- fmt.Println(hypot(3, 4))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Functions</h2>
- <p>
- And functions are full closures.
- <p>
- The <code>adder</code> function returns a closure.
- Each closure is bound to its own <code>sum</code> variable.
- <div>
- package main
- import "fmt"
- func adder() func(int) int {
- sum := 0
- return func(x int) int {
- sum += x
- return sum
- }
- }
- func main() {
- pos, neg := adder(), adder()
- for i := 0; i < 10; i++ {
- fmt.Println(
- pos(i),
- neg(-2*i),
- )
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Range</h2>
- <p>
- The <code>range</code> form of the <code>for</code>
- loop iterates over a slice or map.
- <div>
- package main
- import "fmt"
- var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
- func main() {
- for i, v := range pow {
- fmt.Printf("2**%d = %d\n", i, v)
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Range</h2>
- <p>
- You can skip the key or value by assigning to <code>_</code>.
- <p>
- If you only want the index, drop the
- “<code>, value</code>” entirely.
- <div>
- package main
- import "fmt"
- func main() {
- pow := make([]int, 10)
- for i := range pow {
- pow[i] = 1<<uint(i)
- }
- for _, value := range pow {
- fmt.Printf("%d\n", value)
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Switch</h2>
- <p>
- You probably knew what <code>switch</code> was going to look like.
- <p>
- A case body breaks automatically, unless it ends with a <code>fallthrough</code> statement.
- <div>
- package main
- import (
- "fmt"
- "runtime"
- )
- func main() {
- fmt.Print("Go runs on ")
- switch os := runtime.GOOS; os {
- case "darwin":
- fmt.Println("OS X.")
- case "linux":
- fmt.Println("Linux.")
- default:
- // freebsd, openbsd,
- // plan9, windows...
- fmt.Printf("%s.", os)
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Switch</h2>
- <p>
- Switch cases evaluate cases from top to bottom, stopping when a
- case succeeds.
- <p>
- (For example,
- <pre>
- switch i {
- case 0:
- case f():
- }</pre>
- <p>
- does not call <code>f</code> if <code>i==0</code>.)
- <div>
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- fmt.Println("When's Saturday?")
- today := time.LocalTime().Weekday
- switch time.Saturday {
- case today+0:
- fmt.Println("Today.")
- case today+1:
- fmt.Println("Tomorrow.")
- case today+2:
- fmt.Println("In two days.")
- default:
- fmt.Println("Too far away.")
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Switch</h2>
- <p>
- Switch without a condition is the same as <code>switch true</code>.
- <div>
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- t := time.LocalTime()
- switch {
- case t.Hour < 12:
- fmt.Println("Good morning!")
- case t.Hour < 17:
- fmt.Println("Good afternoon.")
- default:
- fmt.Println("Good evening.")
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Loops and Functions</h2>
- <p>
- As a simple way to play with functions and loops, implement
- the square root function using Newton's method.
- <p>
- In this case, Newton's method is to approximate <code>Sqrt(x)</code>
- by picking a starting point <i>z</i> and then repeating:
- <center>
- <img src="https://chart.googleapis.com/chart?cht=tx&chl=z=z-\frac{z^2-x}{2z}">
- </center>
- <p>
- To begin with, just repeat that calculation 10 times and see how close you
- get to the answer for various values (1, 2, 3, ...).
- <p>
- Next, change the loop condition to stop once the value has stopped
- changing (or only changes by a very small delta).
- See if that's more or fewer iterations.
- How close are you to the <a target="_blank" href="http://golang.org/pkg/math/#Sqrt">math.Sqrt</a>?
- <p>
- Hint: to declare and initialize a floating point value, give it
- floating point syntax or use a conversion:
- <pre>
- z := float64(0)
- z := 0.0
- </pre>
- <div>
- package main
- import (
- "fmt"
- )
- func Sqrt(x float64) float64 {
- }
- func main() {
- fmt.Println(Sqrt(2))
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Maps</h2>
- <p>
- Implement <code>WordCount</code>. It should return a map of the
- counts of each “word” in the string <code>s</code>.
- The <code>wc.Test</code> function runs a test suite against the
- provided function and prints success or failure.
- <p>
- You might find <a target="_blank" href="http://golang.org/pkg/strings/#Fields">strings.Fields</a> helpful.
- <div>
- package main
- import (
- "<span class="appengineMode">tour</span><span class="localMode">go-tour.googlecode.com/hg</span>/wc"
- )
- func WordCount(s string) map[string]int {
- return map[string]int{"x": 1}
- }
- func main() {
- wc.Test(WordCount)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Slices</h2>
- <p>
- Implement <code>Pic</code>. It should return a slice of length
- <code>dy</code>, each element of which is a slice of <code>dx</code>
- 8-bit unsigned integers. When you run the program, it will display
- your picture, interpreting the integers as grayscale (well, bluescale)
- values.
- <p>
- The choice of image is up to you.
- Interesting functions include <code>x^y</code>, <code>(x+y)/2</code>, and <code>x*y</code>.
- <p>
- (You need to use a loop to allocate each <code>[]uint8</code> inside
- the <code>[][]uint8</code>.)
- <div>
- package main
- import "<span class="appengineMode">tour</span><span class="localMode">go-tour.googlecode.com/hg</span>/pic"
- func Pic(dx, dy int) [][]uint8 {
- }
- func main() {
- pic.Show(Pic)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Fibonacci closure</h2>
- <p>
- Let's have some fun with functions.
- <p>
- Implement a <code>fibonacci</code> function that returns a function
- (a closure) that returns successive fibonacci numbers.
- <div>
- package main
- import "fmt"
- // fibonacci is a function that returns
- // a function that returns an int.
- func fibonacci() func() int {
- }
- func main() {
- f := fibonacci()
- for i := 0; i < 10; i++ {
- fmt.Println(f())
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Advanced Exercise: Complex cube roots</h2>
- <p>
- Let's explore Go's built-in support for complex numbers via the
- <code>complex64</code> and <code>complex128</code> types.
- For cube roots, Newton's method amounts to repeating:
- <center>
- <img src="https://chart.googleapis.com/chart?cht=tx&chl=z=z-\frac{z^3-x}{3z^2}">
- </center>
- <p>
- Find the cube root of 2, just to make sure the algorithm works.
- There is a <a target="_blank" href="http://golang.org/pkg/cmath/#Pow">cmath.Pow</a> function.
- <div>
- package main
- import "fmt"
- func Cbrt(x complex128) complex128 {
- }
- func main() {
- fmt.Println(Cbrt(2))
- }
- </div>
- </div>
- <div class="toc">Methods and Interfaces</div>
- <div class="slide nocode">
- <h2>Methods and Interfaces</h2>
- </div>
- <div class="slide">
- <h2>Methods</h2>
- <p>
- Go does not have classes. However, you can define methods on struct
- types.
- <p>
- The <i>method receiver</i> appears in its own argument list
- between the <code>func</code> keyword and the method name.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- type Vertex struct {
- X, Y float64
- }
- func (v *Vertex) Abs() float64 {
- return math.Sqrt(v.X*v.X + v.Y*v.Y)
- }
- func main() {
- v := &Vertex{3, 4}
- fmt.Println(v.Abs())
- }
- </div>
- </div>
- <div class="slide">
- <h2>Methods</h2>
- <p>
- In fact, you can define a method on <i>any</i> type you define in your
- package, not just structs.
- <p>
- You cannot define a method on a type from another package, or on a
- basic type.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- type MyFloat float64
- func (f MyFloat) Abs() float64 {
- if f < 0 {
- return float64(-f)
- }
- return float64(f)
- }
- func main() {
- f := MyFloat(-math.Sqrt2)
- fmt.Println(f.Abs())
- }
- </div>
- </div>
- <div class="slide">
- <h2>Methods with pointer receivers</h2>
- <p>
- Methods can be associated with a named type or a pointer
- to a named type.
- <p>
- We just saw two <code>Abs</code> methods. One on the
- <code>*Vertex</code> pointer type and the other on the
- <code>MyFloat</code> value type.
- <p>
- There are two reasons to use a pointer receiver.
- First, to avoid copying the value on each method call (more efficient
- if the value type is a large struct). Second, so that the method can
- modify the value that its receiver points to.
- </ol>
- <p>
- Try changing the declarations of the <code>Abs</code> and
- <code>Scale</code> methods to use <code>Vertex</code> as the
- receiver, instead of <code>*Vertex</code>.
- <p>
- The <code>Scale</code> method has no effect when <code>v</code> is a
- <code>Vertex</code>. <code>Scale</code> mutates <code>v</code>. When
- <code>v</code> is a value (non-pointer) type, the method sees a copy of
- the <code>Vertex</code> and cannot mutate the original value.
- <p>
- <code>Abs</code> works either way. It only reads <code>v</code>.
- It doesn't matter whether it is reading the original value (through a
- pointer) or a copy of that value.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- type Vertex struct {
- X, Y float64
- }
- func (v *Vertex) Scale(f float64) {
- v.X = v.X * f
- v.Y = v.Y * f
- }
- func (v *Vertex) Abs() float64 {
- return math.Sqrt(v.X*v.X + v.Y*v.Y)
- }
- func main() {
- v := &Vertex{3, 4}
- v.Scale(5)
- fmt.Println(v, v.Abs())
- }
- </div>
- </div>
- <div class="slide">
- <h2>Interfaces</h2>
- <p>
- An interface type is defined by a set of methods.
- <p>
- A value of interface type can hold any value that
- implements those methods.
- <div>
- package main
- import (
- "fmt"
- "math"
- )
- type Abser interface {
- Abs() float64
- }
- func main() {
- var a Abser
- f := MyFloat(-math.Sqrt2)
- v := Vertex{3, 4}
- a = f // a MyFloat implements Abser
- a = &v // a *Vertex implements Abser
- a = v // a Vertex, does NOT
- // implement Abser
- fmt.Println(a.Abs())
- }
- type MyFloat float64
- func (f MyFloat) Abs() float64 {
- if f < 0 {
- return float64(-f)
- }
- return float64(f)
- }
- type Vertex struct {
- X, Y float64
- }
- func (v *Vertex) Abs() float64 {
- return math.Sqrt(v.X*v.X + v.Y*v.Y)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Interfaces</h2>
- <p>
- A type implements an interface by implementing the methods.
- <p>
- <i>There is no explicit declaration of intent.</i>
- <p>
- Implicit interfaces decouple implementation packages from the packages
- that define the interfaces: neither depends on the other.
- <p>
- It also encourages the definition of precise interfaces, because you
- don't have to find every implementation and tag it with the new
- interface name.
- <p>
- <a target="_blank" href="http://golang.org/pkg/io/">Package io</a> defines <code>Reader</code> and <code>Writer</code>; you don't have to.
- <div>
- package main
- import (
- "fmt"
- "os"
- )
- type Reader interface {
- Read(b []byte) (n int, err os.Error)
- }
- type Writer interface {
- Write(b []byte) (n int, err os.Error)
- }
- type ReadWriter interface {
- Reader
- Writer
- }
- func main() {
- var w Writer
- // os.Stdout implements Writer
- w = os.Stdout
- fmt.Fprintf(w, "hello, writer\n")
- }
- </div>
- </div>
- <div class="slide">
- <h2>Errors</h2>
- <p>
- An error is anything that can describe itself:
- <pre>
- package os
- type Error interface {
- String() string
- }
- </pre>
- <div>
- package main
- import (
- "fmt"
- "os"
- "time"
- )
- type MyError struct {
- When *time.Time
- What string
- }
- func (e *MyError) String() string {
- return fmt.Sprintf("at %v, %s",
- e.When, e.What)
- }
- func run() os.Error {
- return &MyError{
- time.LocalTime(),
- "it didn't work",
- }
- }
- func main() {
- if err := run(); err != nil {
- fmt.Println(err)
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Web servers</h2>
- <p>
- <a target="_blank" href="http://golang.org/pkg/http/">Package http</a> serves HTTP requests using any value
- that implements <code>http.Handler</code>:
- <pre>
- package http
- type Handler interface {
- ServeHTTP(w ResponseWriter,
- r *Request)
- }
- </pre>
- <p>
- In this example, the type <code>MyHandler</code> implements <code>http.Handler</code>.
- <p>
- <span class="localMode">
- Visit <a href="http://localhost:4000/" target="_blank">http://localhost:4000/</a> to see the greeting.
- </span>
- <span class="appengineMode">
- <b>Note:</b> This example won't run through the web-based tour user
- interface. To try writing web servers you may want to
- <a target="_blank" href="http://golang.org/doc/install.html">Install
- Go</a>.
- </span>
- <div>
- package main
- import (
- "fmt"
- "http"
- )
- type Hello struct{}
- func (h Hello) ServeHTTP(
- w http.ResponseWriter,
- r *http.Request) {
- fmt.Fprint(w, "Hello!")
- }
- func main() {
- var h Hello
- http.ListenAndServe("localhost:4000",h)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Images</h2>
- <p>
- <a target="_blank" href="http://golang.org/pkg/image/#Image">Package image</a> defines the <code>Image</code>
- interface:
- <pre>
- package image
- type Image interface {
- ColorModel() ColorModel
- Bounds() Rectangle
- At(x, y int) Color
- }</pre>
- <p>
- (See <a target="_blank" href="http://golang.org/pkg/image/#Image">the
- documentation</a> for all the details.)
- <p>
- <code>Color</code> and <code>ColorModel</code> are interfaces too,
- but we'll ignore that by using the predefined implementations
- <code>image.RGBAColor</code> and <code>image.RGBAColorModel</code>.
- <div>
- package main
- import (
- "fmt"
- "image"
- )
- func main() {
- m := image.NewRGBA(100, 100)
- fmt.Println(m.Bounds())
- fmt.Println(m.At(0, 0).RGBA())
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Errors</h2>
- <p>
- Copy your <code>Sqrt</code> function from the earlier exercises and
- modify it to return an <code>os.Error</code> value.
- <p>
- <code>Sqrt</code> should return a non-nil error value when given a
- negative number, as it doesn't support complex numbers.
- <p>
- Create a new type
- <pre>
- type ErrNegativeSqrt float64</pre>
- <p>
- and make it an <code>os.Error</code> by giving it a
- <pre>
- func (e ErrNegativeSqrt) String() string</pre>
- <p>
- method such that <code>ErrNegativeSqrt(-2).String()</code> returns
- <code>"cannot Sqrt negative number: -2"</code>.
- <p>
- <b>Note:</b> a call to <code>fmt.Print(e)</code> inside the
- <code>String</code> method will send the program into an infinite loop.
- You can avoid this by converting <code>e</code> first:
- <code>fmt.Print(float64(e))</code>. Why?
- <p>
- Change your <code>Sqrt</code> function to return an
- <code>ErrNegativeSqrt</code> value when given a negative number.
- <div>
- package main
- import (
- "fmt"
- "os"
- )
- func Sqrt(f float64) (float64, os.Error) {
- return 0, nil
- }
- func main() {
- fmt.Println(Sqrt(2))
- fmt.Println(Sqrt(-2))
- }
- </div>
- </div>
- <div class="slide localMode">
- <h2>Exercise: HTTP Handlers</h2>
- <p>
- Implement the following types and define ServeHTTP methods on them.
- Register them to handle specific paths in your web server.
- <pre>type String string
-
- type Struct struct {
- Greeting string
- Punct string
- Who string
- }</pre>
- <p>
- For example, you should be able to register handlers using:
- <pre>http.Handle("/string", String("I'm a frayed knot."))
- http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})</pre>
- <div>
- package main
- import (
- "http"
- )
- func main() {
- // your http.Handle calls here
- http.ListenAndServe("localhost:4000", nil)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Images</h2>
- <p>
- Remember the picture generator you wrote earlier?
- Let's write another one, but this time it will return
- an implementation of <code>image.Image</code> instead of a slice of data.
- <p>
- Define your own <code>Image</code> type, implement
- <a target="_blank" href="http://golang.org/pkg/image/#Image" target="_blank">the necessary methods</a>,
- and call <code>pic.ShowImage</code>.
- <p>
- <code>Bounds</code> should return a <code>image.Rectangle</code>, like
- <code>image.Rect(0, 0, w, h)</code>.
- <p>
- <code>ColorModel</code> should return <code>image.RGBAColorModel</code>.
- <p>
- <code>At</code> should return a color;
- the value <code>v</code> in the last picture generator corresponds to
- <code>image.RGBAColor{v, v, 255, 255}</code> in this one.
- <div>
- package main
- import (
- "image"
- "<span class="appengineMode">tour</span><span class="localMode">go-tour.googlecode.com/hg</span>/pic"
- )
- type Image struct{}
- func main() {
- m := Image{}
- pic.ShowImage(m)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Rot13 Reader</h2>
- <p>
- A common pattern is an
- <a target="_blank" href="http://golang.org/pkg/io/#Reader">io.Reader</a> that wraps
- another <code>io.Reader</code>, modifying the stream in some way.
- <p>
- For example, the
- <a target="_blank" href="http://golang.org/pkg/compress/gzip/#Decompressor.NewReader">gzip.NewReader</a>
- function takes an <code>io.Reader</code> (a stream of gzipped data)
- and returns a <code>*gzip.Decompressor</code> that also implements
- <code>io.Reader</code> (a stream of the decompressed data).
- <p>
- Implement a <code>rot13Reader</code> that implements
- <code>io.Reader</code> and reads from an <code>io.Reader</code>,
- modifying the stream by applying the
- <a target="_blank" href="http://en.wikipedia.org/wiki/ROT13">ROT13</a>
- substitution cipher to all alphabetical characters.
- <p>
- The <code>rot13Reader</code> type is provided for you. Make it an
- <code>io.Reader</code> by implementing its <code>Read</code> method.
- <div>
- package main
- import (
- "io"
- "os"
- "strings"
- )
- type rot13Reader struct {
- r io.Reader
- }
- func main() {
- s := strings.NewReader(
- "Lbh penpxrq gur pbqr!")
- r := rot13Reader{s}
- io.Copy(os.Stdout, &r)
- }
- </div>
- </div>
- <div class="toc">Concurrency</div>
- <div class="slide nocode">
- <h2>Concurrency</h2>
- </div>
- <div class="slide">
- <h2>Goroutines</h2>
- <p>
- A <i>goroutine</i> is a lightweight thread managed by the Go runtime.
- <pre>go f(x, y, z)</pre>
- <p>
- starts a new goroutine running
- <pre>f(x, y, z)</pre>
- <p>
- The evaluation
- of <code>f</code>, <code>x</code>, <code>y</code>, and <code>z</code>
- happens in the current goroutine and the execution of <code>f</code>
- happens in the new goroutine.
- <p>
- Goroutines run in the same address space, so access to shared memory
- must be synchronized. The <code><a href="http://golang.org/pkg/sync/"
- target="_blank">sync</a></code> package provides useful primitives,
- although you won't need them much in Go as there are other primitives.
- (See the next slide.)
- <div>
- package main
- import (
- "fmt"
- "<span class="appengineMode">runtime</span><span class="localMode">time</span>"
- )
- func say(s string) {
- for i := 0; i < 5; i++ {
- <span class="appengineMode">runtime.Gosched()</span><span class="localMode">time.Sleep(100e6)</span>
- fmt.Println(s)
- }
- }
- func main() {
- go say("world")
- say("hello")
- }
- </div>
- </div>
- <div class="slide">
- <h2>Channels</h2>
- <p>
- Channels are a typed conduit through which you can send and receive values with the channel operator, <code><-</code>.
- <pre>
- ch <- v // Send v to channel ch.
- v := <-ch // Receive from ch, and
- // assign value to v.
- </pre>
- <p>
- (The data flows in the direction of the "arrow".)
- <p>
- Like maps and slices, channels must be created before use:
- <pre>
- ch := make(chan int)
- </pre>
- <p>
- By default, sends and receives block until the other side is ready.
- This allows goroutines to synchronize without explicit locks or
- condition variables.
- <div>
- package main
- import "fmt"
- func sum(a []int, c chan int) {
- sum := 0
- for _, v := range a {
- sum += v
- }
- c <- sum // send sum to c
- }
- func main() {
- a := []int{7, 2, 8, -9, 4, 0}
- c := make(chan int)
- go sum(a[:len(a)/2], c)
- go sum(a[len(a)/2:], c)
- x, y := <-c, <-c // receive from c
- fmt.Println(x, y, x + y)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Buffered Channels</h2>
-
- <p>
- Channels can be <i>buffered</i>. Provide the buffer length as the
- second argument to <code>make</code> to initialize a buffered channel:
- <pre>
- ch := make(chan int, 100)
- </pre>
- <p>
- Sends to a buffered channel block only when the buffer is full.
- Receives block when the buffer is empty.
- <p>
- Modify the example to overfill the buffer and see what happens.
- <div>
- package main
- import "fmt"
- func main() {
- c := make(chan int, 2)
- c <- 1
- c <- 2
- fmt.Println(<-c)
- fmt.Println(<-c)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Range and Close</h2>
- <p>
- A sender can <code>close</code> a channel to indicate that no more
- values will be sent. Receivers can test whether a channel has been
- closed by assigning a second parameter to the receive expression: after
- <pre>
- v, ok := <-ch</pre>
- <p>
- <code>ok</code> is <code>false</code> if there are no more values to
- receive and the channel is closed.
- <p>
- The loop <code>for i := range c</code> receives values from the
- channel repeatedly until it is closed.
- <p>
- <b>Note:</b> Only the sender should close a channel, never the
- receiver. Sending on a closed channel will cause a panic.
- <p>
- <b>Another note</b>: Channels aren't like files; you don't usually
- need to close them. Closing is only necessary when the receiver must be
- told there are no more values coming.
- <div>
- package main
- import (
- "fmt"
- )
- func fibonacci(n int, c chan int) {
- x, y := 1, 1
- for i := 0; i < n; i++ {
- c <- x
- x, y = y, x + y
- }
- close(c)
- }
- func main() {
- c := make(chan int, 10)
- go fibonacci(cap(c), c)
- for i := range c {
- fmt.Println(i)
- }
- }
- </div>
- </div>
- <div class="slide">
- <h2>Select</h2>
- <p>
- The <code>select</code> statement lets a goroutine wait on multiple
- communication operations.
- <p>
- A <code>select</code> blocks until one of its cases can run, then it
- executes that case. It chooses one at random if multiple are ready.
- <div>
- package main
- import "fmt"
- func fibonacci(c, quit chan int) {
- x, y := 1, 1
- for {
- select {
- case c <- x:
- x, y = y, x + y
- case <-quit:
- fmt.Println("quit")
- return
- }
- }
- }
- func main() {
- c := make(chan int)
- quit := make(chan int)
- go func() {
- for i := 0; i < 10; i++ {
- fmt.Println(<-c)
- }
- quit <- 0
- }()
- fibonacci(c, quit)
- }
- </div>
- </div>
- <div class="slide">
- <h2>Default Selection</h2>
- <p>
- The <code>default</code> case in a <code>select</code> is run if no
- other case is ready.
- <p>
- Use a <code>default</code> case to try a send or receive without
- blocking:
- <pre>
- select {
- case i := <-c:
- // use i
- default:
- // receiving from c would block
- }</pre>
- <p>
- <span class="appengineMode">
- <b>Note:</b> This example won't run through the web-based tour user
- interface because the
- <a target="_blank" href="http://golang.org/doc/play/">sandbox
- environment</a> has no concept of time. You may want to
- <a target="_blank" href="http://golang.org/doc/install.html">install
- Go</a> to see this example in action.
- </span>
- <div>
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- tick := time.Tick(1e8)
- boom := time.After(5e8)
- for {
- select {
- case <-tick:
- fmt.Println("tick.")
- case <-boom:
- fmt.Println("BOOM!")
- return
- default:
- fmt.Println(" .")
- time.Sleep(5e7)
- }
- }
- }
- </div>
- </div>
- <div class="slide nocode">
- <h2>Exercise: Equivalent Binary Trees</h2>
- <p>
- There can be many different binary trees with the same sequence of
- values stored at the leaves.
- For example, here are two binary trees storing the sequence
- 1, 1, 2, 3, 5, 8, 13.
- <img src="static/fig4.png">
- <p>
- A function to check whether two binary trees store the same sequence is
- quite complex in most languages. We'll use Go's concurrency and
- channels to write a simple solution.
- <p>
- This example uses the <code>tree</code> package, which defines the type:
- <pre>
- type Tree struct {
- Left *Tree
- Value int
- Right *Tree
- }
- </pre>
- </div>
- <div class="slide">
- <h2>Exercise: Equivalent Binary Trees</h2>
- <p>
- <b>1.</b> Implement the <code>Walk</code> function.
- <p>
- <b>2.</b> Test the <code>Walk</code> function.
- <p>
- The function <code>tree.New(k)</code> constructs a randomly-structured
- binary tree holding the values <code>k</code>, <code>2k</code>, <code>3k</code>, ...,
- <code>10k</code>.
- <p>
- Create a new channel <code>ch</code> and kick off the walker:
- <pre>
- go Walk(tree.New(1), ch)
- </pre>
- <p>
- Then read and print 10 values from the channel.
- It should be the numbers 1, 2, 3, ..., 10.
- <p>
- <b>3.</b> Implement the <code>Same</code> function using <code>Walk</code>
- to determine whether <code>t1</code> and <code>t2</code> store the same values.
- <p>
- <b>4.</b> Test the <code>Same</code> function.
- <p>
- <code>Same(tree.New(1), tree.New(1))</code> should return true, and
- <code>Same(tree.New(1), tree.New(2))</code> should return false.
- <div>
- package main
- import "<span class="appengineMode">tour</span><span class="localMode">go-tour.googlecode.com/hg</span>/tree"
- // Walk walks the tree t sending all values
- // from the tree to the channel ch.
- func Walk(t *tree.Tree, ch chan int)
- // Same determines whether the trees
- // t1 and t2 contain the same values.
- func Same(t1, t2 *tree.Tree) bool
- func main() {
- }
- </div>
- </div>
- <div class="slide">
- <h2>Exercise: Web Crawler</h2>
- <p>
- In this exercise you'll use Go's concurrency features to
- parallelize a web crawler.
- <p>
- Modify the <code>Crawl</code> function to fetch URLs in parallel
- without fetching the same URL twice.
- <div>
- package main
- import (
- "os"
- "fmt"
- )
- type Fetcher interface {
- // Fetch returns the body of URL and
- // a slice of URLs found on that page.
- Fetch(url string) (body string, urls []string, err os.Error)
- }
- // Crawl uses fetcher to recursively crawl
- // pages starting with url, to a maximum of depth.
- func Crawl(url string, depth int, fetcher Fetcher) {
- // TODO: Fetch URLs in parallel.
- // TODO: Don't fetch the same URL twice.
- // This implementation doesn't do either:
- if depth <= 0 {
- return
- }
- body, urls, err := fetcher.Fetch(url)
- if err != nil {
- fmt.Println(err)
- return
- }
- fmt.Printf("found: %s %q\n", url, body)
- for _, u := range urls {
- Crawl(u, depth-1, fetcher)
- }
- return
- }
- func main() {
- Crawl("http://golang.org/", 4, fetcher)
- }
- // fakeFetcher is Fetcher that returns canned results.
- type fakeFetcher map[string]*fakeResult
- type fakeResult struct {
- body string
- urls []string
- }
- func (f *fakeFetcher) Fetch(url string) (string, []string, os.Error) {
- if res, ok := (*f)[url]; ok {
- return res.body, res.urls, nil
- }
- return "", nil, fmt.Errorf("not found: %s", url)
- }
- // fetcher is a populated fakeFetcher.
- var fetcher = &fakeFetcher{
- "http://golang.org/": &fakeResult{
- "The Go Programming Language",
- []string{
- "http://golang.org/pkg/",
- "http://golang.org/cmd/",
- },
- },
- "http://golang.org/pkg/": &fakeResult{
- "Packages",
- []string{
- "http://golang.org/",
- "http://golang.org/cmd/",
- "http://golang.org/pkg/fmt/",
- "http://golang.org/pkg/os/",
- },
- },
- "http://golang.org/pkg/fmt/": &fakeResult{
- "Package fmt",
- []string{
- "http://golang.org/",
- "http://golang.org/pkg/",
- },
- },
- "http://golang.org/pkg/os/": &fakeResult{
- "Package os",
- []string{
- "http://golang.org/",
- "http://golang.org/pkg/",
- },
- },
- }
- </div>
- </div>
- <div class="slide nocode">
- <h2>Where to Go from here...</h2>
- <p class="appengineMode">
- You can get started by
- <a href="http://golang.org/doc/install.html">installing Go</a> or
- downloading the
- <a href="http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Go">Go App Engine SDK</a>.
- </p>
- <p>
- <span class="appengineMode">Once you have Go on your machine, the</span>
- <span class="localMode">The</span>
- <a target="_blank" href="http://golang.org/doc/docs.html">Go Documentation</a>
- is a great place to
- <span class="appengineMode">continue</span>
- <span class="localMode">start</span>.
- It contains references, tutorials, videos, and more.
- <p>
- If you need help with the standard library,
- see the <a target="_blank" href="http://golang.org/pkg/">package
- reference</a>. For help with the language itself, you might be
- surprised to find the
- <a target="_blank" href="http://golang.org/doc/go_spec.html">Language
- Spec</a> is quite readable.
- <p>
- If you're interested in writing web applications,
- see the
- <a target="_blank" href="http://golang.org/doc/codelab/wiki/">Wiki
- Codelab</a>.
- <p>
- If you want to further explore Go's concurrency model, see the
- <a target="_blank" href="http://golang.org/doc/codewalk/sharemem/">Share Memory by Communicating</a>
- codewalk.
- <p>
- The <a target="_blank" href="http://golang.org/doc/codewalk/functions/">First Class Functions in Go</a>
- codewalk gives an interesting perspective on Go's function types.
- <p>
- The <a target="_blank" href="http://blog.golang.org/">Go Blog</a> has a
- large archive of informative Go articles.
- <p>
- Visit <a target="_blank" href="http://golang.org">golang.org</a> for
- more.
- </div>
- </div><!-- end slides -->
- </body>
- </html>