defer
в Generator
<3Какво ще покаже следния код?
func 4times4() (res int) { defer func() { res *= 4 } return 4 } fmt.Println(4times4())
4times4
не е валидно име на функция.С какво можем да сравняваме функции?
nil
Ако знаем, че foo
е указател към int
в масив, то как можем да вземем следващия елемент в масива?
Кога се оценяват аргументите на defer
функция?
defer
израза.package main
import "fmt"
func main() { var x [5]float64 x[0] = 98 x[1] = 93 x[2] = 77 x[3] = 82 x[4] = 83 var total float64 = 0 for i := 0; i < 5; i++ { total += x[i] } fmt.Println(total / 5) }
Очевидно броим от 0
var x [5]string x[0] = "Баба" x[1] = "меца" x[2] = "яде" x[3] = "от" x[4] = "медеца"
или накратко:
x := [6]float64{98, 93, 77, 82, 83}
Чакай малко! Подали сме само 5 числа.
x[5] == 0
x := [...]string{"Incredible", "isn't", "it?"}
x
е от тип [3]string
Да разгледаме следния код
package main
import "fmt"
func main() {
dqdo := [4]uint32{0, 1, 2, 3} baba := [4]uint32{0, 1, 2, 3} fmt.Printf("The two arrays are identical: %t\n", dqdo == baba)
}
package main
import "fmt"
func main() {
dqdo := [4]uint32{0, 1, 2, 3} baba := [5]uint32{0, 1, 2, 3} fmt.Printf("The two arrays are identical: %t\n", dqdo == baba)
}
func (foo [100]uint32)
a := [100]float64 b := a
func (foo *[100]uint32)
len()
- връща размера като intrange
- ключова дума, която позволява да итерираме по индекс и стойностfor index, value := range arr { ... } for index := 0; index < len(arr); index++ { value := arr[index] ... }
Тези два цикъла са еквивалентни
(Заради range нямаме нужда от foreach)
Като масивите имат дължина и могат да се индексират, но дължината им може да се променя*.
var x []float64
Горното само създава променливата, а се инициализира по следния начин:
x := make([]float64, 5)
Това указва на слайса да бъде с размер 5. Всеки слайс е част от масив с не по-малка дължина от слайса.
x := make([]float64, 5, 10)
Това е същото като горното, но този слайс сочи към масив с размер 10.
numbers := []float64{0, 1.2, 3.4, 55.3}
arr := [6]float64{1, 2, 3, 4, 5, 6} x := arr[1:5]
Създаваме слайс от втори до пети елемент включително на масива arr.
x := arr[2:] // Взема всички без първите два елемента x := arr[:2] // Взема първите два елемента x := arr[:] // Взема всички елементи
x := []int{2, 3, 5, 7, 11}
Създава нов slice, който сочи към нов масив от 5 елемента.
y := x[1:3]
Създава нов slice, но не и нов масив - използва се вече съществуващия за x.
len(x)
- Взема размера на slice-аcap(x)
- Взема размера на масива, към който slice-а сочиpackage main
import "fmt"
func main() { x := []int{2, 3, 5, 7, 11} y := x[1:3] fmt.Println("len(x) =", len(x), ", cap(x) =", cap(x)) fmt.Println("len(y) =", len(y), ", cap(y) =", cap(y)) }
var foo []uint32 foo == nil // True
len
и cap
връщат 0 за нулев slicelen(foo) == cap(foo) == 0
x := []uint32{0, 1, 2, 3, 4, 5, 6, 7} y := x[:] y[4] = 42 x[4] == 42 // True
y
не копира съдържанието на x
x
x := []uint32{0, 1, 2, 3, 4, 5, 6, 7} y := x[2:4] // [2, 3] y = y[:cap(y)] // [2, 3, 4, 5, 6, 7]
Built-in функция, която добавя елементи към края на slice:
sliceA := []int{1, 2, 3} sliceB := append(sliceA, 4, 5) // [1 2 3 4 5]
Може да добавя и един slice към друг:
sliceC := append(sliceA, sliceB...)
Ако в резултатния slice има достатъчно място, той се използва непроменен. Ако няма, автоматично се заделя по-голям slice:
sliceD := make([]int, 0, 3) // len = 0, cap = 3 sliceD = append(sliceD, 1, 2) // len = 2, cap = 3 sliceD = append(sliceD, 2, 4) // len = 4, cap = 6
Изтриване на n-ия елемент от слайс
x := []int{1, 2, 3, 4, 5} x = append(x[:n], x[n+1:]...)
Ако n = 2:
[]int{1, 2, 4, 5}
var l int slice1 := []int{1, 2, 3, 4} slice2 := []int{7, 6, 5}
Копираме трите елемента от slice2
в slice1
l = copy(slice1, slice2) // slice1 = [7 6 5 4], l = 3
Копираме края на slice1 в началото му
l = copy(slice1, slice1[2:]) // slice1 = [3 4 3 4], l = 2
Копираме slice1 в slice2
l = copy(slice2, slice1) // slice2 = [1 2 3], l = 3 // Копират се само първите 3 елемента, защото len(slice2) = 3
1. Опит за писане в неинициализиран слайс води до паника.
2. Масивите, в които се съхраняват данните на слайсовете, не се чистят от garbage collector-a, докато има референции (слайсове) към тях.
// WARNING: shitty code, don't do this at home. We are professionals! func GetFileHeader(filename string) []byte { b, _ := ioutil.ReadFile(filename) return b[:10] }
Цялото съдържание на файла няма да бъде изчистено от паметта, докато първите 10 байта се ползват някъде.
Решение: copy() в нов слайс
Неподредена колекция от двойки ключове и стойности
var x map[string]int // Ключовете в x са низове, а стойностите числа
За да го инициализраме, ползваме make
:
x := make(map[string]int)
Подобно на слайсовете, писането в неинициализиран map води до паника.
Ползваме го почти както масиви и слайсове. Добавяне на стойност:
x["key"] = 10
За да вземем стойност по ключ:
value, ok := x["key"]
ok
е true
, ако съществува двойка с такъв ключ. В противен случай, value
е нулевата стойност на типа (""
за string
) и ok
е false.
wordcount := map[string]int{"word1": 10, "word2": 5}
delete
:x := make(map[string]int) delete(x, "key") // Изтрива двойката с ключ е "key". Ако няма такава, нищо не се случва.
if _, ok := x["key"]; ok { fmt.Println("key exists") }
range
:for key, value := range m { fmt.Println("Key:", key, "Value:", value) }
golang.org/ref/spec#Comparison_operators
Но има sync.Map в стандартната библиотека, който позволява конкурентен достъп.
type Person struct { name string age uint } var chochko Person chochko.name = "Чочко" chochko.age = 27
Други начини за инициализиране:
chochko := Person{name: "Чочко", age: 27} chochko := Person{"Чочко", 27}
chochko := new(Person) chochko.name = "Чочко" chochko.age = 27
new само заделя и нулира памет, а make инициализира, т.е.:
package main import "fmt" type example struct { attrs map[string]int } func main() { e := new(example) e.attrs = make(map[string]int) e.attrs["h"] = 42 fmt.Println(e) }
make
се ползва само върху slice
и map