Skip to content

Go Język Programowania Cheat Sheet

Go (znany również jako Golang) to statycznie typowany, kompilowany język opracowany przez Roberta Griesemera, Roba Pike’a i Kena Thompsona w Google. Składnia Go jest zbliżona do C, ale oferuje bezpieczeństwo pamięci, GC (garbage collection), typowanie strukturalne oraz współbieżność w stylu CSP.

Hello world

package main

import "fmt"

func main() {
  message := greetMe("world")
  fmt.Println(message)
}

func greetMe(name string) (string) {
  return "Hello, " + name + "!"
}
$ go build

Zmienne

Deklaracja zmiennej

var msg string
msg = "Hello"

Skrócona deklaracja

msg := "Hello"

Stałe

const Phi = 1.618

Stałe mogą być znakami, ciągami znaków, wartościami logicznymi lub liczbowymi.

Typy podstawowe

Ciągi znaków (Strings)

str := "Hello"
str := `Wieloliniowy
string`

Typem dla ciągów znaków jest string.

Liczby

Typowe typy

num := 3          // int
num := 3.         // float64
num := 3 + 4i     // complex128
num := byte('a')  // byte (alias dla uint8)

Inne typy

var u uint = 7        // uint (bez znaku)
var p float32 = 22.7  // 32-bitowy float

Wskaźniki

func main () {
  b := *getPointer()
  fmt.Println("Wartość to", b)
}
 
func getPointer () (myPointer *int) {
  a := 234
  return &a
}

Wskaźniki wskazują na lokalizację w pamięci zmiennej. Go posiada pełne odśmiecanie pamięci (garbage collection).

Tablice (Arrays)

// var numbers [5]int
numbers := [...]int{0, 0, 0, 0, 0}

Tablice mają stały rozmiar.

Wycinki (Slices)

slice := []int{2, 3, 4}
slice := []byte("Hello")

W przeciwieństwie do tablic, wycinki mają dynamiczny rozmiar.

Sterowanie przepływem

Instrukcje warunkowe

if day == "sunday" || day == "saturday" {
  rest()
} else if day == "monday" && isTired() {
  groan()
} else {
  work()
}

Instrukcja wewnątrz if

if _, err := getResult(); err != nil {
  fmt.Println("Uh oh")
}

Instrukcja if może wykonać prostą instrukcję przed wyrażeniem warunkowym.

Switch

switch day {
  case "sunday":
    // przypadki domyślnie nie "przechodzą" (no fallthrough)!
    fallthrough

  case "saturday":
    rest()

  default:
    work()
}

Funkcje

Lambdy (funkcje anonimowe)

myfunc := func() bool {
  return x > 10000
}

Funkcje są obywatelami pierwszej kategorii (first-class objects).

Wiele typów zwracanych

a, b := getMessage()
func getMessage() (a string, b string) {
  return "Hello", "World"
}

Nazwane wartości zwracane

func split(sum int) (x, y int) {
  x := sum * 4 / 9
  y := sum - x
  return
}

Dzięki nazywaniu wartości zwracanych w deklaracji, return (bez argumentów) zwróci zmienne o tych nazwach.

Pakiety

Ładowanie

import "fmt"
import "math/rand"
import (
  "fmt"        // daje fmt.Println
  "math/rand"  // daje rand.Intn
)

Obie formy są poprawne.

Aliasy

import r "math/rand"
 
r.Intn()

Nazwy eksportowane

func Hello () {
  ···
}

Nazwy eksportowane zaczynają się od wielkiej litery.

Pakiety

package hello

Każdy plik pakietu musi zaczynać się od deklaracji package.

Współbieżność

Goroutines

func main() {
  // "Kanał" (channel)
  ch := make(chan string)

  // Uruchomienie współbieżnych procedur
  go push("Moe", ch)
  go push("Larry", ch)
  go push("Curly", ch)

  // Odczyt 3 wyników
  // (Ponieważ nasze goroutines są współbieżne,
  // kolejność nie jest gwarantowana!)
  fmt.Println(<-ch, <-ch, <-ch)
}
 
func push(name string, ch chan string) {
  msg := "Hey, " + name
  ch <- msg
}

Kanały są bezpiecznymi dla współbieżności obiektami komunikacyjnymi używanymi w goroutines.

Kanały buforowane

ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
// błąd krytyczny:
// all goroutines are asleep - deadlock!

Kanały buforowane ograniczają liczbę komunikatov, które mogą pomieścić.

Zamykanie kanałów

Zamyka kanał

ch <- 1
ch <- 2
ch <- 3
close(ch)

Iteracja po kanale aż do jego zamknięcia

for i := range ch {
  ···
}

Zamknięty, jeśli ok == false

v, ok := <- ch

Defer & Panic

Defer

func main() {
  defer fmt.Println("Gotowe")
  fmt.Println("Pracuję...")
}

Odracza wykonanie funkcji do momentu, gdy funkcja nadrzędna zakończy działanie. Argumenty są oceniane natychmiast, ale wywołanie funkcji następuje dopiero na końcu.

Defer z lambdami

func main() {
  defer func() {
    fmt.Println("Gotowe")
  }()
  fmt.Println("Pracuję...")
}

Lambdy lepiej nadają się do bloków odroczonych.

Struktury (Structs)

Definicja

type Vertex struct {
  X int
  Y int
}

func main() {
  v := Vertex{1, 2}
  v.X = 4
  fmt.Println(v.X, v.Y)
}

Literały

v := Vertex{X: 1, Y: 2}
// Nazwy pól można pominąć
v := Vertex{1, 2}
// Y jest domniemane
v := Vertex{X: 1}

Można również określić nazwy pól.

Wskaźniki do struktur

v := &Vertex{1, 2}
v.X = 2

Gdy v jest wskaźnikiem, v.X i (*v).X to to samo.

Metody

Odbiorniki (Receivers)

type Vertex struct {
  X, Y float64
}
func (v Vertex) Abs() float64 {
  return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
 
v := Vertex{1, 2}
v.Abs()

W Go nie ma klas, ale można definiować funkcje dla typów za pomocą odbiorników.

Odbiorniki wskaźnikowe

func (v *Vertex) Scale(f float64) {
  v.X = v.X * f
  v.Y = v.Y * f
}
 
v := Vertex{6, 12}
v.Scale(0.5)
// `v` zostaje zaktualizowany