Samouczek Golang: Naucz się języka programowania Go dla początkujących

Co to jest Go?

Go (znany również jako Golang) jest językiem programowania open source opracowanym przez Google. Jest to statycznie typowany kompilowany język. Go obsługuje programowanie współbieżne, tzn. pozwala na jednoczesne uruchamianie wielu procesów. Jest to możliwe dzięki kanałom, goroutines itp. Język Go ma zbieranie śmieci, które samo zarządza pamięcią i pozwala na opóźnione wykonywanie funkcji.

W tym samouczku Learn Go Language nauczymy się wszystkich podstaw języka Golang.

Jak pobrać i zainstalować GO

Krok 1) Iść do https://golang.org/dl/. Pobierz plik binarny dla swojego systemu operacyjnego.

Krok 2) Double kliknij instalator i kliknij Uruchom.

Krok 3) Kliknij Dalej

Krok 4) Wybierz folder instalacyjny i kliknij Dalej.

Krok 5) Kliknij Zakończ po zakończeniu instalacji.

Krok 6) Po zakończeniu instalacji możesz to sprawdzić, otwierając terminal i wpisując

go version

Spowoduje to wyświetlenie zainstalowanej wersji go

Twój program First Go – Go Hello World!

Utwórz folder o nazwie studyGo. W tym samouczku języka Go utworzymy nasze programy w tym folderze. Pliki Go są tworzone z rozszerzeniem .wybrać się. Możesz uruchamiać programy Go, używając składni

go run <filename>

Utwórz plik o nazwie First.go, dodaj do niego poniższy kod i zapisz

package main
import ("fmt")

func main() {
	fmt.Println("Hello World! This is my first Go program\n")
}

Przejdź do tego folderu w terminalu. Uruchom program za pomocą polecenia

idź najpierw pobiegnij. idź

Możesz zobaczyć wydruk wyjściowy

Hello World! This is my first Go program

Omówmy teraz powyższy program.

package main – Każdy program Go Language powinien zaczynać się od nazwy pakietu. Go pozwala nam używać pakietów w innych programach go, a tym samym wspiera ponowne wykorzystanie kodu. Wykonanie programu Go rozpoczyna się od kodu znajdującego się w pakiecie o nazwie main.

import fmt – importuje pakiet fmt. Pakiet ten implementuje funkcje we/wy.

func main() – Jest to funkcja, od której rozpoczyna się wykonywanie programu. Funkcja główna powinna być zawsze umieszczona w pakiecie głównym. Pod funkcją main() możesz wpisać kod wewnątrz { }.

fmt.Println – Spowoduje wydrukowanie tekstu na ekranie za pomocą funkcji Println fmt.

Uwaga: w poniższych sekcjach tego samouczka Go, gdy wspominasz o wykonaniu/uruchomieniu kodu, oznacza to zapisanie kodu w pliku z rozszerzeniem .go i uruchomienie go przy użyciu składni

    go run <filename>

Typy danych

Typy (typy danych) reprezentują typ wartości przechowywanej w zmiennej, typ wartości zwracanej przez funkcję itp.

Istnieją trzy podstawowe typy w języku Go

Typy liczbowe – Reprezentują wartości liczbowe, w tym liczby całkowite, zmiennoprzecinkowe i wartości zespolone. Różne typy liczbowe to:

int8 – 8-bitowe liczby całkowite ze znakiem.

int16 – 16-bitowe liczby całkowite ze znakiem.

int32 – 32-bitowe liczby całkowite ze znakiem.

int64 – 64-bitowe liczby całkowite ze znakiem.

uint8 – 8-bitowe liczby całkowite bez znaku.

uint16 – 16-bitowe liczby całkowite bez znaku.

uint32 – 32-bitowe liczby całkowite bez znaku.

uint64 – 64-bitowe liczby całkowite bez znaku.

float32 – 32-bitowe liczby zmiennoprzecinkowe.

float64 – 64-bitowe liczby zmiennoprzecinkowe.

complex64 – ma float32 części rzeczywistej i urojonej.

complex128 – ma float32 części rzeczywistej i urojonej.

Rodzaje ciągów – Reprezentuje sekwencję bajtów (znaków). Możesz wykonywać różne operacje na ciągach, takie jak łączenie ciągów, wyodrębnianie podciągów itp.

Typy logiczne – Reprezentuje 2 wartości, prawdę lub fałsz.

Interfejs Golanga

Interfejs Golanga to zbiór sygnatur metod używanych przez Type do implementowania zachowania obiektów. Głównym celem interfejsu Golang jest dostarczanie sygnatur metod z nazwami, argumentami i typami zwracanych wartości. Zadeklarowanie i zaimplementowanie metody zależy od typu. Interfejs w języku Golang można zadeklarować za pomocą słowa kluczowego „interfejs”.

Zmienne

Zmienne wskazują lokalizację pamięci, w której przechowywana jest pewna wartość. Parametr typu (w poniższej składni) reprezentuje typ wartości, która może być przechowywana w lokalizacji pamięci.

Zmienną można zadeklarować za pomocą składni

    var <variable_name> <type>

Po zadeklarowaniu zmiennej typu możesz przypisać zmienną do dowolnej wartości tego typu.

Możesz także nadać zmiennej wartość początkową podczas samej deklaracji, używając

    var <variable_name> <type> = <value>

Jeśli zadeklarujesz zmienną z wartością początkową, wywnioskowaj typ zmiennej z typu przypisanej wartości. Możesz więc pominąć typ podczas deklaracji, używając składni

    var <variable_name> = <value>

Możesz także zadeklarować wiele zmiennych za pomocą składni

    var <variable_name1>, <variable_name2>  = <value1>, <value2>

Poniższy program w tym samouczku Go zawiera kilka przykładów deklaracji zmiennych w języku Golang

 
package main
import "fmt"

