A Linguagem de Programação Go
-
Upload
francisco-souza -
Category
Technology
-
view
1.568 -
download
3
description
Transcript of A Linguagem de Programação Go
A linguagem de programação GoFrancisco SouzaDev in Cachu 2013
program main
print *, "Hello world!"
end program
what the f**rancisco?!
open source fanboy
Desenvolvedor na Globo.com
Usa Go diaramente para construir o Tsuru
tsuru.io (http://tsuru.io)
Go?
Uma linguagem focada em algumas características...
Eficiência
Segurança
Concorrência
Escalabilidade
Um mascote legal :)
Por que uma nova linguagem?
Linguagens estáticas
package main
import "fmt"
func main() { fmt.Println("#devincachu 2013: eu fui! :D")} Run
Tempo de compilação...
Tsuru: 16 mil linhas de código
% time go install ./...2.53 real 3.03 user 0.56 sys
Compilador + biblioteca padrão: 230++ mil linhas de código
% time ./make.bash47.89 real 59.23 user 11.54 sys
Tempo de compilação (cont.)
Linguagens dinâmicas
Go: o melhor dos dois mundos?
Explorando a biblioteca padrão...
package main
import (
"fmt"
"net"
)
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:3000")
if err != nil {
panic(err)
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
panic(err)
}
fmt.Fprintln(conn, "Oi pessoal do #devincachu!")
conn.Close()
}
} Run
Um pouco mais amigável...
127.0.0.1:7070/ (http://127.0.0.1:7070/)
package main
import ( "fmt" "net/http")
func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Oi do #devincachu 2013! :)") }) http.ListenAndServe("127.0.0.1:7070", nil)} Run
Aspectos da linguagem
Variáveis
Muitos jeitos de declarar, alguns mais verbosos, outros mais simples...
var name string name = "Francisco" fmt.Println(name)
var name string = "Francisco" fmt.Println(name)
var name = "Francisco" fmt.Println(name)
name := "Francisco" fmt.Println(name)
Declarações
Na linguagem C e maioria de suas derivadas, declarações podem ser lidas em espiral:
Detalhes:
The Clockwise/Spiral Rule (http://c-faq.com/decl/spiral.anderson.html)
Declarações (cont.)
Em Go, as declarações são sempre da esquerda para a direita:
var name string
var name string = "Francisco"
var name = "Francisco"
name := "Francisco"
var f func(fn func(int) int) func(int) int
Loops
for i := 0; i < 10; i++ { fmt.Println(i) }
for { fmt.Println("Looping forever") break // not really }
Slices & arrays
Em Go, arrays são como os arrays estáticos em C:
var numeros [16]int
Além dos arrays, existem os slices:
var numeros []int
Slices: exemplo
func Reverse(values []int) []int { result := make([]int, len(values)) length := len(values) for i := range values { result[i] = values[length-1-i] } return result}
func main() { numbers := [8]int{1, 2, 3, 4, 5, 6, 7, 8} fmt.Println(Reverse(numbers[:]))} Run
Funções
func sum(x int, y int) int { return x + y}
func swap(x, y int) (int, int) { return y, x}
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return}
fmt.Println(sum(10, 5)) fmt.Println(swap(10, 5)) fmt.Println(split(20)) Run
Tipos
type Person struct { Name string Birth time.Time}
type MyString string
type MyInt int
No pacote :
type Duration int64
"Construtores"
Em Go, não existem construtores propriamente ditos, mas há uma convenção na comunidade para construtores ( ):
func NewPerson(name string, birth time.Time) (*Person, error) {
if time.Now().Sub(birth) < 0 {
return nil, errors.New("LOLWUT, did you born in the future?!")
}
person := Person{Name: name, Birth: birth}
return &person, nil
}
Métodos
type Person struct {
Name string
Birth time.Time
}
func (p *Person) Age() int {
difference := time.Now().Sub(p.Birth)
return int(difference / (365 * 24 * time.Hour))
}
p, err := NewPerson("Francisco", date)
if err != nil {
panic(err)
}
fmt.Printf("%s is %d years old.\n", p.Name, p.Age()) Run
Métodos (cont.)
type MyInt int
func (i MyInt) String() string { return fmt.Sprintf("%d", i)}
Interfaces
Interfaces
Go possui interfaces, de forma semelhante à linguagem Java.
type Reader interface { Read(content []byte) (int, error)}
Você pode declarar funções baseadas nessas interfaces:
func Dump(r Reader) { var buf [512]byte n, _ := r.Read(buf[:]) for n > 0 { fmt.Printf("%s", buf) n, _ = r.Read(buf[:]) }}
Interfaces (cont.)
Em , qualquer tipo que tenha o método especificado por uma interface, automaticamente implementa aquela interface, de forma implícita.
Assim, qualquer tipo com o método implementa a interface declarada no slide anterior.
resp, err := http.Get("http://golang.org/")
if err != nil {
panic(err)
}
Dump(resp.Body)
file, err := os.Open("/etc/passwd")
if err != nil {
panic(err)
}
Dump(file)
file.Close()
Tratamento de erros
Lidando com erros
No construtor do tipo , o segundo retorno é do tipo .
func NewPerson(name string, birth time.Time) (*Person, error) {
Lidando com erros (cont.)
Go não inclui o mecanismo de exceções de linguagens como Python e Java. Ao invés disso, a linguagem utiliza o tipo para representar falhas.
Um idioma comum:
func fazAlgumaCoisa() (*Result, error)
Tratando erros:
result, err := fazAlgumaCoisa()if err != nil { panic(err)}
Ignorando erros:
result, _ := fazAlgumaCoisa()
Concorrência
CSP
O modelo de concorrência é inspirado no CSP (Communicating Sequential Processes).
PROC producer (CHAN INT out!) out ! 42:
PROC consumer (CHAN INT in?) INT v: SEQ in ? v:
CSP (cont.)
O modelo também inspirou outras linguagens, como Occam, Erlang e Limbo.
O modelo também está disponível em outras linguagens:
python-csp (https://github.com/python-concurrency/python-csp)
JCSP (http://www.cs.kent.ac.uk/projects/ofa/jcsp/)
CSP em Go
Processos -> goroutines
Canais -> canais :-)
Goroutines
A criação de uma goroutine é uma simples chamada de função precedida pela palavra-chave go.
package main
import "fmt"
func say(what, who string) {
fmt.Printf("%s, %s!\n", what, who)
}
func main() {
say("Hello world", "#devincachu")
} Run
Canais
Em Go, diferentes goroutines se comunicam através de canais.
func sum(values []int, result chan int) { var sum int for _, v := range values { sum += v } result <- sum}
func main() { ch := make(chan int) values := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} go sum(values, ch) fmt.Println(<-ch)} Run
Um exemplo
func elevator(people chan string) { for person := range people { fmt.Printf("Carrying %s...\n", person) time.Sleep(time.Duration(rand.Intn(2000)) * time.Millisecond) }}
ch := make(chan string) go elevator(ch) for _, p := range people { ch <- p } Run
Concorrência vs Paralelismo
Concorrência vs Paralelismo
Concorrência: lidar com múltiplas coisas ao mesmo tempo
Paralelismo: fazer múltiplas coisas ao mesmo tempo
func elevator(people chan string) { for person := range people { fmt.Printf("Carrying %s...\n", person) time.Sleep(time.Duration(rand.Intn(2000)) * time.Millisecond) }}
ch := make(chan string) go elevator(ch) for _, p := range people { ch <- p } Run
Hands on
Download de arquivos
O exemplo visa demonstrar um client que baixa arquivos do site textfiles.com.
Download de arquivos (cont.)
Uso do programa:
% ./download -h -d="": Destination directory (where to save files) -u="": URL to download files from -w=2: Number of workers
Exemplo de uso:
% ./download -d files -u http://www.textfiles.com/programming/ -w 50
Solução
Cada worker é uma goroutine, que receberá um canal de arquivos para baixar.
func download(files <-chan string, wg *sync.WaitGroup) {
O é um mecanismo de sincronização que permitirá esperar até que o
worker termine a execução.
Solução (cont.)
Os workers receberão os arquivos a partir de um canal. Haverá um enviando os links através desse canal.
func extract(url string, files chan<- string) error {
O extrator utilizará uma expressão regular para extrair os arquivos.
var link = regexp.MustCompile(`<a href="([\w-]+\.txt)">[\w-]+\.txt</a>`)
Declaração das flags
Go tem um pacote na biblioteca padrão para declaração de flags a serem utilizadas na linha de comando.
var url, dstdir stringvar workers uint
func init() { flag.StringVar(&url, "u", "", "URL to download files from") flag.StringVar(&dstdir, "d", "", "Destination directory (where to save files)") flag.UintVar(&workers, "w", 2, "Number of workers")}
A função init é executada sempre que o pacote é importado. No caso do pacote main, a função é executada antes da função .
Extrator
func extract(url string, files chan<- string) error { resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return err } links := link.FindAllSubmatch(bytes.ToLower(b), -1) for _, l := range links { files <- string(l[1]) } close(files) return nil}
Worker
func download(files <-chan string, wg *sync.WaitGroup) { defer wg.Done() for file := range files { resp, err := http.Get(url + file) if err != nil { log.Printf("Failed to download %q: %s.", file, err) continue } p := path.Join(dstdir, file) f, err := os.Create(p) if err != nil { log.Printf("Failed to open %q: %s.", p, err) continue } _, err = io.Copy(f, resp.Body) resp.Body.Close() f.Close() if err != nil { log.Printf("Failed to write %q: %s.", p, err) } }}
Juntando todo mundo
func main() { flag.Parse() os.MkdirAll(dstdir, 0755) var wg sync.WaitGroup if workers < 1 { workers = 2 } files := make(chan string, workers) for i := uint(0); i < workers; i++ { wg.Add(1) go download(files, &wg) } err := extract(url, files) if err != nil { log.Fatal(err) } wg.Wait()}
Demonstração
Próximos passos
Site da linguagem
golang.org (http://golang.org)
A Tour of Go
tour.golang.org (http://tour.golang.org)
Effective Go
golang.org/doc/effective_go.html (http://golang.org/doc/effective_go.html)
Communicating Sequential Processes
www.usingcsp.com (http://www.usingcsp.com)
Códigos da palestra
github.com/fsouza/go-devincachu (https://github.com/fsouza/go-devincachu)
Thank you
Francisco SouzaDev in Cachu 2013@franciscosouza (http://twitter.com/franciscosouza)
[email protected] (mailto:[email protected])
http://f.souza.cc (http://f.souza.cc)