Youtube Playlist - Уроки по Golang
var для переменных
const для констант
// целые числа
var a int8 = -123 // -128 <> 127, 1 byte, 8 bits
var b int16 = -12345 // -32768 <> 32767, 2 bytes, 16 bits
var c int32 = 30 // -2bil <> 2bil, 4 bytes
var d int64 // -9pent <> 9 pent, 8 bytes
var e uint8 // 0 <> 255, 1 byte
var f uint16 // 0 <> 65535, 2 bytes
var g uint32 // 0 <> 4bil, 4 bytes
var h uint64 // 0 <> 18pent, 8 bytes
var i byte // synonim uint8
var j rune // synonim int32
var k int
var m uint
// числа с плавающей запятой
var a1 float32 = 31.111145 // 4 bytes
var b1 float64 = -235454.4555 // 8 bytes
// комплексные числа
var c1 complex64 = 1+2i
var d1 complex128 = 4+90i
//булевы
var b23 bool = true
var b13 bool = false
// строки
var name string = "Golang Lessons"
name1 := "Присвоение, где go сам определяет тип"
var name2 string // пустая строка
var (
name = 'John'
age = 32
)
var name, age = 'John', 32
func test() (string, string) {
a:= 'Hello'
b:= 'world'
return a,b
}
Если нужно вернуть больше 2-х элементов, то лучше использовать структуру.
В Go в функцию в качестве аргумента можно передать другую функцию.
Также Go поддерживает замыкание.
a := 0
for a < 1000 {
if a == 100 {
fmt.Println("a is 100")
} else {
fmt.Println(fmr.Sprintf("a is not 100. a=%d", a))
}
a++
}
Также есть switch case default.
//stack, работает по методу LIFO
defer в Golang - это ключевое слово, которое используется для отложенного выполнения функции или метода до тех пор, пока текущая функция не завершится. Когда встречается оператор defer, Golang добавляет вызов функции или метода в стек отложенных вызовов, а затем продолжает выполнение текущей функции.
defer может быть использовано для управления ресурсами, таких как файлы или сетевые соединения, чтобы гарантировать, что они будут закрыты независимо от того, как завершится функция. Он также может быть использован для обработки ошибок, когда функция должна быть завершена раньше времени.
& - получение ссылки, * - разыменование
a := "hello world"
b := 42
p := &a //ссылается на значение а (шестнадцатиричный адрес в памяти)
fmt.Println(*p) // выведет значение по ссылке
*p = "oh my" // изменило значение по ссылке, то есть в a
Логическое объединение набора полей.
type Point struct {
X int
Y int
}
p1 := Point{
X: 1,
Y: 2,
}
fmt.Println(p1)
fmt.Println(p1.X)
p2 := Point{X: 123} // другие значения проинициализируются значениями по умолчанию
Композиция и встраивание
type report struct {
sol int
temperature temperature // Поле temperature является структурой типа temperature
location location
}
type temperature struct {
high, low celsius
}
type location struct {
lat, long float64
}
type celsius float64
bradbury := location{-4.5895, 137.4417}
t := temperature{high: -1.0, low: -78.0}
report := report{sol: 15, temperature: t, location: bradbury}
fmt.Printf("%+v\n", report) // Выводит: {sol:15 temperature:{high:-1 low:-78} location:{lat:-4.5895 long:137.4417}}
fmt.Printf("a balmy %v° C\n", report.temperature.high) // Выводит: a balmy -1° C
fmt.Printf("%v° C\n", report.high) // Выводит: -1° C
report.high = 32
fmt.Printf("%v° C\n", report.temperature.high) // Выводит: 32° C
Методы для структур
func (p Point) method() {
fmt.Println(p.X)
fmt.Println(p.Y)
}
p1.method()
Слайс - абстракция/обертка над массивом.
var a [2]string // массив из 2-х элементов стринг
a[0] = "hello"
a[1] = "world"
numbers := [...]int{1,2,3} // компилятор сам считает размер массива
//slices
letters := []string{"a", "b", "c"} // не имеет размера
letters = append(letters, "d")
createSlice := make([]string, 3) // создает пустой слайс из 3-х элементов стринг
capacity for Slice - the maximum length the slice can reach when resliced;
sum := 0
for i:=0; i<10; i++ {
sum += i
}
// похоже на while
for ; sum < 1000; {
sum += 10
}
for sum < 1000 {
sum += 10
}
// бесконечный цикл
for true {
sum += 10
}
for {
sum += 10
}
arr := []string{"a", "b", "c"}
for i, l := range arr {
fmt.Println(i) // index
fmt.Println(l) // value
}
Map похоже на dict в Python.
type Point struct {
X int
Y int
}
pointsMap := map[string]Point{} // ключ - стринг, значение структура Point; {} - проинициализировали
pointsMap["a"] = Point{
X: 1,
Y: 2,
}
otherPointsMap := make(map[string]Point) // проинициализировали
var oneMorePointsMap map[string]Point // объявлена, но не проинициализирована
otherMap := map[string]int{}
// проверка ключа в мапе
key := "a"
value, ok := pointsMap[key]
if ok {
fmt.Println(value)
}
// итерация по мапе
for k, v := range pointsMap {
fmt.Println(k)
fmt.Println(v)
}
Go’s mechanism for grouping and naming related sets of methods: interfaces.
В интерфейсе не может быть данных, только методы.
type structHere struct {
N1, N2 int
}
func (s *structHere) Sum() int {
return s.N1 + s.N2
}
type InterfaceHere interface {
Sum() int
}
type otherStruct struct {
A, B int
}
func (o otherStruct) Sum() int {
return o.A + o.B
}
func main() {
var a InterfaceHere
sh := structHere{N1: 1, N2: 2}
os := otherStruct{A:2, B:3}
a = &sh
fmt.Println(a.Sum())
a = os
fmt.Println(a.Sum())
}
Interfaces are named collections of method signatures.
Основной файл:
package main
func Multiple(x, y int) int {
return x*y
}
func main() {
}
Файл с тестом (должен оканчиваться на _test.go):
package main
import "testing"
func TestMultiple(t *testing.T) {
var x, y, result = 2, 2, 4
realResult := Multiple(x, y)
if realResult != result {
t.Errorf("expected result: %d != %d real result", result, realResult)
}
}
С goconvey (каждый запускается с начала):
package main
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestExampleCleanup(t *testing.T) {
x := 0
Convey("A", t, func() {
x++
Convey("A-B", func() {
x++
Convey("A-B-C", func() {
So(x, ShouldEqual, 2)
})
Convey("A-B-C1", func() {
So(x, ShouldEqual, 4)
})
Convey("A-B-C2", func() {
So(x, ShouldEqual, 6)
})
})
Reset(func() {
t.Log("finish")
})
})
}
package main
import {
"fmt"
"time"
}
func main() {
go say("hello")
fmt.Println("1")
fmt.Println("2")
fmt.Println("3")
fmt.Println("4")
fmt.Println("5")
time.Sleep(2 * time.Second)
}
func say(word string) {
time.Sleep(1 * time.Second)
fmt.Println(word)
}
package main
import {
"fmt"
"time"
}
func main() {
ch := make(chan int)
go sayHello(ch)
for i := range ch { //цикл по каналу
fmt.Println(i)
}
}
func sayHello(exit chan int) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
exit <- i // пишем в канал
}
close(exit) //закрытие канала
}
package main
import {
"fmt"
"time"
}
func main() {
data := make(chan int)
exit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-data)
}
exit <- 0
}()
selectOne(data, exit)
}
func selectOne(data, exit chan int) {
x: = 0
for {
select {
case data <- x:
x += 1
case <- exit:
fmt.Println("exit")
return
default:
fmt.Println("waiting")
time.Sleep(50 * time.Millisecond)
}
}
}
package main
import (
"fmt"
"sync"
"time"
)
type Counter struct {
mu sync.Mutex // выше тех значений, которые должен защищать
c map[string]int
}
func (c *Counter) Inc(key string) {
c.mu.Lock()
c.c[key]++ // код критической секции
c.mu.Unlock()
}
func (c *Counter) Value(key string) int {
c.mu.Lock()
defer c.mu.Unlock() // когда в return критический код
return c.c[key]
}
func main() {
key := 'test'
c := Counter{c: make(map[string]int)}
for i := 0; i<1000; i++ {
go c.Inc(key)
}
time.Sleep(time.Second * 3)
fmt.Println(c.Value(key))
}
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
k := i
go func() {
defer wg.Done()
fmt.Printf("%d goroutine working...\n", k)
time.Sleep(300 * time.Millisecond)
}()
}
wg.Wait()
fmt.Println("all done")
}
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var wg sync.WaitGroup
var counter uint64
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
atomic.AddUint64(&counter, 1)
}
}()
}
wg.Wait()
fmt.Printf("all done. counter=%d\n", counter)
}
package main
import (
"fmt"
"sync"
)
func main() {
var once sync.once
done := make(chan bool)
for i := 0; i < 30; i++ {
go func() {
once.Do(func() {
fmt.Println("the only one")
})
done <- true
}()
}
for i := 0; i < 30; i++ {
<- done
}
}
panic("something goes wrong")
package main
import "log"
func main() {
divide(4,0)
}
func divide(a,b int) {
defer func() {
if err := recover(); err != nil {
log.Println("panic happened")
}
}()
fmt.Println(a / b)
}
package main
import "os/exec"
func main() {
c := exec.Command("top")
c.Stdin = os.Stdin
c.Stdout = st.Stdout
c.Stderr = os.Stderr
c.Run()
}
package main
import (
"context"
"fmt"
"net/http"
"time"
)
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
go func() {
err := cancelRequest(ctx)
if err != nil {
cancel()
}
}()
doRequest(ctx, "https://ya.ru")
}
func cancelRequest(ctx context.Context) error {
time.Sleep(100 * time.Millisecond)
return fmt.Errorf("fail request")
}
func doRequest(ctx context.Context, requestStr string) {
req, _ := http.NewRequest(http.MethodGet, requestStr, nil)
req = req.WithContext(ctx)
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
panic(err)
}
select {
case <-time.After(500 * time.Millisecond):
fmt.Printf("response completed, status code=%d", res.StatusCode)
case <-ctx.Done():
fmt.Println("request too long")
}
}
Два метода:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
IsBlocked bool `json:"is_blocked"`
Books []Book `json:"books"`
}
type Book struct {
Name string `json:"name"`
Year int `json:"year"`
}
func main() {
serialize()
byt := []byte(`{"name":"Artur","age":80,"is_blocked":true,"books":[{"name":"Harry Potter","year":1999},{"name":"Lord of the rings","year":2000}]}`)
var dat User
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat.Books[0].Name)
}
func serialize() {
var books []Book
books = append(books, Book{Name: "Harry Potter", Year: 1999}, Book{Name: "Lord of the rings", Year: 2000})
sv := User{
Name: "Artur",
Age: 80,
IsBlocked: true,
Books: books,
}
boolVar, _ := json.Marshal(sv)
fmt.Println(string(boolVar))
}