func main() {
    //declaring a integer variable x
    var x int
    x=3 //assigning x the value 3 
    fmt.Println("x:", x) //prints 3
    
    //declaring a integer variable y with value 20 in a single statement and prints it
    var y int=20
    fmt.Println("y:", y)
    
    //declaring a variable z with value 50 and prints it
    //Here type int is not explicitly mentioned 
    var z=50
    fmt.Println("z:", z)
    
    //Multiple variables are assigned in single line- i with an integer and j with a string
    var i, j = 100,"hello"
    fmt.Println("i and j:", i,j)
}

Dane wyjściowe będą

x: 3
y: 20
z: 50
i and j: 100 hello

Język Go zapewnia także łatwy sposób deklarowania wartości zmiennych poprzez pominięcie słowa kluczowego var using

    <variable_name> := <value>

Zauważ, że użyłeś := zamiast =. Nie możesz użyć := tylko do przypisania wartości do zmiennej, która jest już zadeklarowana. := służy do deklarowania i przypisywania wartości.

Utwórz plik o nazwie assign.go z następującym kodem

package main
import ("fmt")

func main() {
	a := 20
	fmt.Println(a)

	//gives error since a is already declared
	a := 30
	fmt.Println(a)
}

Wykonaj polecenie go run sign.go, aby zobaczyć wynik jako

./assign.go:7:4: no new variables on left side of :=		

Zmienne zadeklarowane bez wartości początkowej będą miały wartość 0 dla typów numerycznych, wartość false dla typów logicznych i pusty ciąg znaków dla ciągów

Stałe

Zmienne stałe to te zmienne, których wartości nie można zmienić po przypisaniu. Stała w języku programowania Go jest deklarowana za pomocą słowa kluczowego „const”

Utwórz plik o nazwie constant.go i użyj następującego kodu

package main
import ("fmt")

func main() {
	const b =10
	fmt.Println(b)
	b = 30
	fmt.Println(b)
}

Wykonaj idź, uruchom stałą.go, aby zobaczyć wynik jako

.constant.go:7:4: cannot assign to b

Przykłady pętli

Pętle służą do wielokrotnego wykonywania bloku instrukcji w oparciu o warunek. Większość języków programowania udostępnia 3 rodzaje pętli – for, while, do while. Ale język programowania Go obsługuje tylko pętlę for.

Składnia pętli for Golang jest następująca

for initialisation_expression; evaluation_expression; iteration_expression{
   // one or more statement
}

Wyrażenie_inicjalizacji jest wykonywane jako pierwsze (i tylko raz) w pętli for Golang.

Następnie oceniane jest wyrażenie_oceny i jeśli jest prawdziwe, wykonywany jest kod znajdujący się w bloku.

Wykonywany jest identyfikator iteracji_wyrażenia, a ocena_wyrażenia jest oceniana ponownie. Jeśli to prawda, blok instrukcji zostanie wykonany ponownie. Będzie to trwało, dopóki wyrażenie_oceny nie stanie się fałszywe.

Skopiuj poniższy program do pliku i uruchom go, aby zobaczyć pętlę for języka Go drukującą liczby od 1 do 5

package main
import "fmt"

func main() {  
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
    }
}

Wyjście to

1
2
3
4
5

Jeśli inaczej

Jeśli else jest instrukcją warunkową. Synaks jest

if condition{
// statements_1
}else{
// statements_2
}

Tutaj oceniany jest warunek i jeśli jest prawdziwy, wykonane zostaną instrukcje_1, w przeciwnym razie wykonane zostaną instrukcje_2.

Możesz użyć instrukcji if również bez else. Można także połączyć instrukcje if else. Poniższe programy wyjaśnią więcej na temat if else.

Wykonaj poniższy program. Sprawdza, czy liczba x jest mniejsza niż 10. Jeśli tak, wyświetli „x jest mniejsze niż 10”

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x < 10
        fmt.Println("x is less than 10")
    } 
}

Tutaj, ponieważ wartość x jest większa niż 10, instrukcja if w warunku bloku nie zostanie wykonana.

Teraz spójrz na poniższy program. W tym samouczku dotyczącym języka programowania Go mamy blok else, który zostanie wykonany w przypadku niepowodzenia oceny if.

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else {
        //Executes if x >= 10
        fmt.Println("x is greater than or equals 10")
    }
}

Ten program wyświetli dane wyjściowe

x is greater than or equals 10

W tym samouczku Go zobaczymy program z wieloma blokami if else (połączonymi łańcuchowo if else). Wykonaj poniższy przykład Go. Sprawdza, czy liczba jest mniejsza niż 10, mieści się w przedziale 10-90 lub jest większa niż 90.

package main
import "fmt"

func main() {  
    var x = 100
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else if x >= 10 && x <= 90 {
        //Executes if x >= 10 and x<=90
        fmt.Println("x is between 10 and 90")
    } else {
        //Executes if both above cases fail i.e x>90
        fmt.Println("x is greater than 90")
    }
}

Tutaj najpierw warunek if sprawdza, czy x jest mniejsze niż 10 i tak nie jest. Sprawdza zatem, czy następny warunek (else if) mieści się w przedziale od 10 do 90, co również jest fałszywe. Następnie wykonuje blok w sekcji else, który daje wynik

x is greater than 90

Przełącznik

Switch to kolejna instrukcja warunkowa. Instrukcje Switch oceniają wyrażenie, a wynik jest porównywany z zestawem dostępnych wartości (przypadków). Po znalezieniu dopasowania wykonywane są instrukcje powiązane z tym dopasowaniem (przypadkiem). Jeśli nie zostanie znalezione żadne dopasowanie, nic nie zostanie wykonane. Możesz także dodać domyślny przypadek do przełączenia, który zostanie wykonany, jeśli nie zostaną znalezione żadne inne dopasowania. Składnia przełącznika jest następująca

switch expression {
    case value_1:
        statements_1
    case value_2:
        statements_2
    case value_n:
        statements_n
    default:
        statements_default
    }

Tutaj wartość wyrażenia jest porównywana z wartościami w każdym przypadku. Po znalezieniu dopasowania wykonywane są instrukcje powiązane z tym przypadkiem. Jeśli nie zostanie znalezione żadne dopasowanie, wykonywane są instrukcje z sekcji domyślnej.

Wykonaj poniższy program

package main
import "fmt"

