Kreirano 2024-10-26 Sat 17:10, pritisni ESC za mapu, Ctrl+Shift+F za pretragu, ? za pomoć
PATH
varijablu na go/bin
folderNa primer:
wget https://dl.google.com/go/go$VERSION.$OS-$ARCH.tar.gz
mkdir -p ~/install/go
tar -C ~/install/go -xzf go$VERSION.$OS-$ARCH.tar.gz
VERSION
- tekuća verzija (trenutno 1.19.3), OS
- operativni sistem
(npr. linux
) a ARCH
- arhitektura (npr. amd64
)
podesiti PATH
:
export PATH=$PATH:~/install/go/
$HOME/go
GOPATH
varijabluOvo je zastareli način rada. U novijim verzijama koristi se sistem modula dok je od verzije 1.18 podržan i radni proces sa workspaces upotrebom go.work fajl.
$ go version
go version go1.19.3 linux/amd64
Napraviti hello
direktorijumu i preći u njega:
mkdir hello
cd hello
Inicijalizovati modul:
go mod init examples/hello
Napraviti fajl hello.go
sa sadržajem:
package main
import "fmt"
func main() {
fmt.Printf("Здраво, свете!\n")
}
Pokrenuti go build
i zatim startovati program:
$ go build
$ ./hello
Здраво, свете!
Ova sekcija objašnjava osnovne radnje prilikom razvoja Go programa. Upotrebu Go alata, standardni način za kreiranje inicijalnog projekta, preuzimanje, izgradnju, instalaciju i pokretanje Go programa.
Bazirano na How to Write Go Code
Go programi su organizovani u pakete (eng. packages) - kolekcija fajlova unutar istog foldera koji se zajedno kompajliraju.
github.com/mojnalog/moj_modul
).cmp
tako da bi buna
putanja za import bila github.com/google/go-cmp/cmp.fmt
, net/http
Napraviti hello
direktorijumu i preći u njega:
mkdir hello
cd hello
Inicijalizovati modul:
$ go mod init example/user/hello
go: creating new go.mod: module example/user/hello
$ cat go.mod
module example/user/hello
go 1.19
Napraviti fajl hello.go
sa sadržajem:
package main
import "fmt"
func main() {
fmt.Printf("Здраво, свете!\n")
}
Pokrenuti go build
i zatim startovati program:
$ go build
$ ./hello
Здраво, свете!
Instalirati program sa:
go install
hello
program će biti instaliran u $GOBIN
folder (podrazumevano ~/go/bin
).
$ echo $GOBIN
~/repos/gocode/bin
$ which hello
~/repos/gocode/bin/hello
Za podešavanje okruženja na portabilan način možemo koristiti go env
.
go env -w GOBIN=/somewhere/else/bin
Sledeći korak je da promenu zabeležimo u sistemu za kontrolu verzija:
$ git init
Initialized empty Git repository in /home/igor/NTP/hello/.git/
$ git add hello.go go.mod
$ git commit -m "Initial commit"
[main (root-commit) 62d03dd] Initial commit
2 files changed, 11 insertions(+)
create mode 100644 go.mod
create mode 100644 hello.go
hello
programa.# Iz hello foldera
$ mkdir morestrings
$ cd morestrings
reverse.go
u folderu morestrings
// Package morestrings implements additional functions to manipulate UTF-8
// encoded strings, beyond what is provided in the standard "strings" package.
package morestrings
// ReverseRunes returns its argument string reversed rune-wise left to right.
func ReverseRunes(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
$ go build
Komanda ne proizvodi ispis već kompajlirani kod kešira.
hello.go
package main
import (
"fmt"
"example/user/hello/morestrings"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!етевс ,овардЗ"))
}
$ cd ..
$ go run hello.go
ili
$ go install example/user/hello
$ hello
Здраво, свете!
Prvi iskaz u svakom Go fajlu mora biti:
package <name>
<name>
ime paketa koje se koristi pri import-ucrypto/rot13
tada njegovo ime treba da bude
rot13
main
Import putanja može biti u obliku URL-a do repozitorijuma za kontrolu verzija (npr. Git ili Mercurial)
Na primer:
package main
import (
"fmt"
"example/user/hello/morestrings"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
Pošto smo dodali novu zavisnost potrebno je da ažuriramo go.mod
fajl. To je
automatizovano kroz komandu go mod tidy
.
$ go mod tidy
go: finding module for package github.com/google/go-cmp/cmp
go: downloading github.com/google/go-cmp v0.5.7
go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.5.7
go: downloading golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
$ go install example/user/hello
$ hello
Hello, Go!
string(
- "Hello World",
+ "Hello Go",
)
$ cat go.mod
module example/user/hello
go 1.18
require github.com/google/go-cmp v0.5.7
Preuzete zavisnosti se keširaju u pkg/mod
podfolderu foldera na koji pokazuje
promenjiva $GOPATH
. Ovaj keš se može obrisati sa go clean -modcache
.
Import declaration Local name of Sin import "lib/math" math.Sin import m "lib/math" m.Sin import . "lib/math" Sin
import _ "lib/math"
testing
+ go test
komanda_test.go
i koji sadrži
funkcije oblika TestXXX
sa signaturom func (t *testing.T)
go test
poziva sve funkcije i ako ona pozove t.Error
ili t.Fail
test se
smatra neuspešnim
Fajl morestrings/reverse_test.go
package morestrings
import "testing"
func TestReverseRunes(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := ReverseRunes(c.in)
if got != c.want {
t.Errorf("ReverseRunes(%q) == %q, want %q", c.in, got, c.want)
}
}
}
$ cd morestrings
$ go test
PASS
ok example/user/hello/morestrings 0.001s
$
Interaktivno učenje Go jezika:
Lokalna instalacija:
$ go install golang.org/x/website/tour $ tour
Program počinje izvršavanje u paketu main
i funkciji func main()
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
rand
).Import
iskazMože se navesti više paketa unutar zagrada (tzv. factored import)
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
}
Ime je eksportovano iz paketa (odnosno može se importovati u drugim paketima) ako počinje velikim slovom.
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi) // <-- treba math.Pi
}
Imenima koji počinju malim slovom ne može se pristupiti izvan paketa u kome su definisani.
Funkcije mogu imati nula ili više parametara
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Ili kraće
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Funkcije mogu vratiti proizvoljan broj rezultata
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Povratne vrednosti mogu biti imenovane i u tom slučaju može se koristiti
return
iskaz bez argumenata (tzv. naked return)
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))
}
var
iskaz definiše varijable. Tip se navodi na kraju
var
iskaz se može koristiti na nivou paketa ili funkcije
package main
import "fmt"
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
var
iskaz može imati inicijalizatore, jedan po varijabliAko se koristi inicijalizator, tip može da se izostavi jer može da se odredi na osnovu inicijalizatora
package main
import "fmt"
var i, j int = 1, 2
func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}
Unutar funkcija, kraći oblik deklaracije baziran na :=
dodeli može da se
koristi
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
Osnovni tipovi u Go-u su:
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // alias for uint8 rune // alias for int32 // represents a Unicode code point float32 float64 complex64 complex128
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
Type: bool Value: false Type: uint64 Value: 18446744073709551615 Type: complex128 Value: (2+3i)
Varijable deklarisane bez inicijalizatora se inicijalizuju na podrazumevane nulte vrednosti:
0
za numeričke tipovefalse
za boolean
tip""
(prazan string) za string
tip package main
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
0 0 false ""
T(v)
konvertuje vrednost v
u tip T
Na primer:
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
i := 42
f := float64(i)
u := uint(f)
package main
import (
"fmt"
"math"
)
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
}
3 4 5
Kada je desna strana iskaza dodele (bilo :=
bilo var =
) tipizirana,
leva strana će biti istog tipa
var i int
j := i // j is an int
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
const
Ne mogu se definisati upotrebom :=
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)
}
Kod netipiziranih konstanti tip se određuje na osnovu konteksta
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
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))
fmt.Println(needInt(Big)) // <-- constant overflow
}
const Huge = 1e1000
// Sledeća linija ne može da se kompajlira
// Greška je 'constant 1.00000e+1000 overflows float64'
fmt.Println(Huge)
// Ali ovo radi bez problema jer se kalkulacija obavlja od strane kompajlera
// u vreme kompajliranja
fmt.Println(Huge / 1e999)
iota
)Kada nam je potrebna enumeracija
const (
CategoryBooks = iota // 0
CategoryHealth // 1
CategoryClothing // 2
)
type Stereotype int
const (
TypicalNoob Stereotype = iota // 0
TypicalHipster // 1
TypicalUnixWizard // 2
TypicalStartupFounder // 3
)
Ako želimo da preskočimo vrednosti
type AudioOutput int
const (
OutMute AudioOutput = iota // 0
OutMono // 1
OutStereo // 2
_
_
OutSurround // 5
)
Možemo kreirati i izraze sa iota
type Allergen int
const (
IgEggs Allergen = 1 << iota // 1 << 0 which is 00000001
IgChocolate // 1 << 1 which is 00000010
IgNuts // 1 << 2 which is 00000100
IgStrawberries // 1 << 3 which is 00001000
IgShellfish // 1 << 4 which is 00010000
)
for
, if
, else
, switch
i defer
For
iskazfor
Tri komponente:
post iskaz – izvršava se na kraju svake iteracije
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
45
()
se ne navode kao u nekim drugim jezicima ali je navođenje {}
za
telo petlje obaveznopackage main
import "fmt"
func main() {
sum := 1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
}
for
je while
u Go-u
Kada nemamo init i post iskaz možemo izostaviti ;
i dobijamo
ekvivalent while
petlje u drugim jezicima
package main
import "fmt"
func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
1024
Ako se izostavi i uslov dobijamo beskonačnu petlju
package main
func main() {
for {
}
}
if
iskaz
Kao i kod for
i kod if
iskaza zagrade nije potrebno navoditi
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))
}
1.4142135623730951 2i
if
sa kratkim iskazomfor
i if
može da ima kratak iskaz (najčešće :=
) koji se
izvršava pre uslova
Varijable deklarisane u ovom iskazu su dostupne samo unutar if
iskaza
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),
)
}
: 9 20
if
i else
Varijable deklarisane u if
kratkom iskazu su dostupne i u opcionom else
bloku
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),
)
}
: 27 >= 20
: 9 20
switch
iskazif/else
iskaza. Izvršava prvi case
blok
gde je vrednost jednaka vrednošću izraza uslova
Može imati kratak iskaz kao i if
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.\n", os)
}
}
Go runs on Linux.
case
blok (nema
“propadanja”). Takođe case
prihvata izraz koji ne mora biti konstanta i
čija vrednost ne mora biti numeričkaswitch
iskazacase
blokova ide od vrha prema dnu dok se ne nađe prvi blok
čija vrednost je jednaka zadatom uslovu
f()
se ne poziva ako je i==0
switch i {
case 0:
case f():
}
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("When's Saturday?")
today := time.Now().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.")
}
}
When's Saturday? Too far away.
switch
bez uslovaswitch true
Čistiji način pisanja dugih if-then-else lanaca
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
Good afternoon.
defer
iskaz
Parametri funkcije se evaluiraju na mestu poziva defer
ali se ciljna
funkcija ne poziva do povratka
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
hello world
defer
poziva
defer
pozivi se smeštaju na stek i po povratku funkcije se izvršavaju u
LIFO redosledu
package main
import "fmt"
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
counting done 9 8 ... 0
struct
, slice
i map
Pointers
)*T
je pokazivač na vrednost tipa T
&
operator vraća pokazivač na zadati argument/vrednost
i := 42
p = &i // p je pokazivač na vrednost 42
*
operator označava vrednost na koju pokazivač pokazuje
fmt.Println(*p) // čitanje i vrednosti kroz pokazivač p
*p = 21 // postavljanje i vrednosti kroz pokazivač p
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // point to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
}
42 21 73
struct
) package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
{1 2}
.
operatora package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
4
p
na strukturu, polju X
bi mogli
pristupiti sa (*p).X
p.X
tj.
nije potrebno eksplicitno dereferenciranje package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
{1000000000 2}
struct
literaliName:
za postavljanje vrednosti polja i u
tom slučaju redosled je irelevantan&
vraća se pokazivač na strukturu package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3)
}
{1 2} &{1 2} {1 0} {0 0}
Arrays
)[n]T
– niz od n
elemenata tipa T
var a [10]int
– niz od 10 elemenata tipa int
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
Hello World [Hello World] [2 3 5 7 11 13]
Slices
)[]T
– isečak tipa T
Isečak se formira nad potpornim nizom na sledeći način:
a[low : high]
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s)
}
[3 5 7]
package main
import "fmt"
func main() {
names := [4]string{
"John",
"Paul",
"George",
"Ringo",
}
fmt.Println(names)
a := names[0:2]
b := names[1:3]
fmt.Println(a, b)
b[0] = "???"
fmt.Println(a, b)
fmt.Println(names)
}
[John Paul George Ringo] [John Paul] [Paul George] [John ???] [??? George] [John ??? George Ringo]
[3]bool{true, true, false}
[]bool{true, true, false}
package main
import "fmt"
func main() {
q := []int{2, 3, 5, 7, 11, 13}
fmt.Println(q)
r := []bool{true, false, true, true, false, true}
fmt.Println(r)
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
fmt.Println(s)
}
[2 3 5 7 11 13] [true false true true false true] [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
0
Ekvivalentni izrazi:
a[0:10]
a[:10]
a[0:]
a[:]
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
s = s[1:4]
fmt.Println(s)
s = s[:2]
fmt.Println(s)
s = s[1:]
fmt.Println(s)
}
[3 5 7] [3 5] [5]
s
: len(s)
, cap(s)
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=6 cap=6 [2 3 5 7 11 13] len=0 cap=6 [] len=4 cap=6 [2 3 5 7] len=2 cap=4 [5 7]
nil
Ovakav isečak ima dužinu i kapacitet 0
i nema potporni niz
package main
import "fmt"
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
if s == nil {
fmt.Println("nil!")
}
}
[] 0 0 nil!
make
make
funkcija alocira niz sa nultim vrednostima i vraća njegov isečak
a := make([]int, 5) // len(a)=5
moguće je definisati i kapacitet
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
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)
}
a len=5 cap=5 [0 0 0 0 0] b len=0 cap=5 [] c len=2 cap=5 [0 0] d len=3 cap=3 [0 0 0]
package main
import (
"fmt"
"strings"
)
func main() {
// Create a tic-tac-toe board.
board := [][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
}
// The players take turns.
board[0][0] = "X"
board[2][2] = "O"
board[1][2] = "X"
board[1][0] = "O"
board[0][2] = "X"
for i := 0; i < len(board); i++ {
fmt.Printf("%s\n", strings.Join(board[i], " "))
}
}
X _ X O _ X _ _ O
func append(s []T, vs ...T) []T
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than one element at a time.
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
len=0 cap=0 [] len=1 cap=1 [0] len=2 cap=2 [0 1] len=5 cap=6 [0 1 2 3 4]
range
range
forma for
petlje iterira kroz elemente isečaka ili mape
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)
}
}
2**0 = 1 2**1 = 2 2**2 = 4 2**3 = 8 2**4 = 16 2**5 = 32 2**6 = 64 2**7 = 128
Ukoliko ne koristite indeks pri iteraciji moguće ga je ignorisati
upotrebom specijalnog imena _
for i, _ := range pow
for _, value := range pow
Ako vam treba samo indeks možete izostaviti drugu varijablu:
for i := range pow
package main
import "fmt"
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
1 2 4 8 16 32 64 128 256 512
nil
nil
mapa nema ključeve niti se ključevi mogu dodatimake
funkcija vraća inicijalizovanu mapu spremnu za upotrebu 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"])
}
{40.68433 -74.39967}
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)
}
map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
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)
}
map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
postavljanje vrednosti
m[key] = elem
elem = m[key]
delete(m, key)
elem, ok = m[key]
Ako element postoji ok
će imati vrednost true
inače false
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}
The value: 42 The value: 48 The value: 0 The value: 0 Present? false
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
13 5 81
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),
)
}
}
0 0 1 -2 3 -6 6 -12 10 -20 15 -30 21 -42 28 -56 36 -72 45 -90
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())
}
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(Abs(v))
}
5
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())
}
1.4142135623730951
S obzirom da je ovo često potrebno, a i performanse su bolje jer nema kopiranja, pokazivački prijemnici su češći
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 (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(10)
fmt.Println(v.Abs())
}
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func Scale(v *Vertex, f float64) { // ako uklonimo `*`?
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
Scale(&v, 10)
fmt.Println(Abs(v))
}
50
Funkcija sa pokazivačkim argumentom mora primiti pokazivač
var v Vertex
ScaleFunc(v, 5) // Compile error!
ScaleFunc(&v, 5) // OK
ali metode mogu primiti bilo vrednosti bilo pokazivače kao prijemnike
var v Vertex
v.Scale(5) // OK
p := &v
p.Scale(10) // OK
v.Scale(5)
Go će pozvati metodu sa pokazivačkim prijemnikom iako
v
u ovom slučaju može biti vrednost a ne pokazivač(&v).Scale(5)
pošto
Scale
metoda ima pokazivački prijemnik package main
import "fmt"
type Vertex struct {
X, Y float64
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func ScaleFunc(v *Vertex, f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
v.Scale(2)
ScaleFunc(&v, 10)
p := &Vertex{4, 3}
p.Scale(3)
ScaleFunc(p, 8)
fmt.Println(v, p)
}
{60 80} &{96 72}
var v Vertex
fmt.Println(AbsFunc(v)) // OK
fmt.Println(AbsFunc(&v)) // Compile error!
ali metode sa vrednosnim prijemnikom mogu prihvatiti bilo vrednosti bilo pokazivače
var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK
Go će u ovom slučaju interpretirati p.Abs()
kao (*p).Abs()
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 AbsFunc(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
fmt.Println(AbsFunc(v))
p := &Vertex{4, 3}
fmt.Println(p.Abs())
fmt.Println(AbsFunc(*p))
}
Dva razloga za upotrebu pokazivačkog prijemnika:
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}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}
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 // In this line, v is a Vertex (not *Vertex)
fmt.Println(a.Abs()) // and does NOT implement Abser.
}
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)
}
./compile7.go:22:4: cannot use v (type Vertex) as type Abser in assignment: Vertex does not implement Abser (Abs method has pointer receiver)
implements
ključna reč package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()
}
Interfejs vrednosti možemo zamisliti kao uređeni par vrednosti i konkretnog tipa:
(value, type)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
(&{Hello}, *main.T) Hello (3.141592653589793, main.F) 3.141592653589793
nil
sadržanom vrednošćunil
metoda se poziva sa nil
prijemnikomnil
vrednost on nije nil
interfejsnil
prijemnikomtype I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
describe(i)
i.M()
i = &T{"hello"}
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
(<nil>, *main.T) <nil> (&{hello}, *main.T) hello
nil
interfejs vrednostnil
interfejs ne sadrži ni vrednost ni tipnil
interfejsom je run-time greška jer ne znamo
tip koji bi odredio metodu koju treba pozvati package main
import "fmt"
type I interface {
M()
}
func main() {
var i I
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
(<nil>, <nil>) panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x488ac1] goroutine 1 [running]: main.main() /tmp/compile12.go:12 +0x91
Tip interfejsa bez ijedne metode je poznat kao “prazan interfejs” (empty interface)
interface{}
fmt.Print
prihvata proizvoljan broj argumenata tipa interface{}
package main
import "fmt"
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
(<nil>, <nil>) (42, int) (hello, string)
Omogućava pristup tipu vrednosti sadržane u interfejsu
t := i.(T)
i
sadrži vrednost tipa T
i dodeljuje tu
vrednost varijabli t
tipa T
i
ne sadrži vrednost tipa T
program se prekida uz panic
greškuZa proveru da li interfejs sadrži vrednost određenog tipa koristi se comma-ok iskaz
t, ok := i.(T)
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // panic
fmt.Println(f)
}
hello hello true 0 false panic: interface conversion: interface {} is string, not float64
switch
iskazu ali svaki case
navodi tip a ne vrednost switch v := i.(type) {
case T:
// here v has type T
case S:
// here v has type S
default:
// no match; here v has the same type as i
}
type
package main
import "fmt"
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
Twice 21 is 42 "hello" is 5 bytes long I don't know about type bool!
Stringer
definisan u fmt
paketu type Stringer interface {
String() string
}
Stringer
je tip koji može da se transformiše u stringfmt
paket (i mnogi drugi) zahtevaju ovaj interfejs kada štampaju
vrednostipackage main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
error
vrednostima
error
tip je ugrađeni interfejs
type error interface {
Error() string
}
Funkcije često vraćaju error
vrednosti i pozivaoci bi trebali da
proveravaju da li je greška nil
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
fmt.Println("Converted integer:", i)
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
at 2019-05-27 15:04:16.262931451 +0200 CEST m=+0.000213564, it didn't work
io
paket definiše io.Reader
interfejs
func (T) Read(b []byte) (n int, err error)
Read
metoda puni zadati byte
isečak sa podacima i vraća broj bajtova
koji su upisani i grešku ukoliko je ima. Specijalna greška io.EOF
označava da se došlo do kraja.strings.Reader
i vrši čitanje po 8 bajtova odjednom package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
fmt.Printf("b[:n] = %q\n", b[:n])
if err == io.EOF {
break
}
}
}
n = 8 err = <nil> b = [72 101 108 108 111 44 32 82] b[:n] = "Hello, R" n = 6 err = <nil> b = [101 97 100 101 114 33 32 82] b[:n] = "eader!" n = 0 err = EOF b = [101 97 100 101 114 33 32 82] b[:n] = ""
Go rutina je nit (thread) kreirana i upravljana od strane Go izvršnog okruženja (runtime)
go f(x, y, z)
startuje novu Go rutinu koja izvršava
f(x, y, z)
f
, x
, y
i z
se dešava u tekućoj Go rutini dok se
izvršavanje funkcije f
odvija u novoj Go rutinisync
definiše
korisne primitive za sinhronizaciju iako u Go-u ovo često nije neophodno. package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
hello world world hello world ...
Tipizirane veze preko kojih se mogu slati vrednosti upotrebom operatora
kanala (channel operator) - <-
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and assign value to v.
Kanali se kreiraju dinamički upotrebom make
funkcije
ch := make(chan int)
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
-5 17 12
Kreiranje bafera omogućeno je drugim parametrom make
funkcije
ch := make(chan int, 100)
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3 // overflow blocks current Go rutine!
fmt.Println(<-ch)
fmt.Println(<-ch)
}
fatal error: all goroutines are asleep - deadlock!
close
funkcijom da
signalizira da neće više slati podatkeGo rutina koja prima podatke koristi comma-ok idiom da testira da li je kanal zatvoren
v, ok := <-ch
ok
će biti false
ako više nema podataka i kanal je zatvoren
for i := range c
prihvata podatke sa kanala c
sve dok se ne
kanal ne zatvoripanic
.range
petlja package main
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 0, 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)
}
}
0 1 1 2 ... 34
select
select
iskaz omogućava Go rutini da čeka na više komunikacionih operacijaselect
blokira dok jedna od grana nije u mogućnosti da se izvrši. Ukoliko
je više u mogućnosti da se izvrši izbor se vrši slučajno func fibonacci(c, quit chan int) {
x, y := 0, 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)
}
0 1 1 ... 34 quit
select/default
default
grana select
iskaza se izvršava ukoliko nijedna druga nije spremnadefault
da čitate ili pišete bez blokiranja select {
case i := <-c:
// use i
default:
// receiving from c would block
}
package main
import (
"fmt"
"time"
)
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
. tick. . . tick. BOOM!
sync.Mutex
Lock/Unlock
poziva // SafeCounter is safe to use concurrently.
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key]++
c.mux.Unlock()
}
// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mux.Unlock()
return c.v[key]
}
func main() {
c := SafeCounter{v: make(map[string]int)}
for i := 0; i < 1000; i++ {
go c.Inc("somekey")
}
time.Sleep(time.Second)
fmt.Println(c.Value("somekey"))
}