Kreirano Dec 1, 2019 Nedelja 01:12, pritisni ESC za mapu
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.12.4), OS
- operativni sistem
(npr. linux
) a ARCH
- arhitektura (npr. amd64
)
podesiti PATH
:
export PATH=$PATH:~/install/go/
$HOME/go
GOPATH
varijablu$ go version
go version go1.12.4 linux/amd64
src/hello
u workspace direktorijumu (dakle ~/go/src/hello
)
Napraviti fajl hello.go
sa sadržajem:
package main
import "fmt"
func main() {
fmt.Printf("Здраво, свете!\n")
}
Preći u projektni folder, pokrenuti build
i zatim startovati program:
$ cd ~/go/src/hello
$ go build
$ ./hello
Здраво, свете!
Go alati podrazumevaju određene konvencije u organizaciji foldera i programskog koda.
Bazirano na How to Write Go Code
git
).bin/ hello # command executable outyet # command executable src/ github.com/golang/example/ .git/ # Git repository metadata hello/ hello.go # command source outyet/ main.go # command source main_test.go # test source stringutil/ reverse.go # package source reverse_test.go # test source golang.org/x/image/ .git/ # Git repository metadata bmp/ reader.go # package source writer.go # package source ... (many more repositories and packages omitted) ...
GOPATH
$HOME/go
na Unix-like sistemima ili %USERPOFILE%\go
na
Windows-u.go env GOPATH
komanda daje informaciju o tekućoj lokaciji tj. sadržaj
GOPATH
varijable ili podrazumevanu lokaciju ukoliko nije podešena.Da bi instalirani Go programi bili dostupni:
$ export PATH=$PATH:$(go env GOPATH)/bin
fmt
, net/http
$GOPATH/src
Dobra praksa je upotreba domena VCS hosting sajtova. Na primer:
$GOPATH/src/github.com/user
$ mkdir $GOPATH/src/github.com/user/hello
hello.go
package main
import "fmt"
func main() {
fmt.Printf("Здраво, свете!\n")
}
$ go install github.com/user/hello
# ili
$ cd $GOPATH/src/github.com/user/hello
$ go install
hello
program će biti instaliran u $GOPATH/bin/
$ $GOPATH/bin/hello
Здраво, свете!
# ili samo
$ hello
Здраво, свете!
$ cd $GOPATH/src/github.com/user/hello
$ git init
Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
$ git add hello.go
$ git commit -m "initial commit"
[master (root-commit) 0b4507d] initial commit
1 file changed, 1 insertion(+)
create mode 100644 hello.go
$ mkdir $GOPATH/src/github.com/user/stringutil
// Package stringutil contains utility functions for working with strings.
package stringutil
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(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 github.com/user/stringutil
# ili ako smo već u folderu stringutil
$ go build
hello.go
package main
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("!етевс ,овардЗ"))
}
$ go install github.com/user/hello
$ hello
Здраво, свете!
bin/ hello # command executable src/ github.com/user/ hello/ hello.go # command source stringutil/ reverse.go # package source
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 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$GOPATH/src/github.com/user/stringutil/reverse_test.go
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
$ go test github.com/user/stringutil
ok github.com/user/stringutil 0.165s
# ili samo
$ go test
ok github.com/user/stringutil 0.165s
go get
alat će preuzeti kod iz udaljenog repozitorijuma ako nije dostupan
u lokalnom radnom prostoru (workspace)go help importpath
Interaktivno učenje Go jezika:
Pokretanje lokalno:
$ go get golang.org/x/tour $ tour
main
i funkciji func main()
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
rand
).Import
iskazpackage 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.
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
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)
}
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 krajuvar
iskaz se može koristiti na nivou paketa ili funkcijepackage 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 varijablipackage 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)
}
:=
dodeli može da se
koristipackage 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)
}
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)
0
za numeričke tipovefalse
za boolean
tip""
(prazan string) za string
tippackage 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
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)
}
:=
bilo var =
) tipizirana,
leva strana će biti istog tipavar i int
j := i // j is an int
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
const
:=
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)
}
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
)const (
CategoryBooks = iota // 0
CategoryHealth // 1
CategoryClothing // 2
)
type Stereotype int
const (
TypicalNoob Stereotype = iota // 0
TypicalHipster // 1
TypicalUnixWizard // 2
TypicalStartupFounder // 3
)
type AudioOutput int
const (
OutMute AudioOutput = iota // 0
OutMono // 1
OutStereo // 2
_
_
OutSurround // 5
)
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
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
()
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;
i dobijamo
ekvivalent while
petlje u drugim jezicimapackage main
import "fmt"
func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
package main
func main() {
for {
}
}
if
iskazfor
i kod if
iskaza zagrade nije potrebno navoditipackage 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))
}
if
sa kratkim iskazomfor
i if
može da ima kratak iskaz (najčešće :=
) koji se
izvršava pre uslovaif
iskazapackage 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),
)
}
if
i else
if
kratkom iskazu su dostupne i u opcionom else
blokupackage 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 uslovaif
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)
}
}
case
blok (nema
"propadanja"). Takođe case
prihvata izraz koji ne mora biti konstanta i
čija vrenost ne mora biti numeričkaswitch
iskazacase
blokova ide od vrha prema dnu dok se ne nađe prvi blok
čija vrednost je jednaka zadatom uslovuf()
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.")
}
}
switch
bez uslovaswitch true
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.")
}
}
defer
iskazdefer
ali se ciljna
funkcija ne poziva do povratkapackage main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
hello world
defer
pozivadefer
pozivi se smeštaju na stek i po povratku funcije se izvršavaju u
LIFO redosledupackage 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 ...
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
}
struct
)package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
.
operatorapackage main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
p
na strukturu, polju X
bi mogli
pristupiti sa (*p).X
Pošto je ovakva sintaksa teža za korišćenje uvedena je prečica 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)
}
struct
literaliName:
za postavljanje vrednosti polja i u
tom slučaju redosled je irelevantan&
vraća se pokazivač na strukturupackage 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)
}
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)
}
Slices
)[]T
– isečak tipa T
Isečak se formira iznad niza na sledeći način:
a[low : high]
Ovo formira polu-otvoren interval elemenata uključujući prvi ali isključujući poslednji
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s)
}
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] = "XXX"
fmt.Println(a, b)
fmt.Println(names)
}
[John Paul George Ringo] [John Paul] [Paul George] [John XXX] [XXX George] [John XXX 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)
}
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
0
i nema potporni nizpackage 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], " "))
}
}
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 mapepackage 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)
}
}
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)
}
}
nil
nil
mapa nema ključeve niti se ključevi mogu dodatimake
funkcija vraća inicijalizovanu mapu spremnu za upotrebupackage 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"])
}
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)
}
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)
}
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)
}
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),
)
}
}
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))
}
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())
}
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))
}
Funkcija sa pokazivačkim arugmentom 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 prijemnikpackage 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)
}
var v Vertex
fmt.Println(AbsFunc(v)) // OK
fmt.Println(AbsFunc(&v)) // Compile error!
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 pozvatipackage 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
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 vrednostswitch 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)
}
Stringer
definisan u fmt
paketutype 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 odjednompackage 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
petljapackage 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)
}
}
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čajnofunc 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)
}
select/default
default
grana select
iskaza se izvršava ukoliko nijedna druga nije spremnadefault
da čitate ili pišete bez blokiranjaselect {
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. ... 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"))
}