func main() {  
    a,b := 2,1
    switch a+b {
    case 1:
        fmt.Println("Sum is 1")
    case 2:
        fmt.Println("Sum is 2")
    case 3:
        fmt.Println("Sum is 3")
    default:
        fmt.Println("Printing default")
    }
}

Otrzymasz dane wyjściowe jako

Sum is 3		

Zmień wartość a i b na 3, a wynik będzie taki

Printing default

W przypadku można również umieścić wiele wartości, oddzielając je przecinkiem.

Tablice

Array reprezentuje stały rozmiar, nazwaną sekwencję elementów tego samego typu. Nie można mieć tablicy zawierającej zarówno liczby całkowite, jak i znaki. Po zdefiniowaniu rozmiaru nie można zmienić rozmiaru tablicy.

Składnia deklarowania tablicy jest następująca

var arrayname [size] type

Każdemu elementowi tablicy można przypisać wartość za pomocą składni

arrayname [index] = value

Indeks tablicy zaczyna się od 0 do rozmiaru-1.

Możesz przypisywać wartości do elementów tablicy podczas deklaracji, używając składni

arrayname := [size] type {value_0,value_1,…,value_size-1} 

Możesz także zignorować parametr size podczas deklarowania tablicy z wartościami, zastępując size przez ... a kompilator znajdzie długość na podstawie liczby wartości. Składnia jest

arrayname :=  […] type {value_0,value_1,…,value_size-1}

Długość tablicy można znaleźć, korzystając ze składni

len(arrayname)

Wykonaj poniższy przykład Go, aby zrozumieć tablicę

package main
import "fmt"

func main() {  
    var numbers [3] string //Declaring a string array of size 3 and adding elements 
    numbers[0] = "One"
    numbers[1] = "Two"
    numbers[2] = "Three"
    fmt.Println(numbers[1]) //prints Two
    fmt.Println(len(numbers)) //prints 3
    fmt.Println(numbers) // prints [One Two Three]

    directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements 
    fmt.Println(directions) //prints [1 2 3 4 5]
    fmt.Println(len(directions)) //prints 5

    //Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array)
    //fmt.Println(directions[5]) 
}

Wydajność

Two
3
[One Two Three]
[1 2 3 4 5]
5

Funkcja krojenia i dołączania Golanga

Plasterek to część lub segment tablicy. Lub jest to widok lub częściowy widok podstawowej tablicy, na którą wskazuje. Dostęp do elementów plasterka można uzyskać, używając nazwy plasterka i numeru indeksu, tak samo jak w przypadku tablicy. Nie możesz zmienić długości tablicy, ale możesz zmienić rozmiar plasterka.

Zawartość plasterka jest w rzeczywistości wskaźnikami do elementów tablicy. To znaczy jeśli zmienisz dowolny element w plasterku, będzie to miało wpływ również na zawartość tablicy.

Składnia tworzenia plasterka jest następująca

var slice_name [] type = array_name[start:end]

Spowoduje to utworzenie plasterka o nazwie nazwa_plasterka z tablicy o nazwie nazwa_tablicy z elementami od początku do końca indeksu -1.

Teraz w tym samouczku Golang wykonamy poniższy program. Program utworzy wycinek z tablicy i wydrukuje go. Możesz także zobaczyć, że modyfikacja zawartości wycinka spowoduje modyfikację rzeczywistej tablicy.

package main
import "fmt"

func main() {  
    // declaring array
    a := [5] string {"one", "two", "three", "four", "five"}
    fmt.Println("Array after creation:",a)

    var b [] string = a[1:4] //created a slice named b
    fmt.Println("Slice after creation:",b)

    b[0]="changed" // changed the slice data
    fmt.Println("Slice after modifying:",b)
    fmt.Println("Array after slice modification:",a)
}

Spowoduje to wydrukowanie wyniku jako

Array after creation: [one two three four five]
Slice after creation: [two three four]
Slice after modifying: [changed three four]
Array after slice modification: [one changed three four five]

Istnieją pewne funkcje, takie jak Golang len, Golang append, które można zastosować na plasterkach

len(nazwa_kawałka) – zwraca długość plasterka

append(nazwa_kawałka, wartość_1, wartość_2) – Dołączenie Golanga służy do dołączenia wartości_1 i wartości_2 do istniejącego plasterka.

append(kawałek_nale1,nazwa_kawałka2…) – dołącza nazwa_plasterka2 do nazwa_plasterku1

Uruchom następujący program.

package main
import "fmt"

func main() {  
	a := [5] string {"1","2","3","4","5"}
	slice_a := a[1:3]
	b := [5] string {"one","two","three","four","five"}
	slice_b := b[1:3]

    fmt.Println("Slice_a:", slice_a)
    fmt.Println("Slice_b:", slice_b)
    fmt.Println("Length of slice_a:", len(slice_a))
    fmt.Println("Length of slice_b:", len(slice_b))

    slice_a = append(slice_a,slice_b...) // appending slice
    fmt.Println("New Slice_a after appending slice_b :", slice_a)
    
    slice_a = append(slice_a,"text1") // appending value
    fmt.Println("New Slice_a after appending text1 :", slice_a)
}

Dane wyjściowe będą

Slice_a: [2 3]
Slice_b: [two three]
Length of slice_a: 2
Length of slice_b: 2
New Slice_a after appending slice_b : [2 3 two three]
New Slice_a after appending text1 : [2 3 two three text1]

Program najpierw tworzy 2 plasterki i drukuje ich długość. Następnie dołączył jeden plasterek do drugiego, a następnie dołączył ciąg do powstałego plasterka.

Funkcje

Funkcja reprezentuje blok instrukcji, który wykonuje określone zadanie. Deklaracja funkcji podaje nam nazwę funkcji, typ zwracanej wartości i parametry wejściowe. Definicja funkcji reprezentuje kod zawarty w funkcji. Składnia deklarowania funkcji jest następująca

func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}

Parametry i typy zwracane są opcjonalne. Możesz także zwrócić wiele wartości z funkcji.

