Въведение в Go

03.10.2013

Инсталация

* Linux, FreeBSD

Инсталирате си пакета go от вашия пакетен мениджър

* Mac OSX

* Windows

Инсталация, епизод 2

1. Създавате директория ~/go
2. Слагате следните два реда в ~/.profile

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

* За Windows-аджийте има уловки:

Hello, world!

За да сме сигурни, че сме направили всичко като хората, създаваме файл hello.go:

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world!\n")
}

и изпълняваме

go run hello.go

Ако всичко изглежда наред, правим скрийншот и получаваме точка :)

Как да пишем код на Go?

Имаме инструментът go, който се грижи за достатъчно много неща.
Повечето настройки се правят с environment variables.
workspace, с три основни директории:

$ go

build       compile packages and dependencies
clean       remove object files
doc         run godoc on package sources
env         print Go environment information
fix         run go tool fix on packages
fmt         run gofmt on package sources
get         download and install packages and dependencies
install     compile and install packages and dependencies
list        list packages
run         compile and run Go program
test        test packages
tool        run specified go tool
version     print Go version
vet         run go tool vet on packages

Environment variables

$ go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/vladimiroff/go"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread"
CGO_ENABLED="1"

workspace

bin/
    streak                         # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source
    github.com/nf/
        streak/
            .git/                  # git repository metadata
            oauth.go               # command source
            streak.go              # command source

Браво. И сега какво?

Връщаме се обратно към Hello, world! примера:

package main

import "fmt"

func main() {
    fmt.Printf("Hello, world!\n")
}

и се фокусираме върху

package main

Пакети

Една програма на Go е структура от пакети. Нямате шанс просто да хвърлите
едно парче код, в даден файл и то да тръгне.

Особености

Без значение от колко файла се състои:

One package to rule them all

Ако си мислите за "Lord of the rings", грешите. Говорим ви за main.

В една програма имаме точно един пакет main и при изпълнението ѝ се изпълнява функцията main в него.

Програмата приключва, когато приключи изпълнението на функцията main.

Тя не връща нищо.

Преизползване на пакети

Става с ключовата думичка import, последвана от името на пакета, в кавички

import "fmt"

Ако искаме да импортнем няколко пакета:

import "fmt"
import "os"

което go fmt би свел до

import (
    "fmt"
    "os"
)

import

package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Printf("Hello, world!\n")
}

Видимост

Какво точно можем да използваме от импортнат пакет? Тук става забавно.

Даден идентификатор (било то на променлива, константа, тип, функция или
метод) е видим извън пакета си, тогава и само тогава когато името му започва с главна буква.

Наричаме ги exported (на други места им викат public).

Останалите са недостъпни (демек private)

Основни типове

... но това не е всичко

Имаме свободата да решим точно колко байта да е нашия тип:

... и разбира се имаме unsigned:

По подразбиране int е int32

Пример

var name string = "Чочко Чочков"
var age uint8 = 25

Горното можем (и трябва) да запишем като:

var (
    name string = "Чочко Чочков"
    age uint8 = 25
)

Ако са с един и същи тип, можем и така:

var name, age string = "Чочко Чочков", "двадесет и пет"

WTF! WTF! WTF! Защо типа е на грешното място!?

type-inference

Можем да правим и така:

name := "Чочко Чочков"
age := 25

Стойности по подразбиране

Не се грижим за това да си инициализираме стойностите. Всяка променлива в Go се инициализира по подразбиране:

var (
    digit int         // 0
    digit *int        // nil
    number float64    // 0.0
    isIt bool         // false
    name string       // ""
    root complex64    // (0+0i)
    pipe chan <type>  // nil
)

Кастване

Кастването работи, както очаквате:

number := 42                      // (int=42.0)
specificNumber := float64(number) // (float64=42.0)

С тази разлика, че нямате имплицитен каст:

number * specificNumber // (mismatched types int and float64)

Unused variable

Дефинирана стойност, която не се използва, води до грешка по време на компилация

Константи

Аналогично с var:

const (
    name string = "Чочко Чочков"
    age uint8 = 25
)

Могат да бъдат само

iota

Нали помните enum?

const (
    Monday = iota
    Tuesday
    Wednesday
    Thursday
    Friday
    Partyday
    Sunday
)

Контролни структури

if

if age < 13 {
    fmt.Print("Още не си тийнейджър")
} else if age >= 13 && age < 20 {
    fmt.Print("В момента си тийнейджър")
} else {
    fmt.Print("Минали са ти тийнейджърските години")
}

for

Добрия стар for от C:

for i := 0; i < 20; i++ {
    fmt.Println(i)
}

И точно както в C, някои от аргументите не са задължителни.
... някои да се чете като всички.

package main

import "fmt"

func main() {
    for {
        fmt.Println("Can't stop me!")
    }
}

Забележка: Отварящата { и тук е на същия ред с условието

while

Няма. for покрива всичките му приложения.

foreach

Няма. for покрива всичките му приложения.

switch

switch {
    case age < 13:
        fmt.Print("Още не си тийнейджър")
    case age >= 13 && age < 20:
        fmt.Print("В момента си тийнейджър")
    default:
        fmt.Print("Минали са ти тийнейджърските години")
}

Няма нужда от излишния `break`

Ако искаме да изпълним два поредни case-а, използваме fallthrough.

break и continue

Все пак има break, който е приложим за for цикли.

continue работи, точно както очаквате и където очаквате.

goto

Да, има и такова.

Ако не знаете кога, не го ползвайте.

Към момента допускаме, че още не знаете кога => не го ползвате.

Особености, с които се сблъскахте (Q&A)

;

Q: Няма точка и запетая след всеки израз?

A: Всъщност има, но е имплицитна.

Сега си спомнете за правилото с отварящата {.

Индентация

Q: Интервали vs. Табове?
A: Един таб.

В следващия епизод:

Въпроси?