Teraz w tym samouczku Golanga, uruchommy następujący przykład Golanga. Tutaj funkcja o nazwie calc zaakceptuje 2 liczby i wykona dodawanie i odejmowanie i zwróci obie wartości.

package main
import "fmt"

//calc is the function name which accepts two integers num1 and num2
//(int, int) says that the function returns two values, both of integer type.
func calc(num1 int, num2 int)(int, int) {  
    sum := num1 + num2
    diff := num1 - num2
    return sum, diff
}

func main() {  
    x,y := 15,10

    //calls the function calc with x and y an d gets sum, diff as output
    sum, diff := calc(x,y) 
    fmt.Println("Sum",sum)
    fmt.Println("Diff",diff) 
}

Dane wyjściowe będą

Sum 25
Diff 5

Pakiety

Pakiety służą do organizowania kodu. W dużym projekcie nie da się napisać kodu w jednym pliku. Język programowania Go pozwala nam organizować kod w różnych pakietach. Zwiększa to czytelność kodu i możliwość jego ponownego użycia. Wykonywalny program Go powinien zawierać pakiet o nazwie main, a wykonywanie programu rozpoczyna się od funkcji o nazwie main. Możesz zaimportować inne pakiety w naszym programie za pomocą składni

import package_name

W tym samouczku języka Go zobaczymy i omówimy, jak tworzyć i używać pakietów w poniższym przykładzie języka Go.

Krok 1) Utwórz plik o nazwie package_example.go i dodaj poniższy kod

package main
import "fmt"
//the package to be created
import "calculation"

func main() {  
	x,y := 15,10
	//the package will have function Do_add()
sum := calculation.Do_add(x,y)
fmt.Println("Sum",sum) 
}

W powyższym programie fmt jest pakietem, który język programowania Go udostępnia nam głównie do celów we/wy. Możesz także zobaczyć pakiet o nazwie obliczenie. Wewnątrz funkcji main() możesz zobaczyć sumę kroków := obliczenia.Do_add(x,y). Oznacza to, że wywołujesz funkcję Do_add z obliczenia pakietu.

Krok 2) Najpierw powinieneś utworzyć kalkulację pakietu w folderze o tej samej nazwie w folderze src. Zainstalowaną ścieżkę go można znaleźć w zmiennej PATH.

W przypadku komputerów Mac znajdź ścieżkę, wykonując echo $PATH

Zatem ścieżka to /usr/local/go

W przypadku systemu Windows znajdź ścieżkę, wykonując polecenie echo %GOROOT%

Tutaj ścieżka to C:\Go\

Krok 3) Przejdź do folderu src (/usr/local/go/src dla komputerów Mac i C:\Go\src dla systemów Windows). Teraz w kodzie nazwa pakietu to accounting. Go wymaga, aby pakiet został umieszczony w katalogu o tej samej nazwie w katalogu src. Utwórz katalog o nazwie accounting w folderze src.

Krok 4) Utwórz plik o nazwie calc.go (możesz podać dowolną nazwę, ale nazwa pakietu w kodzie ma znaczenie. Tutaj powinny być obliczenia) w katalogu obliczeń i dodaj poniższy kod

package calculation
  
func Do_add(num1 int, num2 int)(int) {
    sum := num1 + num2
    return sum
}

Krok 5) Uruchom polecenie go install z katalogu obliczeń, który skompiluje plik calc.go.

Krok 6) Teraz wróć do package_example.go i uruchom go run package_example.go. Wynikiem będzie Suma 25.

Należy pamiętać, że nazwa funkcji Do_add zaczyna się od dużej litery. Dzieje się tak dlatego, że w Go, jeśli nazwa funkcji zaczyna się z dużej litery, oznacza to, że inne programy mogą ją zobaczyć (uzyskać do niej dostęp), w przeciwnym razie inne programy nie będą miały do ​​niej dostępu. Gdyby nazwa funkcji brzmiała do_add , wystąpiłby błąd

nie może odwoływać się do niewyeksportowanej nazwy obliczeń.calc..

Odroczenie i układanie w stosy

Instrukcje Defer służą do odroczenia wykonania wywołania funkcji do czasu zakończenia wykonywania funkcji zawierającej instrukcję Defer.

Nauczmy się tego na przykładzie:

package main
import "fmt"

func sample() {  
    fmt.Println("Inside the sample()")
}
func main() {  
    //sample() will be invoked only after executing the statements of main()
    defer sample()
    fmt.Println("Inside the main()")
}

Dane wyjściowe będą

Inside the main()
Inside the sample()

W tym przypadku wykonanie próbki() jest odroczone do czasu zakończenia wykonywania otaczającej ją funkcji (main()).

Odroczenie stosowe wykorzystuje wiele instrukcji odroczenia. Załóżmy, że wewnątrz funkcji znajduje się wiele instrukcji odroczenia. Go umieszcza wszystkie odroczone wywołania funkcji na stosie, a gdy funkcja otaczająca powróci, funkcje ułożone w stos zostaną wykonane w Zamówienie „ostatnie weszło, pierwsze wyszło” (LIFO). Można to zobaczyć na poniższym przykładzie.

Wykonaj poniższy kod

package main
import "fmt"

func display(a int) {  
    fmt.Println(a)
}
func main() {  
    defer display(1)
    defer display(2)
    defer display(3)
    fmt.Println(4)
}

Dane wyjściowe będą

4
3
2
1			

Tutaj najpierw wykonywany jest kod wewnątrz funkcji main(), a następnie odroczone wywołania funkcji są wykonywane w odwrotnej kolejności, tj. 4, 3,2,1.

wskaźniki

Zanim wyjaśnimy wskaźniki, omówmy najpierw operator '&'. Operator '&' jest używany do uzyskania adresu zmiennej. Oznacza to, że '&a' wydrukuje adres pamięci zmiennej a.

W tym samouczku Golang uruchomimy poniższy program, aby wyświetlić wartość zmiennej i adres tej zmiennej

package main
import "fmt"

func main() {
	a := 20
	fmt.Println("Address:",&a)
	fmt.Println("Value:",a)
}

Wynik będzie

Address: 0xc000078008
Value: 20

Zmienna wskaźnikowa przechowuje adres pamięci innej zmiennej. Wskaźnik można zdefiniować za pomocą składni

	var variable_name *type

Gwiazdka (*) oznacza, że ​​zmienna jest wskaźnikiem. Więcej zrozumiesz wykonując poniższy program

package main
import "fmt"

func main() {
	//Create an integer variable a with value 20
	a := 20
	
	//Create a pointer variable b and assigned the address of a
	var b *int = &a

	//print address of a(&a) and value of a  
	fmt.Println("Address of a:",&a)
	fmt.Println("Value of a:",a)

	//print b which contains the memory address of a i.e. &a
	fmt.Println("Address of pointer b:",b)

	//*b prints the value in memory address which b contains i.e. the value of a
	fmt.Println("Value of pointer b",*b)

	//increment the value of variable a using the variable b
	*b = *b+1

	//prints the new value using a and *b
	fmt.Println("Value of pointer b",*b)
	fmt.Println("Value of a:",a)}

Dane wyjściowe będą

Address of a: 0x416020
Value of a: 20
Address of pointer b: 0x416020
Value of pointer b 20
Value of pointer b 21
Value of a: 21

Struktury

Struktura to typ danych zdefiniowany przez użytkownika, który sam zawiera jeszcze jeden element tego samego lub innego typu.

Korzystanie ze struktury jest procesem dwuetapowym.

Najpierw utwórz (zadeklaruj) typ struktury

Po drugie, utwórz zmienne tego typu do przechowywania wartości.

Struktury są używane głównie wtedy, gdy chcesz razem przechowywać powiązane dane.

Weź pod uwagę informację o pracowniku, która zawiera imię i nazwisko, wiek i adres. Można sobie z tym poradzić na 2 sposoby

Utwórz 3 tablice – jedna tablica przechowuje nazwiska pracowników, jedna wiek, a trzecia wiek.

Zadeklaruj typ struktury za pomocą 3 pól – nazwy, adresu i wieku. Utwórz tablicę tego typu struktury, w której każdy element jest obiektem struktury mającym nazwę, adres i wiek.

Pierwsze podejście nie jest skuteczne. W tego rodzaju scenariuszach struktury są wygodniejsze.

Składnia deklarowania struktury jest następująca

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Przykładem deklaracji struktury jest

type emp struct {
    name string
    address string
    age int
}

Tutaj tworzony jest nowy typ zdefiniowany przez użytkownika o nazwie emp. Teraz możesz tworzyć zmienne typu emp, używając składni

	var variable_name struct_name

Przykładem jest

var empdata1 emp 

Możesz ustawić wartości dla empdata1 jako

empdata1.name = "John"
	empdata1.address = "Street-1, Bangalore"
	empdata1.age = 30

Można także utworzyć zmienną struktury i przypisać wartości według

empdata2 := emp{"Raj", "Building-1, Delhi", 25}

Tutaj trzeba zachować kolejność elementów. Raj zostanie przypisany do imienia, następnego elementu do adresowania i ostatniego do wieku.

Wykonaj poniższy kod

package main
import "fmt"

//declared the structure named emp
type emp struct {
        name string
        address string
        age int
}       

//function which accepts variable of emp type and prints name property
func display(e emp) {
          fmt.Println(e.name)
}

func main() {
// declares a variable, empdata1, of the type emp
var empdata1 emp
//assign values to members of empdata1
empdata1.name = "John"
empdata1.address = "Street-1, London"
empdata1.age = 30

//declares and assign values to variable empdata2 of type emp
empdata2 := emp{"Raj", "Building-1, Paris", 25}

//prints the member name of empdata1 and empdata2 using display function
display(empdata1)
display(empdata2)
}

Wydajność

John
Raj

Metody (nie funkcje)

Metoda to funkcja posiadająca argument odbiorcy. Archiz technicznego punktu widzenia znajduje się pomiędzy słowem kluczowym func a nazwą metody. Składnia metody jest taka

func (variable variabletype) methodName(parameter1 paramether1type) {  
}

Przekonwertujmy powyższy przykładowy program tak, aby zamiast funkcji używał metod.

package main
import "fmt"

//declared the structure named emp
type emp struct {
    name string
    address string
    age int
}

//Declaring a function with receiver of the type emp
func(e emp) display() {
    fmt.Println(e.name)
}

func main() {
    //declaring a variable of type emp
    var empdata1 emp
    
    //Assign values to members
    empdata1.name = "John"
    empdata1.address = "Street-1, Lodon"
    empdata1.age = 30

    //declaring a variable of type emp and assign values to members
    empdata2 := emp {
        "Raj", "Building-1, Paris", 25}

    //Invoking the method using the receiver of the type emp
   // syntax is variable.methodname()
    empdata1.display()
    empdata2.display()
}

Go nie jest językiem obiektowym i nie ma w nim koncepcji klasy. Metody dają wyobrażenie o tym, co robisz w programach obiektowych, w których funkcje klasy są wywoływane przy użyciu składni nazwaobiektu.nazwafunkcji()

Konkurencja

Go obsługuje współbieżne wykonywanie zadań. Oznacza to, że Go może wykonywać wiele zadań jednocześnie. Różni się to od koncepcji paralelizmu. W paralelizmie zadanie jest dzielone na małe podzadania i wykonywane równolegle. Natomiast w przypadku współbieżności wiele zadań jest wykonywanych jednocześnie. Współbieżność jest osiągana w Go za pomocą Goroutines i Channels.

Gorutyny

Goroutine to funkcja, która może działać jednocześnie z innymi funkcjami. Zwykle po wywołaniu funkcji sterowanie zostaje przeniesione do wywoływanej funkcji, a po zakończeniu jej wykonywania kontrola powraca do funkcji wywołującej. Następnie funkcja wywołująca kontynuuje wykonywanie. Funkcja wywołująca czeka, aż wywołana funkcja zakończy wykonywanie, zanim przejdzie do pozostałych instrukcji.

Jednak w przypadku goroutine funkcja wywołująca nie będzie czekać na zakończenie wykonywania wywołanej funkcji. Będzie kontynuować wykonywanie z następnymi instrukcjami. W programie możesz mieć wiele goroutines.

Ponadto główny program zakończy działanie po zakończeniu wykonywania swoich instrukcji i nie będzie czekać na zakończenie wywołanych procedur gor.

Goroutine jest wywoływany za pomocą słowa kluczowego go, po którym następuje wywołanie funkcji.

Przykład

go add(x,y)

Gorutyny zrozumiesz dzięki poniższym przykładom Golang. Wykonaj poniższy program

package main
import "fmt"
    
func display() {
	for i:=0; i<5; i++ {
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	//The main() continues without waiting for display()
	for i:=0; i<5; i++ {
		fmt.Println("In main")
	}
}

Dane wyjściowe będą

In main
In main
In main
In main
In main

Tutaj główny program zakończył wykonywanie jeszcze przed rozpoczęciem goroutine. Display() to goroutine wywoływana przy użyciu składni

go function_name(parameter list)

W powyższym kodzie funkcja main() nie czeka na zakończenie funkcji display(), a funkcja main() zakończyła wykonywanie, zanim funkcja display() wykonała swój kod. Zatem instrukcja print wewnątrz display() nie została wydrukowana.

Teraz modyfikujemy program, aby drukował także instrukcje z display(). Dodajemy opóźnienie czasowe wynoszące 2 sekundy w pętli for funkcji main() i 1 sekundę opóźnienia w pętli for funkcji display().

package main
import "fmt"
import "time"
    
func display() {
	for i:=0; i<5; i++ {
		time.Sleep(1 * time.Second)
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	for i:=0; i<5; i++ {
		time.Sleep(2 * time.Second)
		fmt.Println("In main")
	}
}

Dane wyjściowe będą nieco podobne do

In display
In main
In display
In display
In main
In display
In display
In main
In main
In main

Tutaj możesz zobaczyć, że obie pętle są wykonywane w sposób nakładający się ze względu na współbieżne wykonanie.

Kanały

Kanały umożliwiają funkcjom komunikację między sobą. Można go traktować jako medium, w którym jedna procedura umieszcza dane i uzyskuje do niej dostęp inna procedura na serwerze Golang.

Kanał można zadeklarować za pomocą składni

channel_variable := make(chan datatype)

Przykład:

	ch := make(chan int)

Dane do kanału można wysyłać za pomocą składni

channel_variable <- variable_name

Przykład

    ch <- x

Dane z kanału można odbierać za pomocą składni

    variable_name := <- channel_variable

Przykład

   y := <- ch

W powyższych przykładach goroutine w języku Go widziałeś, że główny program nie czeka na goroutine. Ale tak nie jest, gdy w grę wchodzą kanały. Załóżmy, że jeśli goroutine przesyła dane do kanału, funkcja main() będzie czekać na instrukcję odbierającą dane kanału, aż otrzyma dane.

Zobaczysz to w poniższych przykładach języków Go. Najpierw napisz normalną goroutine i zobacz zachowanie. Następnie zmodyfikuj program, aby korzystał z kanałów i zobacz zachowanie.

Wykonaj poniższy program

package main
import "fmt"
import "time"
    
func display() {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
}

func main() {
	go display()
	fmt.Println("Inside main()")
}

Dane wyjściowe będą

Inside main()

Funkcja main() zakończyła wykonywanie i zakończyła działanie przed wykonaniem goroutine. Zatem wydruk wewnątrz display() nie został wykonany.

Teraz zmodyfikuj powyższy program, aby korzystać z kanałów i zobaczyć zachowanie.

package main
import "fmt"
import "time"
    
func display(ch chan int) {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
	ch <- 1234
}

func main() {
	ch := make(chan int) 
	go display(ch)
	x := <-ch
	fmt.Println("Inside main()")
	fmt.Println("Printing x in main() after taking from channel:",x)
}

Dane wyjściowe będą

Inside display()
Inside main()
Printing x in main() after taking from channel: 1234

Tutaj dzieje się funkcja main() po osiągnięciu x := <-ch będzie czekać na dane na kanale ch. Funkcja display() czeka 5 sekund, a następnie przesyła dane do kanału ch. Funkcja main() po odebraniu danych z kanału zostaje odblokowana i kontynuuje wykonywanie.

Nadawca przesyłający dane do kanału może poinformować odbiorców, że zamykając kanał, nie będą już dodawane żadne dane do kanału. Jest to używane głównie wtedy, gdy używasz pętli do przesyłania danych do kanału. Kanał można zamknąć za pomocą

close(channel_name)

Natomiast po stronie odbiornika można sprawdzić czy kanał jest zamknięty za pomocą dodatkowej zmiennej podczas pobierania danych z kanału za pomocą

variable_name, status := <- channel_variable

Jeśli status ma wartość True oznacza to, że otrzymałeś dane z kanału. Jeśli fałszywe, oznacza to, że próbujesz czytać z zamkniętego kanału

Możesz także używać kanałów do komunikacji pomiędzy goroutinami. Należy użyć 2 goroutines – jedna wypycha dane do kanału, a druga odbiera dane z kanału. Zobacz poniższy program

package main
import "fmt"
import "time"

//This subroutine pushes numbers 0 to 9 to the channel and closes the channel
func add_to_channel(ch chan int) {	
	fmt.Println("Send data")
	for i:=0; i<10; i++ {
		ch <- i //pushing data to channel
	}
	close(ch) //closing the channel

}

//This subroutine fetches data from the channel and prints it.
func fetch_from_channel(ch chan int) {
	fmt.Println("Read data")
	for {
		//fetch data from channel
x, flag := <- ch

		//flag is true if data is received from the channel
//flag is false when the channel is closed
if flag == true {
			fmt.Println(x)
		}else{
			fmt.Println("Empty channel")
			break	
		}	
	}
}

func main() {
	//creating a channel variable to transport integer values
	ch := make(chan int)

	//invoking the subroutines to add and fetch from the channel
	//These routines execute simultaneously
	go add_to_channel(ch)
	go fetch_from_channel(ch)

	//delay is to prevent the exiting of main() before goroutines finish
	time.Sleep(5 * time.Second)
	fmt.Println("Inside main()")
}

Tutaj są 2 podprogramy, jeden wpycha dane do kanału, a drugi drukuje dane do kanału. Funkcja add_to_channel dodaje liczby od 0 do 9 i zamyka kanał. Jednocześnie funkcja fetch_from_channel czeka na

x, flag := <- ch i gdy dane staną się dostępne, drukuje je. Wychodzi, gdy flaga jest fałszywa, co oznacza, że ​​kanał jest zamknięty.

Oczekiwanie w funkcji main() ma na celu uniemożliwienie wyjścia z funkcji main() do czasu, aż goroutines zakończą wykonywanie.

Wykonaj kod i zobacz wynik jako

Read data
Send data
0
1
2
3
4
5
6
7
8
9
Empty channel
Inside main()

Wybierz

Select można postrzegać jako instrukcję switch, która działa na kanałach. Tutaj instrukcje case będą operacją kanału. Zazwyczaj każda instrukcja case będzie próbą odczytu z kanału. Gdy którykolwiek z przypadków jest gotowy (kanał jest odczytywany), wykonywana jest instrukcja powiązana z tym przypadkiem. Jeśli wiele przypadków jest gotowych, zostanie wybrany losowy przypadek. Możesz mieć domyślny przypadek, który jest wykonywany, jeśli żaden z przypadków nie jest gotowy.

Zobaczmy poniższy kod

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)
    
    //Both case statements wait for data in the chan1 or chan2.
    //chan2 gets data first since the delay is only 2 sec in data2().
    //So the second case will execute and exits the select block
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    }
}

Wykonanie powyższego programu da wynik:

from data2()

Tutaj instrukcja select czeka, aż dane będą dostępne w którymkolwiek z kanałów. Funkcja data2() dodaje dane do kanału po 2 sekundowym uśpieniu, co spowoduje wykonanie drugiego przypadku.

Dodaj domyślny przypadek do zaznaczenia w tym samym programie i zobacz wynik. Tutaj, po osiągnięciu bloku wyboru, jeśli żaden przypadek nie ma gotowych danych na kanale, wykona domyślny blok bez czekania, aż dane będą dostępne na którymkolwiek kanale.

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values  
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)

    //Both case statements check for data in chan1 or chan2.
    //But data is not available (both routines have a delay of 2 and 4 sec)
    //So the default block will be executed without waiting for data in channels.
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    default:
    	fmt.Println("Default case executed")
    }
}

Ten program da wynik:

Default case executed			

Dzieje się tak dlatego, że po osiągnięciu bloku wyboru żaden kanał nie miał danych do odczytu. Zatem wykonywany jest przypadek domyślny.

Mutex

Mutex to skrót od mutual exclusion (wzajemnego wykluczania). Mutex jest używany, gdy nie chcesz, aby zasób był dostępny dla wielu podprogramów jednocześnie. Mutex ma 2 metody – Lock i Unlock. Mutex jest zawarty w pakiecie sync. Musisz więc zaimportować pakiet sync. Instrukcje, które muszą być wykonywane wzajemnie wykluczająco, mogą być umieszczone wewnątrz mutex.Lock() i mutex.Unlock().

Nauczmy się muteksu na przykładzie liczenia liczby wykonań pętli. W tym programie oczekujemy, że procedura wykona pętlę 10 razy, a licznik zostanie zapisany w postaci sumy. Wywołujesz tę procedurę 3 razy, więc łączna liczba powinna wynosić 30. Liczba jest przechowywana w zmiennej globalnej count.

Najpierw uruchamiasz program bez mutexu

package main
import "fmt"
import "time"
import "strconv"
import "math/rand"
//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Zobacz wynik

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

Wynik może być inny, gdy go wykonasz, ale wynik końcowy nie będzie wynosił 30.

Tutaj dzieje się tak, że 3 goroutines próbują zwiększyć liczbę pętli przechowywaną w zmiennej count. Załóżmy, że w danej chwili liczba wynosi 5, a goroutine1 zwiększy liczbę do 6. Główne kroki obejmują

Skopiuj licznik do temp

Zwiększ temp

Temp. przechowywania z powrotem do zliczenia

Załóżmy, że wkrótce po wykonaniu kroku 3 przez goroutine1; inna goroutine może mieć starą wartość, powiedzmy 3 wykonuje powyższe kroki i zapisuje 4 z powrotem, co jest błędne. Można temu zapobiec, używając muteksu, który powoduje, że inne procedury czekają, gdy jedna z nich już używa zmiennej.

Teraz uruchomisz program z mutexem. Tutaj wyżej wymienione 3 kroki są wykonywane w muteksie.

package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"

//declare a mutex instance
var mu sync.Mutex

//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		//lock starts here
		mu.Lock()
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
		//lock ends here
		mu.Unlock()
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Teraz będzie wynik

 Count after i=3 Count: 21
Count after i=2 Count: 28
Count after i=1 Count: 30
Final Count: 30

Tutaj otrzymujemy oczekiwany wynik jako wynik końcowy. Ponieważ instrukcje odczytywania, zwiększania i zapisywania liczby licznika są wykonywane w muteksie.

Obsługa błędów

Błędy to nietypowe warunki, takie jak zamknięcie nieotwartego pliku, otwarcie pliku, który nie istnieje itp. Funkcje zwykle zwracają błędy jako ostatnią zwracaną wartość.

Poniższy przykład wyjaśnia więcej na temat błędu.

package main
import "fmt"
import "os"

//function accepts a filename and tries to open it.
func fileopen(name string) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        fmt.Println(er)
        return
    }else{
    	fmt.Println("file opened", f.Name())
    }
}

func main() {  
    fileopen("invalid.txt")
}

Wyjście będzie:

open /invalid.txt: no such file or directory

Tutaj próbowaliśmy otworzyć nieistniejący plik, ale zwrócił on błąd do zmiennej er. Jeśli plik jest prawidłowy, błąd będzie miał wartość null

Niestandardowe błędy

Korzystając z tej funkcji, możesz tworzyć niestandardowe błędy. Odbywa się to za pomocą New() pakietu błędów. Przepiszemy powyższy program, aby wykorzystać niestandardowe błędy.

Uruchom poniższy program

package main
import "fmt"
import "os"
import "errors"

//function accepts a filename and tries to open it.
func fileopen(name string) (string, error) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        //created a new error object and returns it  
        return "", errors.New("Custom error message: File name is wrong")
    }else{
    	return f.Name(),nil
    }
}

func main() {  
    //receives custom error or nil after trying to open the file
    filename, error := fileopen("invalid.txt")
    if error != nil {
        fmt.Println(error)
    }else{
    	fmt.Println("file opened", filename)
    }  
}

Wyjście będzie:

Custom error message:File name is wrong

Tutaj area() zwraca pole kwadratu. Jeśli wartość wejściowa jest mniejsza niż 1, funkcja area() zwraca komunikat o błędzie.

Czytanie plików

Pliki służą do przechowywania danych. Go pozwala nam na odczytanie danych z plików

Najpierw utwórz plik data.txt w swoim obecnym katalogu z poniższą zawartością.

Line one
Line two
Line three

Teraz uruchom poniższy program, aby zobaczyć, że drukuje zawartość całego pliku jako dane wyjściowe

package main
import "fmt"
import "io/ioutil"

func main() {  
    data, err := ioutil.ReadFile("data.txt")
    if err != nil {
        fmt.Println("File reading error", err)
        return
    }
    fmt.Println("Contents of file:", string(data))
}

Tutaj dane, err := ioutil.ReadFile(“data.txt”) odczytuje dane i zwraca sekwencję bajtów. Podczas drukowania jest konwertowany do formatu ciągu znaków.

Zapisywanie plików

Zobaczysz to za pomocą programu

package main
import "fmt"
import "os"

func main() {  
    f, err := os.Create("file1.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString("Write Line one")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

Tutaj tworzony jest plik test.txt. Jeśli plik już istnieje, zawartość pliku zostanie obcięta. Funkcja Writeline() służy do zapisywania zawartości pliku. Następnie zamknąłeś plik za pomocą Close().

Ściągawka

W tym samouczku Go omówiliśmy:

Temat Opis Składnia
Typy podstawowe Numeryczne, łańcuchowe, bool
Zmienne Deklaruj i przypisuj wartości do zmiennych var nazwa_zmiennej typ
var nazwa_zmiennej typ = wartość
var nazwa_zmiennej1, nazwa_zmiennej2 = wartość1, wartość2
nazwa_zmiennej := wartość
Stałe Zmienne, których wartości nie można zmienić po przypisaniu zmienna stała = wartość
Dla pętli Wykonuj instrukcje w pętli. dla wyrażenia_inicjalizacyjnego; wyrażenie_oceny; iteracja_wyrażenie{
// jedno lub więcej instrukcji
}
Jeśli inaczej Jest to stwierdzenie warunkowe jeśli warunek{
// oświadczenia_1
Else {}
// oświadczenia_2
}
wyłącznik Instrukcja warunkowa z wieloma przypadkami wyrażenie przełączające {
wartość przypadku_1:
oświadczenia_1
wartość przypadku_2:
oświadczenia_2
wartość przypadku_n:
oświadczenia_n
domyślna:
oświadczenia_domyślne
}
Szyk Stały rozmiar nazwanej sekwencji elementów tego samego typu nazwa tablicy := [rozmiar] typ {wartość_0, wartość_1,…, wartość_rozmiar-1}
Plaster Część lub segment tablicy var nazwa_plasterku [] type = nazwa_tablicy[początek:koniec]
Funkcje Blok instrukcji realizujący określone zadanie func nazwa_funkcji(typ parametru_1, typ parametru_n) typ_zwrotu {
//sprawozdania
}
Pakiety Służą do organizowania kodu. Zwiększa czytelność kodu i możliwość jego ponownego użycia importuj nazwę_pakietu
Odraczać Opóźnia wykonanie funkcji do momentu zakończenia wykonywania funkcji zawierającej odroczenie nazwa_funkcji(lista_parametrów)
wskaźniki Przechowuje adres pamięci innej zmiennej. var nazwa_zmiennej *typ
Structure Typ danych zdefiniowany przez użytkownika, który sam zawiera jeszcze jeden element tego samego lub innego typu wpisz nazwa struktury struktura {
zmienna_1 zmienna_1_typ
zmienna_2 zmienna_2_typ
zmienna_n zmienna_n_typ
}
Metody Metoda to funkcja posiadająca argument odbiorcy func (typ zmiennej) nazwa_metody(lista_parametrów) {
}
Gorutyna Funkcja, która może działać jednocześnie z innymi funkcjami. przejdź nazwa_funkcji (lista_parametrów)
Kanał Sposób komunikowania się funkcji między sobą. Medium, w którym jedna procedura umieszcza dane i do którego uzyskuje dostęp inna procedura. Ogłosić:
ch := make(chan int)
Wyślij dane do kanału:
zmienna_kanału <- nazwa_zmiennej
Odbierz z kanału:
nazwa_zmiennej := <- zmienna_kanału
Wybierz Instrukcja Switch, która działa na kanałach. Instrukcje case będą operacją kanału. Gdy którykolwiek kanał jest gotowy z danymi, wykonywana jest instrukcja powiązana z tym case wybierać {
przypadek x := <-chan1:
fmt.Drukuj(x)
przypadek y := <-chan2:
fmt.Println(y)
}
Mutex Mutex jest używany, gdy nie chcesz, aby wiele podprogramów miało dostęp do zasobu jednocześnie. Mutex ma 2 metody – Zablokuj i Odblokuj mutex.Lock()
//sprawozdania
mutex.Odblokuj().
Czytaj pliki Odczytuje dane i zwraca sekwencję bajtów. Dane, błąd:= ioutil.ReadFile(nazwa pliku)
Zapisz plik Zapisuje dane do pliku l, błąd := f.WriteString(text_to_write)