Pierwsze kroki z Go
Go to język programowania ogólnego przeznaczenia stworzony z myślą o programowaniu systemów. Został wynaleziony w 2007 roku przez Roberta Griesemera z Google, Roba Pike′a i Kena Thompsona. Jest silnie i statycznie typowany, ma wbudowaną obsługę wyrzucania elementów bezużytecznych i obsługuje programowanie współbieżne. Pakiety są używane do konstruowania programów do efektywnego zarządzania zależnościami. Implementacje programistyczne Go wykorzystują tradycyjny model kompilacji i łączenia do generowania wykonywalnych plików binarnych. Język programowania Go został wprowadzony w listopadzie 2009 roku i jest obecnie używany w niektórych systemach produkcyjnych Google.
PROGRAMOWANIE FUNKCJI
o Projektowanie języka: projektanci języka podjęli świadomą decyzję, aby język był prosty i łatwy do zrozumienia. Wszystkie szczegóły zawarte są na kilku stronach, a kilka interesujących decyzji projektowych zostało podjętych przy użyciu obiektowego wsparcia języka. Język jest uparty, zalecając konwersacyjną metodę osiągania rzeczy. Kompozycja jest preferowana nad dziedziczeniem. Mantra w Go Language brzmi "Zrób więcej za mniej".
o Zarządzanie pakietami: Go zawiera nowoczesne przepływy pracy programistów do pracy z projektami Open Source do zarządzania zewnętrznymi pakietami. Wsparcie dla pobierania pakietów zewnętrznych i publikowania naszych pakietów jest zapewniane bezpośrednio w narzędziu za pomocą zestawu prostych poleceń.
o Potężna biblioteka standardowa: Go ma solidną bibliotekę standardową, dystrybuowaną w formie pakietów.
o Typowanie statyczne: Go to język z typowaniem statycznym. W rezultacie ten kompilator nie tylko pomyślnie kompiluje kod, ale także zapewnia konwersje typów i kompatybilność. Dzięki tej funkcji Go pozwala uniknąć wszystkich problemów, które obserwujemy w językach o dynamicznym typowaniu.
o Obsługa testów: Go zawiera domyślnie funkcje testów jednostkowych, takie jak prosty mechanizm pisania testów jednostkowych równolegle z naszym kodem, co pozwala nam zrozumieć pokrycie kodu przez nasze testy. Na przykład możemy łatwo użyć tego do wygenerowania dokumentacji kodu.
o Niezależność platformy: podobnie jak język Java, język Go obsługuje niezależność platformy. Ze względu na swoją modułową konstrukcję i modułowość kod jest kompilowany i konwertowany do postaci binarnej, która jest tak mała, jak to tylko możliwe i nie wymaga zależności. Jego kod można skompilować na dowolnej platformie, serwerze lub aplikacji, na której pracujemy.
DLACZEGO GoLang JEST LEPSZY OD INNYCH JĘZYKÓW PROGRAMOWANIA?
W świecie języków programowania nie ma wytchnienia dla innowacji i przełomów. Deweloperzy nieustannie poszukują prostszego, wyrafinowanego i przyjaznego projektom języka. GoLang pojawił się jako niesamowity nowy język programowania z mnóstwem rozwiązań. GoLang od samego początku zaskoczył świat programowania. Tutaj ujawnionych zostanie wiele niespodzianek, które wyróżniają ten język spośród innych. Zacznijmy od przeglądu podstawowych funkcji w skrócie.
Podstawowe możliwości GoLang
Podobno programiści Google wymyślili GoLang, czekając na projekt kompilacji kodu. Właśnie dlatego GoLang jest jedynym językiem, który łączy w sobie wszystkie trzy pożądane cechy, a mianowicie łatwość kodowania, wydajną kompilację kodu i wydajne wykonanie. Fakt, że można połączyć wszystkie te możliwości w jednym języku, odróżnia GoLang od innych języków programowania. Go, znany również jako GoLang, to solidny język systemowy używany do programowania w dużych serwerach sieciowych i dużych systemach rozproszonych. Mówiąc prościej, w kontekście tego, czego Google wymagał od swoich serwerów sieciowych i systemów rozproszonych, GoLang pojawił się jako alternatywa dla C++ i Javy dla twórców aplikacji. Język został zaprojektowany w celu wyeliminowania powolności i trudności związanych z programowaniem dużych i skalowalnych serwerów i systemów oprogramowania. Mówiąc dokładniej, Go przybył do Google, aby zapewnić następujące rozwiązania:
o Kompilacja i wykonanie w mgnieniu oka.
o Wyeliminowanie konieczności pracy z różnymi podzbiorami języków dla jednego projektu.
o Poprawiona czytelność kodu i dokumentacji.
o Zapewnienie całkowicie spójnego języka.
o Umożliwienie prostego wersjonowania programów.
o Możliwość rozwoju w wielu językach.
o Ułatwienie zarządzania zależnościami.
Wielowątkowość i współbieżność
Ponieważ sprzęt staje się z czasem coraz bardziej wyrafinowany, producenci dodają do systemu rdzenie, aby poprawić wydajność. W przypadku ogromnej liczby rdzeni system musi utrzymywać połączenia z bazą danych za pośrednictwem mikroserwisów, zarządzać kolejkami i utrzymywać pamięci podręczne. Właśnie dlatego dzisiejszy sprzęt wymaga języka programowania, który może lepiej obsługiwać współbieżność i zwiększać wydajność w miarę wzrostu liczby rdzeni w miarę upływu czasu. Podczas pracy z wieloma wątkami, większość języków programowania ma brak równoczesnego wykonywania, co często spowalnia tempo programowania, kompilacji i wykonywania. W tym miejscu Go wyłania się jako najbardziej realna opcja do obsługi zarówno wielowątkowości, jak i współbieżności. Kiedy wielordzeniowe procesory były powszechnie dostępne na zaawansowanym sprzęcie, powstał Go jako język programowania. Oczywiście twórcy Go postawili na współbieżność. Go używa goroutines zamiast wątków, co pozwala na jednoczesną obsługę wielu zadań.
Go wzmacnia sprzęt od wewnątrz
Ponieważ procesory sprzętowe rozumieją tylko pliki binarne, każda aplikacja napisana w języku Java lub JVM jest interpretowana jako pliki binarne. Taka interpretacja na poziomie sprzętowym wydłuża czas wykonania. Właśnie dlatego języki kompilowane, takie jak C/C++, które eliminują etap zrozumienia, mogą poprawić wydajność i szybkość wykonywania. Jednak wyodrębnianie i przydzielanie zmiennych w C/C++ wiąże się ze znaczną ilością komplikacji i czasu. W tym miejscu Go błyszczy jako idealne rozwiązanie, łącząc najlepsze z obu światów. Go, podobnie jak C/C++, jest językiem kompilowanym, co sprawia, że jest równie szybki jak oni. Z drugiej strony wykorzystuje wyrzucanie elementów bezużytecznych i usuwanie obiektów, podobnie jak Java, do alokacji zmiennych. W rezultacie Go jest idealnym językiem do pracy w dowolnym systemie sprzętowym.
Niezrównana prostota Go
Jedną z głównych zalet przyjęcia Go jest jego prostota. Pomimo tego, że jest to bardzo wyrafinowany język z bogatym zestawem funkcji, Go wyróżnia się na tle innych ze względu na swoją prostotę i bezpośrednie podejście.
o Brak generyków: Generyki lub szablony, które od dawna stanowią podstawę różnych języków programowania, często zwiększają niejasność i trudności w zrozumieniu. Decydując się na rezygnację z tego, projektanci uprościli sprawę.
o Pojedynczy plik wykonywalny: GoLang nie zawiera biblioteki uruchomieniowej. Może wygenerować pojedynczy plik wykonywalny, który można wdrożyć po prostu kopiując. Zmniejsza to wszelkie obawy dotyczące popełniania błędów z powodu zależności lub niezgodności wersji.
o Brak bibliotek dynamicznych: Go zdecydowało się zrezygnować z bibliotek dynamicznych, aby zachować prostotę języka. Jednak w najnowszej wersji Go 1.10 programiści mogą przesyłać biblioteki dynamiczne za pośrednictwem pakietów wtyczek. Zostało to uwzględnione tylko jako dodatkowa funkcja.
Wbudowana struktura testowania i profilowania
Podczas tworzenia aplikacji JavaScript wielu z nas napotkało złożoność wyboru środowiska testowego poprzez serię analiz. Fakt, że przez większość czasu nie używamy więcej niż 20% wybranego frameworka, jest prawdą. Ten sam problem pojawia się, gdy do oceny wymagane jest dobre profilowanie. Go zawiera wbudowane narzędzie do testowania i profilowania, które pomaga nam szybko i łatwo przetestować aplikację. Oprócz dostarczania gotowych do wykonania przykładów kodu, narzędzie może być wykorzystywane do wszelkiego rodzaju potrzeb związanych z testowaniem i profilowaniem.
Łatwa krzywa uczenia się
Jedną z ważnych zalet Go jest niska krzywa uczenia się. Nie powinniśmy się dziwić, jeśli powiemy, że wszystkich funkcji GoLanga można się nauczyć w zaledwie kilka godzin. Kiedy opanujemy te podstawy, będziemy musieli zrozumieć najlepsze praktyki programistyczne dla określonych potrzeb, a także standardową bibliotekę. Jednak do nauki języka wystarczy dwu- lub trzygodzinna sesja.
POCZĄTEK OD GO
Kilka internetowych IDE, takich jak The Go Playground, repl.it i inne, może uruchamiać programy Go bez instalowania czegokolwiek. Aby zainstalować Go na naszych komputerach stacjonarnych lub laptopach, będziemy potrzebować dwóch programów: edytora tekstu i kompilatora.
Edytor tekstu
Edytor tekstu zapewnia nam platformę do pisania naszego kodu źródłowego. Poniżej znajduje się lista edytorów tekstu:
o Notatnik Windows
o Brief
o Polecenie edycji systemu operacyjnego
o Epsilon
o Kod VS
o vm lub vi
o Emacsa
Znalezienie kompilatora Go
Dystrybucja Go jest dostępna jako plik instalacyjny binarny dla systemów operacyjnych FreeBSD, Mac OS X, Linux i Windows z 32-bitowymi (386) i 64-bitowymi (amd64) architekturami procesorów x86.
ZAINSTALUJ Idź NA WINDOWS
Zanim zaczniemy, musimy najpierw zainstalować GoLang w naszym systemie. Potrzebujemy wiedzy z pierwszej ręki, czym jest język Go i do czego służy. Go to statycznie typowany język programowania typu open source, stworzony w 2007 roku przez Roberta Griesemera, Roba Pike'a i Kena Thompsona z Google, ale wydany w 2009 roku. Nosi również nazwę GoLang i obsługuje proceduralny język programowania. Początkowo został zaprojektowany w celu zwiększenia produktywności programowania na dużych bazach kodu, maszynach wielordzeniowych i sieciowych. Programy GoLang są łatwe do napisania. Można je napisać w dowolnym edytorze zwykłego tekstu, takim jak notatnik, notatnik ++ lub coś podobnego. Można również użyć internetowego IDE do napisania kodu GoLang lub zainstalować go w swoim systemie, aby ułatwić pisanie i pracę nad tymi kodami. Najlepsze jest to, że IDE ułatwia pisanie kodu GoLang, ponieważ IDE zawiera wiele funkcji, takich jak intuicyjny edytor kodu, debugger, kompilator itp. Po pierwsze, trzeba mieć zainstalowany język Go w swoim systemie, aby pisać kody GoLang i wykonywać różne intrygujące i wartościowe operacje.
Jak określamy wersję językową Go. To jest preinstalowane?
Zanim przystąpimy do instalacji Go, dobrze jest sprawdzić, czy nie jest ono już zainstalowane w naszym systemie. Aby sprawdzić, czy nasze urządzenie ma preinstalowany GoLang, przejdź do wiersza poleceń (dla Windows), wyszukaj cmd w oknie dialogowym Uruchom (+ R). Wykonaj następujące polecenie:
go version
Jeśli GoLang jest już zainstalowany na twoim komputerze, wygeneruje wiadomość zawierającą wszystkie szczegóły wersji GoLang; w przeciwnym razie, jeśli GoLang nie jest zainstalowany na komputerze, pojawi się komunikat o błędzie "Złe polecenie lub nazwa pliku".
Pobieranie i instalowanie Go
Zanim rozpoczniemy procedurę instalacji, musimy ją najpierw pobrać. Wszystkie wersje dla systemu Windows są dostępne do pobrania pod adresem https://go.dev/dl/.
Pobierz GoLang dla naszej architektury systemu, a następnie postępuj zgodnie z instrukcjami
Instrukcje instalacji GoLanga.
o Krok 1: Rozpakuj pobrany plik archiwum po jego pobraniu. Po rozpakowaniu znajdziemy folder go w naszym bieżącym katalogu.
o Krok 2: Skopiuj i wklej wyodrębniony folder, gdziekolwiek go umieścimy. W tym przypadku instalujemy go na dysku C.
o Krok 3: Teraz skonfiguruj zmienne środowiskowe. Kliknij prawym przyciskiem myszy Mój komputer i wybierz Właściwości. Wybierz Zaawansowane ustawienia systemu z lewego menu, a następnie Zmienne środowiskowe.
o Krok 4: Ze zmiennych systemowych wybierz Ścieżka, a następnie Edytuj. Następnie wybierz Nowy i wprowadź ścieżkę z katalogiem bin, do którego wkleiliśmy folder Go. Tutaj zmienimy ścieżkę C: gobiC: \ go \ bin i kliknij OK.
o Krok 5: Utwórz nową zmienną użytkownika, która powie poleceniu Go, gdzie znajdują się biblioteki GoLang. Aby to zrobić, przejdź do Zmiennych użytkownika i wybierz Nowy.
Teraz wprowadź GOROOT jako nazwę zmiennej i ścieżkę do naszego folderu GoLang jako wartość zmiennej. Tak więc w tym przypadku wartość zmiennej to C:\go\. Po zakończeniu wypełniania formularza kliknij OK.
Następnie w Zmiennych środowiskowych kliknij OK, a nasza konfiguracja jest zakończona. Teraz sprawdź wersję GoLang, wpisując wersję go w wierszu poleceń. Po zakończeniu procesu instalacji dowolny edytor tekstu lub IDE może użyć do napisania kodów GoLang, które następnie można uruchomić w IDE lub w wierszu polecenia za pomocą polecenia:
go run filename.go
PISANIE PIERWSZEGO PROGRAMU Go
package main
import "fmt"
func main() {
// print
fmt.Println("Hello, everyone")
}
Wyjaśnienie składni programu Go:
o Linia 1: zawiera główny pakiet programu, w tym jego całość treści. Jest to punkt wyjścia dla programu, więc musi być napisany.
o Linia 2: zawiera import "fmt", polecenie preprocesora, które instruuje kompilator, aby umieścił pliki w pakiecie.
o Linia 3: główna funkcja; to jest początek wykonywania programu.
o Linia 4: fmt.
o Println(): jest standardową funkcją biblioteczną służącą do drukowania czegoś na ekranie.
o Pakiet fmt: przesłał metodę Println, która w tym przypadku wyświetla wynik.
o Komentarze: służą do wyjaśniania kodu w taki sam sposób, jak w Javie, C lub C++. Wpisy komentarzy są ignorowane przez kompilatory i nie są wykonywane. Komentarze mogą mieć długość jednej lub wielu linii.
Komentarz jednowierszowy
Składnia:
// komentarz jednowierszowy
Komentarz wielowierszowy
Składnia:
/* komentarz wielowierszowy */
Przykład:
package main
import "fmt"
func main() {
fmt.Println("2 + 2 =", 2 + 2)
}
Wyjaśnienie poprzedniego programu
Poprzedni program używa tej samej linii pakietu, linii importu, deklaracji funkcji i funkcji Println, co pierwszy program Go. Zamiast wypisywać łańcuch "Cześć wszystkim", wypisujemy 2 + 2 =, po którym następuje wynik wyrażenia 2 + 2. To wyrażenie składa się z trzech części: literału liczbowego int 2, operatora + (reprezentującego dodawanie) i inny literał liczbowy typu int 2.
Dlaczego istnieje "język Go"?
Go jest próbą połączenia łatwości programowania języka interpretowanego i bezpieczeństwa języka statycznego i dynamicznego z wydajnością języka kompilowanego. Aspiruje również do tego, aby być najnowocześniejszym, z obsługą sieci i obliczeń wielordzeniowych.
Czego brakuje w Go, a jest w innych językach?
o Go stara się ograniczyć pisanie w obu znaczeniach tego słowa. Deweloperzy ciężko pracowali, aby ograniczyć bałagan i złożoność do minimum w całym procesie projektowania.
o Nie ma deklaracji przekazywania ani plików nagłówkowych; wszystko jest deklarowane tylko raz.
o Proste wyprowadzenie typu przy użyciu konstrukcji := zadeklaruj i zainicjuj zmniejsza zacinanie.reduces stuttering.
o Nie ma hierarchii typów: typy po prostu istnieją; nie są zobowiązani do ogłaszania swoich związków.
Ograniczenia sprzętowe
Zaobserwowaliśmy, że konfiguracja sprzętu i przetwarzania zmienia się w dłuższym tempie na przestrzeni dekady. W 2004 roku P4 miał taktowanie 3,0 GHz. W 2018 roku Macbook Pro miał taktowanie około (2,3 GHz vs. 2,66 GHz). Używamy większej liczby procesorów, aby przyspieszyć działanie, ale koszt korzystania z większej liczby procesorów również rośnie. W rezultacie używamy ograniczonych procesorów, a przy niewielkiej liczbie procesorów mamy ciężki język programowania, którego wątkowanie zużywa więcej pamięci i spowalnia wydajność naszego systemu. Aby rozwiązać ten problem, GoLang został zaprojektowany w taki sposób, że zamiast wątkowania używa gorutyny, która jest podobna do wątkowania, ale zużywa znacznie mniej pamięci. Ponieważ wątki zużywają 1 MB pamięci, a goroutines 2 KB, łatwo jest uruchomić miliony goroutines jednocześnie. W wyniku powyższych punktów GoLang jest potężnym językiem, który obsługuje współbieżność w taki sam sposób, jak robią to C++ i Java.
Zalety i wady języka Go
Korzyści:
o Elastyczny: jest elastyczny, ponieważ jest zwięzły, prosty i łatwy do odczytania.
o Współbieżność: umożliwia jednoczesne uruchamianie wielu procesów i efektywnie.
o Szybka kompilacja: Czas kompilacji jest bardzo krótki.
o Biblioteka: zawiera obszerną bibliotekę standardową.
o Wyrzucanie śmieci to podstawowa funkcja go. Go wyróżnia się zapewnianiem wysokiego poziomu kontroli nad alokacją pamięci, a opóźnienie modułu wyrzucania elementów bezużytecznych zostało radykalnie zmniejszone w ostatnich wersjach.
o Sprawdza osadzanie interfejsu i typu.
Wady:
o Mimo wielu dyskusji na ten temat, nie obsługuje leków generycznych.
o Chociaż pakiety dołączone do tego języka programowania są bardzo pomocne, Go nie jest obiektowym językiem programowania w tradycyjnym tego słowa znaczeniu.
o Brakuje niektórych bibliotek, zwłaszcza zestawu narzędzi interfejsu użytkownika.
Niektóre popularne aplikacje języka Go obejmują:
o Docker: Jest to zestaw narzędzi do zarządzania i wdrażania kontenerów Linuksa.
o Red Hat: jest Openshift i jest platformą przetwarzania w chmurze jako usługą.
o Kubernetes: Przyszłość płynnie zautomatyzowanego wdrażania.
o Dropbox: przeniósł niektóre ze swoich krytycznych komponentów z Pythona do Go.
o Netflix: Dla dwóch różnych aspektów ich architektury serwerowej.
o InfluxDB: Jest to baza danych szeregów czasowych, która jest open source i została opracowana przez InfluxData.
o GoLang: język został stworzony w Go.
TERMINAL
GoLand posiada zintegrowany emulator terminala, który pozwala nam na interakcję z naszą powłoką wiersza poleceń z poziomu IDE. Może uruchamiać polecenia Git, modyfikować uprawnienia do plików i wykonywać inne funkcje wiersza poleceń bez przełączania się do specjalistycznego programu terminala. Emulator terminala zaczyna się od naszej normalnej powłoki systemowej, ale obsługuje wiele alternatywnych powłok, w tym Windows PowerShell, Command Prompt cmd.exe, sh, bash, zsh, csh i inne. Zobacz Konfigurowanie emulatora terminala, aby uzyskać więcej informacji na temat zmiany powłoki.
Otwórz okno narzędzia Terminal
Wybierz Widok | Okna narzędziowe | Terminal z menu głównego lub naciśnij Alt+F12. Domyślnie emulator terminala działa z bieżącym katalogiem ustawionym na katalog główny bieżącego projektu. Alternatywnie możemy kliknąć prawym przyciskiem myszy dowolny plik (na przykład w oknie narzędzia Projekt lub dowolnej otwartej karcie) i wybrać Otwórz w terminalu z menu kontekstowego, aby uruchomić okno narzędzia Terminal z nową sesją w katalogu pliku.
Rozpocznij nową sesję
Kliknij przycisk Dodaj, aby utworzyć nową sesję w nowej zakładce na pasku narzędzi. Aby uruchomić kilka sesji na karcie, kliknij ją prawym przyciskiem myszy i wybierz z menu kontekstowego opcję Podziel w prawo lub Podziel w dół. Kiedy zamykamy projekt lub GoLand, Terminal zapamiętuje zakładki i sesje. Nazwy kart, historia powłoki i bieżący katalog roboczy są zapisywane. Użyj przycisku Zamknij na pasku narzędzi Terminala lub kliknij kartę prawym przyciskiem myszy i wybierz opcję Zamknij kartę z menu kontekstowego, aby zamknąć kartę. Aby przechodzić między aktywnymi kartami, naciśnij klawisze Alt+w prawo i Alt+w lewo. Możemy również nacisnąć Alt + Down, aby uzyskać listę wszystkich kart terminala. Kliknij kartę prawym przyciskiem myszy i wybierz opcję Zmień nazwę sesji z menu kontekstowego, aby zmienić jej nazwę. Ctrl + F wyszuka określony ciąg w sesji terminala. Spowoduje to przeszukanie całego tekstu sesji, w tym monitu, poleceń i danych wyjściowych. Skonfiguruj emulator terminala w następujący sposób:
Aby otworzyć ustawienia środowiska IDE, naciśnij klawisze Ctrl+Alt+S, a następnie wybierz pozycję Narzędzia | Terminal.
ZAINSTALUJ G NA MAC
Zanim zaczniemy, musimy najpierw zainstalować GoLang w naszym systemie. Potrzebujemy wiedzy z pierwszej ręki, czym jest język Go i do czego służy. Go to statycznie typowany język programowania typu open source, stworzony w 2007 roku przez Roberta Griesemera, Roba Pike'a i Kena Thompsona z Google, ale wydany w 2009 roku. Nosi również nazwę GoLang i obsługuje proceduralny język programowania. Pierwotnie został zaprojektowany w celu zwiększenia produktywności programowania na dużych bazach kodu, maszynach wielordzeniowych i sieciowych. Programy GoLang można tworzyć w dowolnym edytorze zwykłego tekstu, takim jak TextEdit, Sublime Text lub podobnym. Można również użyć internetowego IDE do napisania kodu GoLang lub zainstalować go w swoim systemie, aby ułatwić pisanie i pracę nad tymi kodami. Dla wygody użycie IDE ułatwia pisanie kodu GoLang, ponieważ IDE zawiera wiele funkcji, takich jak intuicyjny edytor kodu, debugger, kompilator itp. Poniżej przedstawiono kroki instalacji GoLang na MacOS:
o Krok 1: Określ, czy aplikacja Go jest zainstalowana. Zanim zaczniemy instalować Go, dobrze jest sprawdzić, czy nie jest już zainstalowane w naszym systemie. Aby sprawdzić, czy nasze urządzenie ma preinstalowany GoLang, otwórz Terminal i wpisz następujące polecenie:
go version
Jeśli GoLang jest już zainstalowany na twoim komputerze, wygeneruje wiadomość ze wszystkimi dostępnymi szczegółami wersji GoLang; w przeciwnym razie wyświetli błąd.
o Krok 2: Zanim rozpoczniemy proces instalacji, musimy go najpierw pobrać. W rezultacie wszystkie wersje Go dla MacOS są dostępne do pobrania pod adresem https://go.dev/dl/. Pobierz GoLang w oparciu o naszą architekturę systemu. Dla systemu pobraliśmy go1.13.1drawin-amd64.pkg.
o Krok 3: Po pobraniu pakietu zainstaluj go w naszym systemie.
o Krok 4: Po zakończeniu procesów instalacyjnych. Otwórz Terminal (interfejs wiersza poleceń dla systemu MacOS) i użyj polecenia wersji GoLang, aby sprawdzić, czy Go jest poprawnie zainstalowany. Wyświetla informacje o wersji GoLang, wskazując, że Go został pomyślnie zainstalowany w naszym systemie.
Po pomyślnym zainstalowaniu Go w naszym systemie skonfigurujemy teraz obszar roboczy Go. Obszar roboczy Go to folder na naszym komputerze, w którym będzie przechowywany cały nasz kod Go.
o Krok 1: Utwórz folder o nazwie Go w naszych dokumentach (lub gdziekolwiek chcemy w naszym systemie).
o Krok 2: Powiedz narzędziom Go, gdzie mają szukać tego folderu. Aby rozpocząć, użyj następującego polecenia, aby przejść do naszego katalogu domowego:
cd ~
Następnie użyj następującego polecenia, aby ustawić ścieżkę do folderu:
echo "export GOPATH=/Users/anki/Documents/go" >> .bash_profile
W tym przypadku dodajemy export OPATH=/Users/anki/Documents/go do .bash_profile. Plik profilu .bash jest ładowany automatycznie, gdy logujemy się na nasze konto Mac i zawiera wszystkie konfiguracje i preferencje uruchamiania interfejsu wiersza poleceń (CLI).
o Krok 3: Uruchom następujące polecenie, aby upewnić się, że nasz plik .bash_profile zawiera następującą ścieżkę:
cat. bash_profile
o Krok 4: Teraz użyjemy następującego polecenia, aby zweryfikować naszą ścieżkę go. Możemy również pominąć ten krok, jeśli wolimy.
echo $GOPATH
Tworzenie naszego pierwszego programu
o Krok 1: Pobierz, a następnie zainstaluj wybrany edytor tekstu. Utwórz folder w Dokumentach o nazwie Go (lub dowolną nazwę) po instalacji (lub gdziekolwiek chcemy w naszym systemie). Utwórz inny folder o nazwie źródło w tym folderze i inny folder o nazwie powitanie w tym folderze źródłowym. Wszystkie nasze programy w Go będą zapisywane w tym folderze.
o Krok 2: Napiszmy nasz pierwszy program w Go. Otwórz edytor tekstu i wpisz program Go.
o Krok 3: Po utworzeniu programu Go zapisz go z rozszerzeniem .go.
o Krok 4: Uruchom terminal, aby wykonać swój pierwszy program Go.
o Krok 5: Zmień lokalizację plików naszego programu.
o Krok 6: Po zmianie katalogów użyj następującego polecenia, aby uruchomić program Go:
go run name_of_the_program.go
Wykonaj program Go
Przyjrzyjmy się, jak zapisać kod źródłowy w pliku, skompilować go, a następnie uruchomić program. Postępuj zgodnie z poniższymi instrukcjami:
o Otwórz edytor tekstu i wklej do niego powyższy kod.
o Zapisz plik pod nazwą helloo.go
o Otwórz wiersz polecenia.
o Przejdź do lokalizacji zapisanego pliku.
o Wpisz go run hello.
o Aby uruchomić nasz kod, śmiało naciśnij enter.
o Jeśli twój kod jest wolny od błędów, na ekranie zobaczymy napis "Cześć wszystkim".
$ go run helloo.go
Witam wszystkich
Upewnij się, że kompilator Go znajduje się na naszej ścieżce i że działa w katalogu zawierającym plik źródłowy helloo.go. Czy programy w Go łączą się z językiem programowania C/C++? Rzeczywiście możliwe jest użycie C i Go w tej samej przestrzeni adresowej, ale nie jest to naturalne dopasowanie i może wymagać użycia specjalnego oprogramowania interfejsu. Ponadto łączenie kodu C z kodem Go poświęca bezpieczeństwo pamięci Go i właściwości zarządzania stosem. Czasami użycie bibliotek C do rozwiązania problemu jest konieczne, ale robienie tego zawsze wprowadza element ryzyka, którego nie ma w czystym kodzie Go, więc postępuj ostrożnie. Jeśli musimy używać C z Go, sposób postępowania zależy od implementacji kompilatora Go. Zespół Go zapewnia wsparcie dla trzech implementacji kompilatora Go. Domyślnym kompilatorem jest GC, a następnie gccgo, który korzysta z zaplecza GCC, oraz nieco mniej dojrzały gollvm, który wykorzystuje infrastrukturę LLVM. Ponieważ gc ma inną konwencję wywoływania i linker niż C, nie można go wywołać bezpośrednio z programów C i odwrotnie. Program cgo implementuje "interfejs funkcji obcych", który umożliwia kodowi Go bezpieczne wywoływanie bibliotek C. Ta możliwość została rozszerzona na biblioteki C++ przez firmę SWIG. Gccgo i gollvm mogą być również używane z cgo i SWIG. Ponieważ używają tradycyjnego interfejsu API, możliwe jest łączenie kodu z tych kompilatorów bezpośrednio z programami C lub C++ skompilowanymi przez GCC/LLVM z zachowaniem ostrożności. Jednak wykonanie tego w bezpieczny sposób wymaga znajomości konwencji wywoływania we wszystkich językach i rozważenia ograniczeń stosu podczas wywoływania C lub C++ z Go.
JAK W GoLang TWORZYMY PUSTY PLIK?
Go Language, podobnie jak inne języki komputerowe, pozwala nam konstruować pliki. Oferuje funkcję Create() do tworzenia pliku, która służy do tworzenia lub obcinania podanego nazwanego pliku. Jeśli określony plik już istnieje, ta metoda go obetnie. Jeśli określony plik nie istnieje, ta metoda utworzy go w trybie 0666. Ta procedura zwróci wyjątek *PathError, jeśli określona ścieżka jest niepoprawna. Ta funkcja zwraca deskryptor pliku, który może być odczytywany i zapisywany. Ponieważ jest to określone w pakiecie os, musimy zaimportować pakiet os do naszego programu, aby użyć metody Create().
Składnia:
func Create(file-name string) (*File, error)
Pierwszy przykład:
package main
import (
"log"
"os"
)
func main() {
// empty file Creation
// Create() function Using
myfile, es := os.Create("helloo.txt")
if es != nil {
log.Fatal(es)
}
log.Println(myfile)
myfile.Close()
}
Drugi przykład:
package main
import (
"log"
"os"
)
func main() {
// empty file Creation
// Create() function Using
myfile, es := os.Create("/Users/anki/
Documents/new_folder/helloo.txt")
if es != nil {
log.Fatal(es)
}
log.Println(myfile)
myfile.Close()
}
W GoLang możemy sprawdzić, czy dany plik istnieje, czy nie. Funkcja IsNotExist() w języku programowania Go pozwala nam określić, czy dany plik istnieje, czy nie. Jeśli powyższa funkcja zwróci wartość true, wówczas znany jest błąd informujący, że określony plik lub katalog już nie istnieje, a jeśli zwróci wartość false, oznacza to, że podany plik lub katalog istnieje. ErrNotExist i kilka błędów wywołań systemowych również spełnia wymagania tej procedury. Ponieważ jest to określone w pakiecie os, musimy zaimportować pakiet os do naszego programu, aby użyć metody IsNotExist() .
Składnia:
func IsNotExist(es error) bool
Pierwszy przykład:
package main
import (
"log"
"os"
)
var (
myfile *os.FileInfo
es error
)
func main() {
// Stat() function returns the file info and
//if there is no file, then it will return
error
myfile, es := os.Stat("helloo.txt")
if es != nil {
// Checking if given file exists or not
// Using the IsNotExist() function
if os.IsNotExist(es) {
log.Fatal("File not Found")
}
}
log.Println("File Exist")
log.Println("File Detail is:")
log.Println("Name is: ", myfile.Name())
log.Println("Size is: ", myfile.Size())
}
Drugi przykład:
package main
import (
"log"
"os"
)
var (
myfile *os.FileInfo
es error
)
func main() {
// Stat() function returns the file info and
// if there is no file, then it will return
error
myfile, es := os.Stat("/Users/anki/Documents/
new_folder/myfolder/helloo.txt")
if es != nil {
// Checking if given file exists or not
// Using IsNotExist() function
if os.IsNotExist(es) {
log.Fatal("File not Found")
}
}
log.Println("File Exist")
log.Println("File Detail is:")
log.Println("Name is: ", myfile.Name())
log.Println("Size is: ", myfile.Size())
}
UTWÓRZ KATALOG W Go
W Go użyj metody os.Mkdir(), aby utworzyć pojedynczy katalog. Użyj os.MkdirAll() do ustanowienia hierarchii folderów (katalogi zagnieżdżone). Obie metody wymagają ścieżki i bitów uprawnień do folderu jako parametrów.
Utwórz pojedynczy katalog
package main
import (
"log"
"os"
)
func main() {
if er := os.Mkdir("a", os.ModePerm); er != nil {
log.Fatal(er)
}
}
Make a Directory Hierarchy (Nested Directories)
package main
import (
"log"
"os"
)
func main() {
if er := os.MkdirAll("a/b/c/d", os.ModePerm); er
!= nil {
log.Fatal(er)
}
}
Funkcja os.Mkdir() generuje nowy katalog o podanej wartości name, ale nie pozwala na tworzenie podkatalogów. W tym rozdziale omówiliśmy wprowadzenie Go z jego funkcjami, zaletami i wadami. Omówiliśmy również instalację Go w systemach Windows i Mac. Ponadto omówiliśmy pliki i foldery, terminal i edytory tekstu
Narzędzia GoLang
JAK CZYTAĆ I PISAĆ PROGRAMY W Go
GoLang zawiera obszerną wbudowaną bibliotekę, której można używać do przeprowadzania operacji odczytu i zapisu plików. Moduł io/ioutil polega na czytaniu z plików w systemie lokalnym. Można użyć modułu io/ioutil do zapisania danych do pliku. Moduł fmt obsługuje sformatowane wejścia/wyjścia, udostępniając metody odczytu danych wejściowych ze standardowego wejścia i drukowania danych wyjściowych na standardowe wyjście. Moduł log to podstawowy pakiet rejestrowania, który jest zaimplementowany. Wprowadza typ Logger z metodami formatowania danych wyjściowych. Moduł os pozwala nam korzystać z natywnych funkcji systemu operacyjnego. Buforowane wejścia/wyjścia są realizowane przez moduł bufio, co pomaga zwiększyć szybkość procesora.
o os.Create(): Ta funkcja tworzy plik o określonej nazwie. Jeśli istnieje już inny plik o tej samej nazwie, metoda create go obcina.
o ioutil.ReadFile(): Jedynym parametrem funkcji ioutil.ReadFile() jest ścieżka do pliku, który ma zostać odczytany. Ta procedura zwraca zawartość pliku lub błąd.
o ioutil.WriteFile(): Zwraca ioutil. WriteFile() to funkcja służąca do zapisywania danych do pliku. Funkcja WriteFile() przyjmuje trzy parametry: lokalizację pliku, do którego chcemy pisać, obiekt danych oraz FileMode, który zawiera tryb i uprawnienia pliku bits.log.
o Fatalf: Fatalf zakończy działanie aplikacji po wydrukowaniu komunikatu dziennika. Jest to podobne do wykonywania funkcji Printf(), a następnie os.Exit (1).
o log.Panicf: Panika jest podobna do wyjątku, który może wystąpić w czasie wykonywania. Panicln jest tym samym co Println(), po którym następuje wywołanie panic(). Parametr przekazany do panic() jest wyświetlany po zamknięciu programu.
o bufio.NewReader(os.Stdin): Ta funkcja zwraca nowy czytnik z domyślnym rozmiarem bufora (4096 bajtów).
o inputReader.ReadString('n'): Ta metoda odczytuje dane wprowadzone przez użytkownika ze standardowego wejścia do pierwszego wystąpienia separatora na wejściu i zwraca ciąg znaków zawierający dane do separatora włącznie. Błąd przed zlokalizowaniem ogranicznika zawiera dane odczytane przed błędem i sam błąd.
Pierwszy przykład: aby uzyskać najlepsze wyniki, użyj kompilatora offline. Zapisz plik jako plik .go. Aby uruchomić program, wykonaj poniższe polecenie.
go run file-name.go
// program to read and write files
package main
// importing packages
import (
"fmt"
"io/ioutil"
"log"
"os"
)
func CreateFile() {
// fmt package implements formatted I/O, it
has functions like Printf and Scanf
fmt.Printf("Writing file in Go lang\n")
// in case error is thrown it is received by
err variable and Fatalf method of
// log prints error message and stops program
execution
file, er := os.Create("test1.txt")
if er != nil {
log.Fatalf("failed creating file: %s", er)
}
// Defer is used for the purposes of cleanup
like closing a running file after the file has
// been written and the main function has
completed execution
defer file.Close()
// len variable captures the length of string
written to the file.
len, er := file.WriteString("Welcome
Everyone"+
" Program demonstrates reading and
writing"+
" operations to a file in
the Go lang.")
if er != nil {
log.Fatalf("failed writing to file: %s", er)
}
// Name() method returns name of the file as
presented to Create() method.
fmt.Printf("\nFile Name: %s", file.Name())
fmt.Printf("\nLength: %d bytes", len)
}
func ReadFile() {
fmt.Printf("\n\nReading a file in the Go
lang\n")
fileName := "test1.txt"
// The ioutil package contains inbuilt
// methods like ReadFile that reads
// filename and returns contents.
data, er := ioutil.ReadFile("test.txt")
if er != nil {
log.Panicf("failed reading data from file:
%s", er)
}
fmt.Printf("\nFile Name is: %s", fileName)
fmt.Printf("\nSize is: %d bytes", len(data))
fmt.Printf("\nData is: %s", data)
}
// main function
func main() {
CreateFile()
ReadFile()
}
Drugi przykład: kod programu GoLang odczytuje i zapisuje pliki na podstawie danych wprowadzonych przez użytkownika.
// Program to read and write files
package main
// importing requires packages
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"os"
)
func CreateFile(filename, text string)
{
// fmt package implements formatted I/O
// and contains the inbuilt methods like the
Printf and Scanf
fmt.Printf("Writing to a file in the Go
lang\n")
// Creating file using Create() method with
user inputted filename and err
// variable catches any error thrown
file, er := os.Create(filename)
if er != nil {
log.Fatalf("failed creating file: %s", er)
}
// closing running file after the main method
has completed execution and
// writing to the file is complete
defer file.Close()
// writing data to file using
// WriteString() method and
// length of the string is stored in the len
variable
len, er := file.WriteString(text)
if er != nil {
log.Fatalf("failed writing to file: %s",
er)
}
fmt.Printf("\nFile Name is: %s", file.Name())
fmt.Printf("\nLength is: %d bytes", len)
}
func ReadFile(filename string) {
fmt.Printf("\n\nReading a file in the Go
lang\n")
// file is read using ReadFile() method of the
ioutil package
data, err := ioutil.ReadFile(filename)
// in case of an error
// the error statement is printed, program is
stopped
if er != nil {
log.Panicf("failed reading data from file:
%s", er)
}
fmt.Printf("\nFile Name is: %s", filename)
fmt.Printf("\nSize is: %d bytes", len(data))
fmt.Printf("\nData is: %s", data)
}
// main function
func main() {
// user input for the filename
fmt.Println("Enter-filename: ")
var filename string
fmt.Scanln(&filename)
// user input for the file content
fmt.Println("Enter-text: ")
inputReader := bufio.NewReader(os.Stdin)
input, _ := inputReader.ReadString('\n')
// file is created then read
CreateFile(filename, input)
ReadFile(filename)
}
W GoLang, JAK ZMIENIĆ NAZWĘ I PRZENIEŚĆ PLIK
Funkcja Rename() w języku programowania Go pozwala nam zmienić nazwę i przenieść istniejący plik do nowego katalogu. Ta procedura służy do zmiany nazwy i przesyłania pliku z jednej ścieżki do drugiej. Jeśli określona nowa ścieżka już istnieje i nie znajduje się w katalogu, ta procedura ją zastąpi. Mogą jednak obowiązywać ograniczenia specyficzne dla systemu operacyjnego, jeśli określone stare i nowe ścieżki znajdują się w oddzielnych katalogach. Jeśli określona ścieżka jest błędna, wpisanie *LinkError spowoduje zgłoszenie błędu. Ponieważ jest to określone w pakiecie os, musimy zaimportować pakiet os do naszego programu, aby użyć metody Remove().
Składnia:
func Rename(old-path, new-path string) error
Pierwszy przykład:
// Program to illustrate how to rename,
// move a file in the default directory
package main
import (
"log"
"os"
)
func main() {
// Rename and Remove a file
// Using Rename() function
OriginalPath := "helloo.txt"
NewPath := "abc.txt"
es := os.Rename(Original_Path, New_Path)
if es != nil {
log.Fatal(es)
}
}
Drugi przykład:
// Program to illustrate how to rename,
//remove a file in new directory
package main
import (
"log"
"os"
)
func main() {
// Rename and Remove file
// Using Rename() function
OriginalPath := "/Users/anki/Documents/new_
folder/helloo.txt"
NewPath := "/Users/anki/Documents/new_folder/
myfolder/abc.txt"
es := os.Rename(OriginalPath, NewPath)
if es != nil {
log.Fatal(es)
}
}
JAK CZYTAĆ PLIKI LINIA PO LINII DO STRINGU
Pakiet bufio Scanner służy do odczytu pliku linia po linii. Niech plik tekstowy będzie się nazywał sample1.txt, a zawartość pliku będzie następująca. Język programowania Go to statycznie kompilowany język programowania typu open source. Rob Pike, Ken Thompson i Robert Grieserner stworzyli go w Google. Czasami jest określany jako GoLang. Język programowania Go to język programowania ogólnego przeznaczenia przeznaczony do tworzenia skomplikowanego oprogramowania na dużą skalę.
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// os.Open() opens specific file in the
// read-only mode,
// this return pointer of type os.
file, er := os.Open("sample1.txt")
if er != nil {
log.Fatalf("failed to open")
}
// bufio.NewScanner() function is called in which
// object os.File passed as its parameter
// this returns object bufio.Scanner which is used
on the
// bufio.Scanner.Split() method
scanner := bufio.NewScanner(file)
// The bufio.ScanLines is used as
// input to method bufio.Scanner.Split()
// and then scanning forwards to each
// new line using bufio.Scanner.Scan() method.
scanner.Split(bufio.ScanLines)
var text []string
for scanner.Scan() {
text = append(text, scanner.Text())
}
// The method os.File.Close() is called
// on the os.File object to close filev
file.Close()
// and then a loop iterates through,
// prints each of the slice values.
for _, each_ln := range text {
fmt.Println(each_ln)
}
}
Typy danych
Omówiliśmy, jak odczytać plik w Go i jak zmienić jego nazwę. Tu będziemy zawijać liczby, wartości logiczne i ciągi znaków.
PODSTAWOWA SKŁADNIA
Przyjrzeliśmy się podstawowej strukturze programu Go. Inne istotne części składowe języka programowania Go będą teraz znacznie łatwiejsze do zrozumienia.
Tokeny
Program Go składa się z różnych tokenów. Tokenami mogą być słowa kluczowe, identyfikatory, stałe, literały łańcuchowe lub symbole. Na przykład poniższa instrukcja Go składa się z sześciu tokenów:
fmt.Println("Witam wszystkich")
Poszczególne tokeny są następujące:
fmt
.
Println
(
"Witam wszystkich"
)
Separator linii
Klawisz separatora linii jest terminatorem instrukcji w programie Go. Innymi słowy, poszczególne instrukcje nie wymagają szczególnego separatora, takiego jak ";" w C. Kompilator Go używa terminatora instrukcji ";" aby oznaczać koniec jednej logicznej jednostki. Spójrz na przykład na następujące instrukcje:
fmt.Println("Hello, Everyone")
fmt.Println("We are in the world of Go Programming")
Kometarze
Komentarze są podobne do komunikatów pomocy w naszym programie Go, a kompilator je ignoruje. Zaczynają się od/* i kończą znakami */, jak pokazano poniżej.
/* Mój pierwszy program w Go */
W komentarzach nie może być żadnych komentarzy i nie pojawiają się one w ciągach ani literałach znaków.
Identyfikatory
Identyfikator Go identyfikuje zmienną, funkcję lub inną jednostkę zdefiniowaną przez użytkownika. Identyfikator zaczyna się od litery od A do Z, od a do z lub podkreślenia. Po nim mogą występować podkreślenia, zero lub więcej liter lub cyfr.
identyfikator = litera { litera | cyfra_unicode }
Znaki interpunkcyjne, takie jak @, $ i procent, nie są dozwolone w identyfikatorach w Go. Go to język komputerowy, w którym rozróżniana jest wielkość liter. Tak więc w Go Siła Robocza i siła robocza to dwie odrębne tożsamości. Oto kilka przykładów odpowiednich identyfikatorów:
ramesh sehgal xyz move_name x_123
myname40 _temp j x23b8 retVal
Słowa kluczowe nie mogą być używane jako identyfikatory. Identyfikator _ to unikalny identyfikator, czasami nazywany pustym identyfikatorem. Później odkryjemy, że wszystkie typy, zmienne, stałe, etykiety, nazwy pakietów i nazwy importu pakietów muszą być identyfikatorami. Wyeksportowany identyfikator zaczyna się od wielkiej litery Unicode. W wielu innych językach słowo wyeksportowane można przetłumaczyć jako publiczne. Nieeksportowane identyfikatory nie zaczynają się od wielkiej litery Unicode. Określenie "nieeksportowane" można rozumieć jako "prywatne w kilku różnych językach". Znaki wschodnie są teraz klasyfikowane jako litery nieeksportowane. Niewyeksportowane identyfikatory są czasami nazywane niewyeksportowanymi identyfikatorami. Oto kilka przykładów legalnie wyeksportowanych identyfikatorów:
Gracz_7
Zrobił coś
WERSJA
?
Oto kilka przykładów legalnych, niewyeksportowanych identyfikatorów:
_
_status
memeStat
books
?
Oto kilka przykładów tokenów, których nie wolno używać jako identyfikatory:
// Począwszy od cyfry Unicode.
321
4 jabłka
// Zawierające znaki Unicode nie
// spełnianie wymagań.
c.d
*ptr
$names
c@d.e
// To są słowa kluczowe.
type
range
Słowa kluczowe
Terminy zastrzeżone w Go są wymienione w poniższej tabeli. Te zastrzeżone terminy nie mogą być używane jako stałe, zmienne lub inne identyfikatory.
case default import interface struct
chan defer go map select
break else if package type
const fallthrough goto range switch
continue for func return var
Są one podzielone na sześć kategorii: const, func, import, package, type i var służą do deklarowania różnych typów komponentów kodu w programach Go. Niektóre denotacje typu złożonego używają chan, interface, map i struct jako składników. Aby zarządzać przepływem kodu, używane są break, case, continue, default, other, fallthrough, for, goto, if, range, return, select i switch. Zarówno defer, jak i go kontrolują warunki przepływu, chociaż na różne sposoby.
Biała przestrzeń
W Go białe znaki odnoszą się do spacji, tabulacji, znaków nowej linii i komentarzy. Pusta linia ma po prostu białe znaki, być może z uwagą, i jest całkowicie ignorowana przez kompilator Go. Białe znaki oddzielają jedną sekcję instrukcji od drugiej i pozwalają kompilatorowi określić, gdzie kończy się jeden element, int, a zaczyna następny element w instrukcji. W rezultacie w poniższej instrukcji
var ages int;
Aby kompilator mógł rozróżnić int i age, musi istnieć co najmniej jeden biały znak (zwykle spacja). Dla kontrastu rozważmy następujące stwierdzenie:
fruits = grapes + oranges; // pobierz całkowitą ilość owoców
Nie ma spacji wymaganych między owocami a = lub między = a grapes; jednak mile widziane jest uwzględnienie każdego ze względu na czytelność.
TYPY DANYCH W Go
Typy danych definiują rodzaje danych przechowywanych w poprawnej zmiennej Go. Typ jest podzielony na cztery typy w języku Go, które są następujące:
o Liczby, łańcuchy i wartości logiczne to przykłady typów podstawowych.
o Tablice i struktury to przykłady typów agregatów.
o Wskaźniki, wycinki, mapy, funkcje i kanały to przykłady typów odwołań.
o Typ interfejsu.
W tej sekcji omówimy podstawowe typy danych w języku programowania Go. Podstawowe typy danych są dalej podzielone na trzy podkategorie, które są następujące:
o Liczby
o Logiczne
o Struny
Liczby
Liczby w Go są podzielone na trzy podkategorie, które są następujące:
o Liczby całkowite: Język Go obsługuje zarówno liczby całkowite ze znakiem, jak i bez znaku w czterech różnych rozmiarach, jak pokazano w poniższej tabeli. Liczba całkowita ze znakiem jest oznaczona przez int, podczas gdy liczba całkowita bez znaku jest oznaczona przez uint.
Typ: Opis
int8 : 8-bitowa liczba całkowita ze znakiem
int16 : 16-bitowa liczba całkowita ze znakiem
int32 : 32-bitowa liczba całkowita ze znakiem
int64 : 64-bitowa liczba całkowita ze znakiem
uint8 : 8-bitowa liczba całkowita bez znaku
uint16: 16-bitowa liczba całkowita bez znaku
uint32: 32-bitowa liczba całkowita bez znaku
uint64: 64-bitowa liczba całkowita bez znaku
Int : In i uint mają ten sam rozmiar, 32 lub 64 bity
uint : In i uint mają ten sam rozmiar, 32 lub 64 bity
Rune : Jest taki sam jak int32 i reprezentuje punkty kodowe Unicode
Bajt: Jest to skrót od uint8
Uintptr : Jest to typ liczby całkowitej bez znaku. Nie ma stałej szerokości, ale może przechowywać wszystkie bity wartości wskaźnika
Przykład :
package main
import "fmt"
func main() {
// 8-bit unsigned int usingv
var A uint8 = 225
fmt.Println(A, A-3)
// Using 16-bit signed int
var B int16 = 32767
fmt.Println(B+2, B-2)
}
Liczby zmiennoprzecinkowe
W Go liczby zmiennoprzecinkowe dzielą się na dwa typy, co ilustruje poniższa tabela:
Typ danych: opis
float32 : 32-bitowa liczba zmiennoprzecinkowa IEEE 754
float64 : 64-bitowa liczba zmiennoprzecinkowa IEEE 754
Przykład:
package main
import "fmt"
func main()
{
x := 22.46
y := 35.88
// Subtract of two floating-point number
z := y-x
// Display result
fmt.Printf("Result is: %f", z)
// Display type of c variable
fmt.Printf("\nThe type of z is : %T", z)
}
Liczby zespolone
Liczby zespolone są podzielone na dwie części w poniższej tabeli. Te złożone liczby całkowite obejmują również liczbę zmiennoprzecinkową32 i zmiennoprzecinkową64. Wbudowana funkcja generuje liczbę zespoloną ze swoich składników urojonych i rzeczywistych, podczas gdy wbudowane funkcje urojone i rzeczywiste usuwają te składniki.
Typ danych: opis
complex64 : Liczby zespolone z float32 jako składnikiem rzeczywistym i urojonym.
complex128 : Liczby zespolone z float64 jako składową rzeczywistą i urojoną.
Przykład:
package main
import "fmt"
func main() {
var x complex128 = complex(7, 3)
var y complex64 = complex(8, 3)
fmt.Println(x)
fmt.Println(y)
// Display type
fmt.Printf("The type of x is %T and "+
"the type of y is %T", x, y)
}
Logiczne
Typ danych Boolean reprezentuje tylko jeden bit informacji: prawda lub fałsz. Wartości typu Boolean nie są z natury ani jawnie przekształcane na żaden inny typ.
Przykład :
package main
import "fmt"
func main() {
// variables
strg1 := "PeeksofPeeks"
strg2:= "peeksofpeeks"
strg3:= "PeeksofPeeks"
results1:= strg1 == strg2
results2:= strg1 == strg3
// Display result
fmt.Println( results1)
fmt.Println( results2)
// Display type of
// results1 and results2
fmt.Printf("The type of results1 is %T and "+
"the type of results2 is %T",
results1, results2)
}
Stringi
Typ danych łańcuchowych to seria punktów kodowych Unicode. Innymi słowy, ciąg to seria niezmiennych bajtów, co oznacza, że raz utworzony ciąg nie może się zmienić. Ciąg może zawierać dowolne dane w formie czytelnej dla człowieka, w tym bajty o wartości zerowej.
Przykład:
package main
import "fmt"
func main()
{
// strf variable stores strings
strg := "PeeksofPeeks"
// Display length of the string
fmt.Printf("Length of the string is:%d",
len(strg))
// Display string
fmt.Printf("\nString is: %s", strg)
// Display type of strg variable
fmt.Printf("\nType of strg is: %T", strg)
}
Zmienne i stałe
ZMIENNE W Go
Typowy program wykorzystuje wiele zmiennych, które mogą zmieniać się podczas wykonywania. Rozważmy na przykład program, który wykonuje różne operacje na wartościach wprowadzonych przez użytkownika. Wartości przesłane przez jednego użytkownika mogą różnić się od wartości wprowadzonych przez innego. W rezultacie wymagane są zmienne. Dzieje się tak dlatego, że inny użytkownik może nie wykorzystać ponownie tych samych wartości. Kiedy użytkownik wprowadzi nową wartość w procesie operacji, która będzie dalej wykorzystywana, może przechowywać ją tymczasowo w pamięci o dostępie swobodnym komputera, a wartości w tym obszarze pamięci zmieniają się w trakcie wykonywania, dając na to inne określenie, który jest znany jako zmienne. Tak więc w istocie zmienna jest symbolem zastępczym dla informacji, które mogą być aktualizowane w czasie wykonywania. Zmienne umożliwiają wyszukiwanie i manipulowanie przechowywanymi danymi.
Wytyczne dotyczące nazewnictwa zmiennych:
o Zawsze zaczynaj nazwę zmiennej od litery lub podkreślenia (_). Dodatkowo w nazwach mogą występować litery "a-z" lub "A-Z" albo cyfry 0-9 i znak "_".
Peeks peeks, _peeks24 // prawidłowa zmienna
124peeks, 24peeks // nieprawidłowa zmienna
o Nigdy nie zaczynaj nazwy zmiennej od cyfry.
235peeks // niedozwolona zmienna
o W nazwie zmiennej rozróżniana jest wielkość liter.
peeks i Peeks to dwie różne zmienne
o Słowa kluczowe nie mogą być używane jako nazwy zmiennych.
o Nie ma ograniczeń co do długości nazwy zmiennej; zaleca się jednak, aby nie przekraczał 4-15 liter.
Deklarowanie zmiennej
Zmienne w języku programowania Go można deklarować na dwa sposoby.
Używanie słowa kluczowego var
Zmienne w Go są tworzone przy użyciu słowa kluczowego var określonego typu, połączonego z nazwą i nadanej wartości początkowej.
Składnia:
var nazwa_zmiennej typ = wyrażenie
Ważne notatki:
o W powyższej składni w definicji zmiennej można usunąć typ lub wyrażenie =, ale nie oba jednocześnie.
o Jeśli typ zostanie usunięty, inicjalizacja wartości w wyrażeniu określa typ zmiennej.
Przykład:
// Illustrate the concept of variable
package main
import "fmt"
func main() {
// Variable declared &
// initialized without the explicit type
var myvariable1 = 30
var myvariable2 = "PeeksofPeeks"
var myvariable3 = 37.80
// Display value and
// type of the variables
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
fmt.Printf("Type of myvariable1 is : %T\n",
myvariable1)
fmt.Printf("Value of myvariable2 is : %s\n",
myvariable2)
fmt.Printf("Type of myvariable2 is : %T\n",
myvariable2)
fmt.Printf("Value of myvariable3 is : %f\n",
myvariable3)
fmt.Printf("Type of myvariable3 is : %T\n",
myvariable3)
}
o Jeśli wyrażenie zostanie usunięte, zmienna będzie miała wartość zerową dla typu, na przykład zero dla liczb, fałsz dla logicznych, " " dla łańcuchów i zero dla typów interfejsowych i referencyjnych. W rezultacie w języku programowania Go nie ma pojęcia o niezainicjowanej zmiennej.
Przykład:
// Program to illustrate the concept of variable
package main
import "fmt"
func main() {
// Variable declared &
// initialized without the expression
var myvariable1 int
var myvariable2 string
var myvariable3 float64
// Display zero-value of the variables
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
fmt.Printf("Value of myvariable2 is : %s\n",
myvariable2)
fmt.Printf("Value of myvariable3 is : %f",
myvariable3)
}
o Używając typu, możemy zdefiniować kilka zmiennych tego samego typu w jednej deklaracji.
Przykład :
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main() {
// Multiple variables of same type
// are declared & initialized in single line
var myvariable1, myvariable2, myvariable3 int
= 4, 554, 68
// Display values of the variables
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
fmt.Printf("Value of myvariable2 is : %d\n",
myvariable2)
fmt.Printf("Value of myvariable3 is : %d",
myvariable3)
}
o Jeśli usuniemy typ, możemy zdefiniować wiele zmiennych różnych typów w jednej deklaracji. Zainicjowane wartości wskazują typ zmiennej.
Przykład:
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main() {
// Multiple variables of different types
// are declared and initialized in single line
var myvariable1, myvariable2, myvariable3 = 4,
"CFG", 69.56
// Display value &
// type of variables
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
fmt.Printf("Type of myvariable1 is : %T\n",
myvariable1)
fmt.Printf("\nValue of the myvariable2 is : %s\n",
myvariable2)
fmt.Printf("Type of the myvariable2 is : %T\n",
myvariable2)
fmt.Printf("\nThe value of the myvariable3 is :
%f\n",
myvariable3)
fmt.Printf("Type of the myvariable3 is : %T\n",
myvariable3)
}
o Funkcja wywołująca, która zwraca wiele wartości, pozwala nam zainicjować zestaw zmiennych.
Przykład:
// Here, os.Open function return a
// file in x variable and an error
// in y variable
var x, y = os.Open(name)
Korzystanie z krótkiej deklaracji zmiennej
Krótka deklaracja zmiennej służy do definiowania i inicjalizacji zmiennych lokalnych w funkcjach.
Składnia:
nazwa-zmiennej:= wyrażenie
Uwaga: Proszę nie mylić := i =, ponieważ := to deklaracja, a = to przypisanie.
Ważne notatki:
o Typ wyrażenia decyduje o typie zmiennej w poprzednim wyrażeniu.
Przykład:
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main()
{
// Using short-variable declaration
myvar1 := 37
myvar2 := "PeeksofPeeks"
myvar3 := 36.63
// Display value and type of the variables
fmt.Printf("Value of myvar1 is : %d\n", myvar1)
fmt.Printf("Type of myvar1 is : %T\n", myvar1)
fmt.Printf("\nValue of myvar2 is : %s\n", myvar2)
fmt.Printf("Type of myvar2 is : %T\n", myvar2)
fmt.Printf("\nValue of myvar3 is : %f\n", myvar3)
fmt.Printf("Type of myvar3 is : %T\n", myvar3)
}
o Ze względu na ich zwięzłość i wszechstronność, większość zmiennych lokalnych jest definiowana i inicjowana przy użyciu krótkich deklaracji zmiennych.
o Zmienne z deklaracją var są używane dla zmiennych lokalnych, które wymagają jawnego typu, różniącego się od wyrażenia inicjującego lub zmiennych, których wartości są przypisywane później, a wartość zainicjowana jest nieistotna.
o Używając krótkiej deklaracji zmiennej, możemy zadeklarować kilka zmiennych w jednej deklaracji.
Przykład:
// Go program to illustrate
// concept of variable
package main
import "fmt"
func main()
{
// Using short variable declaration
// Multiple variables of the same types
// are declared & initialized in single line
myvar1, myvar2, myvar3 := 830, 44, 66
// Display value and
// type of variables
fmt.Printf("Value of myvar1 is : %d\n", myvar1)
fmt.Printf("Type of myvar1 is : %T\n", myvar1)
fmt.Printf("\nValue of myvar2 is : %d\n", myvar2)
fmt.Printf("Type of myvar2 is : %T\n", myvar2)
fmt.Printf("\nValue of myvar3 is : %d\n", myvar3)
fmt.Printf("Type of myvar3 is : %T\n", myvar3)
}
o Funkcja wywołująca może zainicjować grupę zmiennych, które zwracają wiele wartości w krótkiej deklaracji zmiennej.
Przykład :
// os.Open function return
// a file in x variable and an
// error in y variable
x, y := os.Open(name)
o Krótka deklaracja zmiennej zachowuje się podobnie do przypisania tylko wtedy, gdy odnosi się do wcześniej zdefiniowanych zmiennych w tym samym bloku leksykalnym. Deklaracje zmiennych w bloku zewnętrznym są ignorowane. Jak pokazano w poniższym przykładzie, co najmniej jedna zmienna jest nową zmienną utworzoną z tych dwóch zmiennych.
Przykład:
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main() {
// Using the short variable declaration
// short variable declaration acts
// as an assignment for the myvar2 variable
// because same variable present in same block
// so the value of myvar2 is changed from 55 to 100
myvar1, myvar2 := 39, 55
myvar3, myvar2 := 55, 100
// If we try to run the commented lines,
// then compiler will gives the error because
// these variables are already defined
// myvar1, myvar2 := 53, 57
// myvar2:= 210
// Display the values of the variables
fmt.Printf("Value of myvar1 and myvar2 is : %d
%d\n",
myvar1, myvar2)
fmt.Printf("Value of myvar3 and myvar2 is : %d
%d\n",
myvar3, myvar2)
}
o Możemy zdefiniować wiele zmiennych różnego rodzaju w jednej deklaracji przy użyciu krótkiej deklaracji zmiennej. Wyrażenie określa typ tych zmiennych.
Przykład:
// Program to illustrate
// the concept of variable
package main
import "fmt"
func main() {
// Using the short variable declaration
// Multiple variables of the different types
// are declared and initialized in single line
myvar1, myvar2, myvar3 := 700, "Peeks", 48.56
// Display value and type of the variables
fmt.Printf("Value of myvar1 is : %d\n", myvar1)
fmt.Printf("Type of myvar1 is : %T\n", myvar1)
fmt.Printf("\nValue of myvar2 is : %s\n", myvar2)
fmt.Printf("Type of myvar2 is : %T\n", myvar2)
fmt.Printf("\nValue of myvar3 is : %f\n", myvar3)
fmt.Printf("Type of myvar3 is : %T\n", myvar3)
}
STAŁE
Jak wskazuje słowo CONSTANT, jest ono ustalone; podobnie w językach programowania po zadeklarowaniu wartości stałej nie można jej dalej zmieniać. Stałe mogą być dowolnym podstawowym rodzajem danych, takim jak stała całkowita, stała zmiennoprzecinkowa, stała znakowa lub ciąg znaków.
Jak powinniśmy zadeklarować?
Stałe są definiowane podobnie jak zmienne, ale ze słowem kluczowym const jako prefiksem określającym stałą określonego typu. Nie da się tego opisać za pomocą składni :=.
Przykład:
package main
import "fmt"
const Pi = 3.14
func main()
{
const POP = "PeeksofPeeks"
fmt.Println("Hello", world)
fmt.Println("Happy", Pi, "Day")
const Correct= true
fmt.Println("Go rules?", Correct)
}
Niewpisane i wpisane stałe liczbowe
Wpisane stałe zachowują się jak niezmienne zmienne i mogą wchodzić w interakcje tylko ze zmiennymi tego samego typu, ale stałe bez typu zachowują się jak literały i wchodzą w interakcje z podobnymi zmiennymi. W Go stałe mogą być określane z typem lub bez niego. Poniżej znajduje się przykład wpisanych i niewpisanych stałych numerycznych, zarówno nazwanych, jak i bezimiennych.
const untypedInteger = 321
const untypedFloating typed = 321.12
const typedInteger int = 321
const typedFloatingPoint float64 = 321.12
Poniżej znajduje się lista stałych języka Go:
o Stała liczbowa (stała całkowita, stała zmiennoprzecinkowa i stała zespolona)
o Stała logiczna
o Literały łańcuchowe
Stała numeryczna
Stałe numeryczne to wartości o wysokiej precyzji. Ponieważ Go jest językiem o typach statycznych, operacje łączące typy numeryczne są niedozwolone. Nie możemy dodać float64 ani nawet int32 do int. Niemniej jednak wolno pisać 1e6*time. Po drugie, czyli matematyka. 1('t'+2.0) lub nawet Exp(1). Stałe, w przeciwieństwie do zmiennych, działają w Go jak zwykłe liczby. Istnieją trzy typy stałych numerycznych: całkowite, złożone i zmiennoprzecinkowe.
Stała całkowita
o Podstawa lub podstawa jest określona przez przedrostek: 0x lub 0X dla szesnastkowego, 0 dla ósemkowego i nic dla dziesiętnego.
o Literał całkowity może dodatkowo zawierać sufiks, który jest mieszanką U (duże litery) i L (wielkie litery), wskazując, że jest on bez znaku lub długi.
o Może to być stała w postaci dziesiętnej, ósemkowej lub szesnastkowej.
o Int może przechowywać co najwyżej 64-bitową liczbę całkowitą, a czasami mniej.
Oto kilka przykładów stałej całkowitoliczbowej:
85 : dziesiętny
0213 : ósemkowy
0x4b : szesnastkowy
30 : wewn
30u : bez znaku wewn
30 l : długi
30ul: długi bez znaku
212 : Prawny
215u : Prawne
0xFeeL: legalne
078 : Nielegalne: 8 nie jest cyfrą ósemkową
032UU: Nielegalne: nie można powtórzyć sufiksu
Stała zespolona Stałe zespolone działają bardzo podobnie do stałych zmiennoprzecinkowych. Jest to uporządkowana lub rzeczywista para stałych całkowitych (lub parametrów), oddzielona przecinkiem i zawarta w nawiasach okrągłych. Pierwsza stała reprezentuje rzeczywisty składnik, podczas gdy druga reprezentuje część urojoną. COMPLEX*8 to stała zespolona, która wymaga 8 bajtów pamięci.
Przykład:
(0.0, 0.0) (-123.456E+30, 987.654E-29)
Stała zmiennoprzecinkowa Część całkowita, kropka dziesiętna, część ułamkowa i część wykładnicza składają się na stałą typu zmiennoprzecinkowego. Stałe zmiennoprzecinkowe mogą być reprezentowane w postaci dziesiętnej lub wykładniczej. Wyrażając w postaci dziesiętnej, musimy uwzględnić kropkę dziesiętną, wykładnik lub oba. A w przypadku stosowania formy wykładniczej część całkowita, ułamkowa lub obie części muszą zawierać. Oto kilka przykładów stałych typu Floating:
3.14159 : Poprawny
314159E-5L : Informacje poprawne
510E : Niedozwolone: niepełny wykładnik
210f : Niedozwolone: brak miejsca dziesiętnego lub wykładnika
.e55 : Niedozwolone: brak liczby całkowitej lub ułamka
Literały łańcuchowe
Go obsługuje dwie formy literałów łańcuchowych: " " (styl podwójnego cudzysłowu) i " " (cudzysłów wsteczny). Operatorów + i += można używać do łączenia łańcuchów. Znaki w łańcuchu są porównywalne z literałami znakowymi, ponieważ są zwykłymi znakami, sekwencjami specjalnymi i znakami uniwersalnymi. I to jest przypadek nieokreślony. Typy ciągów z wartościami zerowymi to puste ciągi, które mogą być reprezentowane literalnie przez " " lub ". Wszystkie typy łańcuchów można porównywać za pomocą operatorów, takich jak ==,!= i (do porównywania tych samych typów)
Składnia:
type _string struct
{
elements *byte // the underlying bytes
len int //the number of bytes
}
Przykład :
"hello, peeksofpeeks"
"hello, \
peeksofpeeks"
"hello " "peeks" "ofpeeks"
Wszystkie trzy z powyższych stwierdzeń są w tym kontekście podobne w tym sensie, że brakuje im określonego typu.
Przykład :
package main
import "fmt"
func main()
{
const X = "POP"
var Y = "PeeksofPeeks"
// Concat strings.
var helloEveryone = X+ " " + Y
helloEveryone += "!"
fmt.Println(helloEveryone)
// Compare strings.
fmt.Println(X == "POP")
fmt.Println(Y < X)
}
Stała logiczna
Stałe łańcuchowe i stałe boolowskie są typami stałych. Podąża za tymi samymi wytycznymi, co stała łańcuchowa. Główna różnica polega na tym, że zawiera dwie stałe bez typu, true i false.
Przykład:
package main
import "fmt"
const Pi = 3.14
func main()
{
const trueConst = true
// Type definition using the type keyword
type myBool bool
var defaultBool = trueConst // allowed
var customBool myBool = trueConst // allowed
// defaultBool = customBool // not allowed
fmt.Println(defaultBool)
fmt.Println(customBool)
}
ZMIENNY ZAKRES W Go
Zasięg zmiennej można opisać jako obszar programu, w którym dostępna jest określona zmienna. Zmienną można zadeklarować w klasie, metodzie, pętli lub innej strukturze. Podobnie jak w C/C++, wszystkie identyfikatory w GoLangu mają zasięg leksykalny (lub statyczny), co oznacza, że zakres zmiennej może zostać określony w czasie kompilacji. Alternatywnie zmienną można wywołać tylko z poziomu bloku kodu, w którym jest zdefiniowana. Reguły zakresu zmiennych w GoLang można podzielić na dwa typy w zależności od tego, gdzie zmienne są deklarowane:
o Zmienne lokalne (deklarowane wewnątrz bloku)
o Zmienne globalne (deklarowane poza blokiem)
Zmienne lokalne
o Typ zmiennych zdefiniowanych w funkcji lub bloku to zwane zmiennymi lokalnymi. Poza funkcją lub blokiem są niedostępne.
o Zmienne te można również zadeklarować w funkcji for, while, i podobne stwierdzenia.
o Dostęp do tych zmiennych można jednak uzyskać za pomocą zagnieżdżonych bloków kodu w ramach funkcji.
o Zmienne blokowe to inna nazwa tych zmiennych.
o Błąd kompilacji wystąpi, jeśli te zmienne zostaną zadeklarowane dwukrotnie z tą samą nazwą w tym samym zakresie.
o Po zakończeniu wykonywania funkcji zmienne te nie są już obecne.
o Zmienna określona poza pętlą jest również dostępna w zagnieżdżonych pętlach. Oznacza to, że zmienna globalna będzie dostępna dla wszystkich metod i pętli. Pętla i funkcja wewnątrz funkcji będzie mogła uzyskać dostęp do zmiennej lokalnej.
o Zmienna zadeklarowana w ciele pętli nie jest widoczna na zewnątrz ciała pętli.
Przykład:
// Program to illustrate the local variables
package main
import "fmt"
// main function
func main() { // from here the local level scope
of main function starts
// local variables inside the main function
var myvariable1, myvariable2 int = 90, 47
// Display values of the variables
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
fmt.Printf("Value of myvariable2 is : %d\n",
myvariable2)
} // here the local level scope of main function
ends
Zmienne globalne
o Zmienne globalne są określane poza funkcją lub blokiem.
o Są one dostępne przez cały czas trwania programu.
o Są one deklarowane poza funkcjami lub blokami na początku programu.
o Są one dostępne z dowolnego miejsca w programie.
Przykład:
// Program to illustrate the global variables
package main
import "fmt"
// the global variable declaration
var myvariable1 int = 120
func main() { // from here the local level scope
starts
// the local variables inside the main function
var myvariable2 int = 210
// Display value of global variable
fmt.Printf("Value of Global myvariable1 is :
%d\n",
myvariable1)
// Display value of local variable
fmt.Printf("Value of Local myvariable2 is : %d\n",
myvariable2)
// calling function
display()
} // local level scope ends
// taking function
func display() { // the local level starts
// Display value of global variable
fmt.Printf("Value of Global myvariable1 is :
%d\n",
myvariable1)
} // the local scope ends here
Uwaga: Co się stanie, jeśli w funkcji pojawi się zmienna lokalna o takiej samej nazwie jak zmienna globalna? Rozwiązanie jest proste: kompilator będzie faworyzował zmienną lokalną. Gdy deklarowane są dwie podobne zmienne o tej samej nazwie, kompilator zwykle generuje błąd czasu kompilacji. Jeśli jednak zmienne są określone w różnych zakresach, kompilator je zaakceptuje. Kompilator będzie poprzedzał zmienną lokalną, gdy zostanie zadeklarowana zmienna lokalna o takiej samej nazwie jak zmienna globalna.
o W poniższym przykładzie możemy zobaczyć dane wyjściowe. Ponieważ wartość myvariable1 w funkcji main wynosi 210. W rezultacie zmienna lokalna zdecydowanie preferuje zmienną globalną.
Przykład:
// Program to show the compiler giving preference
// to local variable over a global variable
package main
import "fmt"
// the global variable declaration
var myvariable1 int = 120
func main() { // from here the local level scope
starts
// local variables inside main function
// it is same as a global variable
var myvariable1 int = 210
// Display value
fmt.Printf("Value of myvariable1 is : %d\n",
myvariable1)
} // here the local level scope ends
DEKLARACJA WIELU ZMIENNYCH
Pojedyncza instrukcja może służyć do deklarowania wielu zmiennych. Składnia deklaracji wielu zmiennych to var nazwa1, nazwa2 typ = wartość początkowa1, wartość początkowa2.
Przykład:
package main
import "fmt"
func main() {
var width, height int = 120, 60 //declaring
multiple variables
fmt.Println("width :", width, "height :", height)
}
Jeśli zmienne mają wartość początkową, typ można pominąć. Ponieważ zmienne w poprzednim programie mają wartości początkowe, typ int może usunąć.
Przykład:
Na przykład powyższe oprogramowanie wydrukuje w rezultacie szerokość 120 i wysokość 60. Jest całkiem jasne, że powinieneś już się domyślić, że jeśli nie określono wartości początkowej szerokości i wysokości, ustawimy ją na 0.
Przykład:
package main
import "fmt"
func main() {
var width, height int
fmt.Println("width :", width, "height :", height)
width = 120
height = 60
fmt.Println("new width :", width, "new height
:", height)
}
Może się zdarzyć, że chcemy zdefiniować zmienne kilku rodzajów w jednym zdaniu. Składnia służąca do tego jest wyjaśniona poniżej:
var (
nme1 = initialvalue1
nme2 = initialvalue2
)
Poniższy program deklaruje zmienne różnego rodzaju przy użyciu składni opisanej powyżej.
package main
import "fmt"
func main() {
var (
name = "natasha"
age = 27
height int
)
fmt.Println("my name :", name, ", age :", age,
"and height :", height)
}
Tutaj definiujemy nazwę zmiennej łańcuchowej, zmienną int wiek i zmienną int wysokość.
Deklaracja skrócona
Go ma również bardziej zwarte podejście do deklarowania zmiennych. Nazywa się to instrukcją skróconą i wykorzystuje operator :=. Skróconą formą deklarowania zmiennej jest nazwa := wartość początkowa. Poniższy program deklaruje zmienną count o wartości 12 przy użyciu składni skróconej. Ponieważ count zostało rozpoczęte od wartości całkowitej 12, Go wywnioskuje, że jest typu int.
package main
import "fmt"
func main() {
count := 12
fmt.Println("Count =",count)
}
Wiele zmiennych można również zadeklarować w jednym wierszu przy użyciu składni skróconej.
package main
import "fmt"
func main() {
name, age := "natasha", 27 //short hand
declaration
fmt.Println("my name :", name, "age :", age)
}
Poprzedni program definiuje dwie zmienne typu string i int, odpowiednio. Jeśli wykonamy lub uruchomimy powyższy program, zobaczymy wydrukowane moje imię, Natasza i wiek, 27. Deklaracja skrócona wymaga przypisania wartości początkowych wszystkim zmiennym po lewej stronie przypisania. Następująca aplikacja zwróci błąd niezgodności przypisania: dwie zmienne, ale tylko jedna wartość. Wynika to z faktu, że wieku nie przypisano wartości.
package main
import "fmt"
func main() {
name, age := "natasha" //error
fmt.Println("my name :", name, "age :", age)
}
Tylko wtedy, gdy co najmniej jedna zmienna po lewej stronie := jest nowo zdefiniowana, można użyć składni skróconej. Pomyśl o następującym programie:
package main
import "fmt"
func main() {
x, y := 30, 10 // declare variables x and y
fmt.Println("x is", x, "y is", y)
y, z := 50, 60 // y is already declared but z is
new
fmt.Println("y is", y, "z is", z)
y, z = 70, 80 // assign new values to already
declared variables y and z
fmt.Println("changed y is", y, "z is", z)
}
Natomiast jeśli wykonamy następujący program:
package main
import "fmt"
func main() {
x, y := 20, 30 //x and y declared
fmt.Println("x is", x, "y is", y)
x, y := 40, 50 //error, no new variables
}
Wygeneruje komunikat o błędzie. Po lewej stronie := nie ma nowych zmiennych, ponieważ zmienne aib zostały już zadeklarowane. Brak nowych zmiennych po lewej stronie := w wierszu nr. 6. Zmienne mogą mieć również wartości obliczane w czasie wykonywania.
Pomyśl o następującym programie:
package main
import (
"fmt"
"math"
)
func main() {
x, y := 145.8, 543.8
z := math.Min(x, y)
fmt.Println("Minimum value :", z)
}
Math to pakiet w powyższym programie, a Min to funkcja w tym pakiecie. Musimy wiedzieć, że wartość z jest określana w czasie wykonywania i jest równa sumie x i y. Zmiennym określonym jako należące do jednego typu nie można przypisać wartości innego typu, ponieważ Go jest ściśle typowany. Ponieważ wiek jest określony jako typ int, a my próbujemy przypisać wartość ciągu, poniższy program wyświetli błąd informujący, że nie możemy użyć "natasha" (typ ciąg) jako typu int w przypisaniu.
package main
func main() {
age := 27 // age is int
age = "natasha" // error since we are trying to
assign the string to a variable of type int
}
Operatory i struktury kontrolne
Operatory w Go
Operatory są budulcem każdego języka programowania. W efekcie bez użycia operatorów funkcjonalność języka Go jest niepełna. Operatory pozwalają nam wykonywać wiele działań na operandach. Operatory w języku programowania Go są klasyfikowane na podstawie ich funkcjonalności:
o Operatory arytmetyczne
o Operatorzy relacyjni
o Różni operatorzy
o Operatory bitowe
o Operatorzy przypisania
o Operatory logiczne
Operatory arytmetyczne
W Go są one używane do wykonywania operacji arytmetycznych/matematycznych na operandach:
o Dodawanie: Operator "+" łączy ze sobą dwa operandy. Na przykład x+y.
o Odejmowanie: Operator "-" bierze dwa operandy i odejmuje je. Na przykład x-y.
o Mnożenie: Znak "*" służy do mnożenia dwóch operandów. Na przykład, x*y.
o Dzielenie: Operator "/" dzieli pierwszy operand przez drugi operand. Jako przykład rozważmy x/y.
o Moduł: Kiedy pierwszy operand jest dzielony przez drugi, zwracana jest reszta operatora "%". Na przykład x procent y.
Nota bene: -, +, !, &, * i - są również znane jako operatory jednoargumentowe i mają wyższy priorytet. Ponieważ operatory ++ i -- pochodzą z instrukcji, a nie z wyrażeń; znajdują się poza hierarchią operatorów.
Przykład:
// Program to illustrate the
// use of the arithmetic operators
package main
import "fmt"
func main()
{
x:= 37
y:= 22
// Addition
result1:= x + y
fmt.Printf("Result of x + y = %d", result1)
// Subtraction
result2:= x - y
fmt.Printf("\nResult of x - y = %d", result2)
// Multiplication
result3:= x * y
fmt.Printf("\nResult of x * y = %d", result3)
// Division
result4:= x / y
fmt.Printf("\nResult of x / y = %d", result4)
// Modulus
result5:= x % y
fmt.Printf("\nResult of x %% y = %d", result5)
}
Operatory relacyjne>
Podczas porównywania dwóch wartości stosowane są operatory relacyjne. Przyjrzyjmy się im:
o Operator "==" (równy) określa, czy dwa operandy są równe. W takim przypadku zwraca wartość true. Jeśli nie, zwraca false. 6==6 zwróci na przykład prawdę.
o Operator "!=" określa, czy dwa podane operandy są równe, czy nie. Jeśli tak, zwraca wartość true. Jeśli nie, zwraca false. Jest to logiczny odpowiednik operatora "==". 6!=6 zwróci na przykład fałsz.
o Operator ">" (Większy niż) określa, czy pierwszym argumentem jest większy niż drugi. W takim przypadku zwraca wartość true. Jeśli nie, zwraca fałsz. 7>6 da na przykład prawdę.
o Operator "<" (Mniej niż) określa, czy pierwszy operand jest mniejszy niż drugi. W takim przypadku zwraca wartość true. Jeśli nie, zwraca false. Na przykład 6<4 zwróci fałsz.
o Operator "?" (Większy niż równy) określa, czy pierwszy operand jest większy lub równy drugiemu operandowi, a następnie zwraca prawdę. Jeśli nie, zwraca false. 6?6 zwróci na przykład prawdę. o Operator "?" (najmniejszy niż równy) określa, czy pierwszy operand jest mniejszy lub równy drugiemu operandowi, a następnie zwraca wartość true. Jeśli nie, zwraca false. Na przykład 6?6 również zwróci wartość true.
Przykład:
// Program to illustrate
// the use of relational operators
package main
import "fmt"
func main() {
x:= 38
y:= 25
// '=='(Equal To)
result1:= x == y
fmt.Println(result1)
// '!='(Not Equal To)
result2:= x != y
fmt.Println(result2)
// '<'(Less Than)
result3:= x < y
fmt.Println(result3)
// '>'(Greater Than)
result4:= x > y
fmt.Println(result4)
// '>='(Greater Than Equal To)
result5:= x >= y
fmt.Println(result5)
// '<='(Less Than Equal To)
result6:= x <= y
fmt.Println(result6)
}
Operatory logiczne
Służą do zintegrowania dwóch lub więcej warunków/ograniczeń lub uzupełnienia oceny pierwotnego warunku.
o Logiczne AND: Operator && zwraca wartość true, gdy spełnione są oba rozważane warunki. Jeśli nie, zwraca false. x && y, na przykład, zwraca wartość true, gdy zarówno x, jak i y są prawdziwe (tj. niezerowe).
o Logiczne LUB: Gdy spełniony jest jeden lub oba wymagania, operator "||" zwraca wartość true. Jeśli nie, zwraca false. Na przykład x || y zwraca true, jeśli x lub y jest prawdziwe (tj. niezerowe). Oczywiście zwraca wartość true, jeśli zarówno x, jak i y są prawdziwe.
o Logiczne NIE: Jeśli dany warunek jest spełniony, operator "!" zwraca prawdę. Jeśli nie, zwraca false. !x, na przykład, zwraca wartość true, jeśli a jest fałszywe, czyli gdy x=0.
Przykład:
// Program to illustrate
//the use of logical operators
package main
import "fmt"
func main() {
var x int = 26
var y int = 65
if(x!=y && x<=y){
fmt.Println("True")
}
if(x!=y || x<=y){
fmt.Println("True")
}
if(!(x==y)){
fmt.Println("True")
}
}
Operatory bitowe
W języku programowania Go 6 operatorów bitowych działa na poziomie bitowym lub wykonuje operacje bit po bicie. Operatory bitowe to:
o & (bitowe AND): Pobiera dwa operandy i wykonuje operację AND na każdym bicie dwóch liczb. AND zwraca 1 tylko wtedy, gdy oba bity są równe 1.
o | (bitowe LUB): Pobiera dwa operandy i wykonuje LUB na każdym bicie dwóch liczb całkowitych. LUB zwraca wartość 1, jeśli jeden z dwóch bitów ma wartość 1.
o ^ (bitowe XOR): Pobiera dwa operandy i wykonuje XOR na każdym bicie dwóch liczb. Jeśli dwa bity są różne, wynikiem operacji XOR jest 1.
o << (przesunięcie w lewo): przyjmuje dwie liczby całkowite, przesuwa w lewo bity pierwszego operandu, a drugi operand określa liczbę przesunąć pozycji.
o >> (przesunięcie w prawo): pobiera dwie liczby, przesuwa bity pierwszego operandu w prawo, a liczba miejsc do przesunięcia jest określana przez drugi operand.
o &^ (AND NOT): Jest to prosty operator.
Przykład:
// Program to illustrate
// the use of bitwise operators
package main
import "fmt"
func main() {
x:= 34
y:= 20
// & (bitwise AND)
result1:= x & y
fmt.Printf("Result of x & y = %d", result1)
// | (bitwise OR)
result2:= x | y
fmt.Printf("\nResult of p | q = %d", result2)
// ^ (bitwise XOR)
result3:= p ^ q
fmt.Printf("\nResult of x ^ y = %d", result3)
// << (left shift)
result4:= x << 1
fmt.Printf("\nResult of x << 1 = %d", result4)
// >> (right shift)
result5:= x >> 1
fmt.Printf("\nResult of x >> 1 = %d", result5)
// &^ (AND NOT)
result6:= x &^ y
fmt.Printf("\nResult of x &^ y = %d", result6)
}
Operatory przypisania
Podczas przypisywania wartości do zmiennej stosowane są operatory przypisania. Lewy operand operatora przypisania jest zmienną, a prawy operand operatora przypisania jest wartością. Wartość po prawej stronie musi mieć ten sam typ danych co zmienna po lewej stronie, w przeciwnym razie kompilator zgłosi błąd. Oto przykłady operatorów przypisania:
o "=" (Proste przypisanie): Najbardziej podstawowy operator przypisania. Wartość po prawej stronie jest przypisywana do zmiennej po lewej stronie za pomocą tego operatora.
o "+=" (Dodaj przypisanie): Kombinacja operatorów "+" i "=". Ten operator najpierw dodaje zmienną po lewej stronie bieżącej wartości do prawej, a następnie przypisuje wynik do zmiennej po lewej stronie.
o "-=" (odejmowanie przypisania): Kombinacja operatorów "?" i "=". Ten operator odejmuje bieżącą wartość zmiennej po lewej stronie od prawej, a następnie przypisuje wynik zmiennej po lewej stronie.
o "*=" (przypisanie mnożenia): Kombinacja operatorów "*" i "=". Ten operator najpierw mnoży zmienną po lewej przez prawą, a następnie przypisuje wynik do lewej zmiennej.
o "/=" (przypisanie dzielenia): Kombinacja operatorów "/" i "=". Ten operator dzieli zmienną po lewej stronie bieżącą wartość przez wartość po prawej stronie, a następnie przypisuje wynik zmiennej po lewej stronie.
o "%=" (przypisanie modułu): Ten operator łączy w sobie operatory "%" i "=". Operator ten mnoży aktualną wartość zmiennej po lewej przez prawą, a następnie przypisuje wynik do lewej zmiennej.
o "&=" (przypisanie bitowe AND): kombinacja "&" i "=" operatorzy. Ten operator "Bitwise AND" bieżąca wartość do lewej zmiennej do prawej przed przypisaniem wyniku do lewej zmiennej.
o "=" (bitowe wyłączne LUB): Kombinacja operatorów "=" i "=". Ten operator "Bitwise Exclusive OR" przestawia bieżącą wartość lewej zmiennej na prawą przed przypisaniem wyniku do lewej zmiennej.
o "|=" (bitowo włącznie OR): Kombinacja operatorów "|" i "=". Ten operator "Bitwise Inclusive OR" przestawia bieżącą wartość lewej zmiennej na prawą przed przypisaniem wyniku do lewej zmiennej.
Przykład:
// Program to illustrate
// the use of assignment operators
package main
import "fmt"
func main()
{
var x int = 49
var y int = 54
// "="(Simple Assignment)
x = y
fmt.Println(p)
// "+="(Add Assignment)
x += y
fmt.Println(x)
//"-="(Subtract Assignment)
x-=y
fmt.Println(x)
// "*="(Multiply Assignment)
x*= y
fmt.Println(x)
// "/="(Division Assignment)
x /= y
fmt.Println(x)
// "%="(Modulus Assignment)
x %= y
fmt.Println(x)
}
Różne operatorzy
o &: Ten operator zwraca adres zmiennej.
o *: Ten operator zwraca wskaźnik do zmiennej.
o <-: Otrzymano nazwę tego operatora. Służy do pobierania wartości z kanału.
Przykład:
// Program to illustrate
// the use of Misc Operators
package main
import "fmt"
func main() {
x := 6
// Using address of operator(&) and
// pointer indirection(*) operator
y := &x
fmt.Println(*y)
*y = 7
fmt.Println(x)
}
INSTRUKCJE STERUJĄCE
Programista musi zdefiniować jeden lub więcej warunków, które mają być ocenione lub przetestowane przez program, instrukcję lub instrukcje, które zostaną wykonane, jeśli warunek zostanie uznany za prawdziwy, oraz opcjonalnie dalsze instrukcje, które zostaną wykonane, jeśli warunek zostanie uznany za fałszywy. Poniżej przedstawiono ogólną formę wspólnych ram podejmowania decyzji obecnych w większości języków programowania.
Język programowania Go obsługuje następujące instrukcje decyzyjne.
Nr: instrukcja i opis
1: instrukcja if: Po wyrażeniu boolowskim następuje jedna lub więcej instrukcji w instrukcji if.
2 : instrukcja if...else : Gdy wyrażenie boolowskie jest fałszywe, po instrukcji if następuje opcjonalna instrukcja else.
3 : zagnieżdżone instrukcje if : Instrukcja if lub else if może być używana wewnątrz innej instrukcji if lub else if.
4 : instrukcja switch : instrukcja switch sprawdza zmienną pod kątem równości względem zbioru wartości.
5 : instrukcja select : instrukcja select jest podobna do instrukcji switch; jednak opisy przypadków odnoszą się do komunikacji kanałowej.
Instrukcja if
Jest to najprostsze stwierdzenie decyzyjne. Służy do decydowania, czy określona instrukcja lub blok instrukcji zostanie wykonany, tj. jeśli dany warunek jest prawdziwy, to blok instrukcji zostanie wykonany, w przeciwnym razie nie.
Składnia:
if (warunek)
{
// Instrukcja do wykonania, jeśli warunek jest prawdziwy
}
Przykład :
// Program to illustrate
//the use of if statement
package main
import "fmt"
func main() {
// taking local variable
var v int = 800
// using the if statement for
// checking condition
if(v < 2000) {
// print following if
// condition evaluates to true
fmt.Printf("v is less than 2000\n")
}
fmt.Printf("Value of v is : %d\n", v)
}
Instrukcja if
else
Instrukcja if sama w sobie informuje nas, że warunek jest prawdziwy, zostanie wykonany blok instrukcji; jeśli warunek jest fałszywy, blok instrukcji nie zostanie wykonany. Ale co, jeśli warunek jest fałszywy i chcemy zrobić coś innego? W tym momencie pojawia się instrukcja else. Gdy warunek jest fałszywy, możemy użyć instrukcji else w połączeniu z instrukcją if, aby uruchomić blok kodu.
Składnia:
if (warunek)
{
// Wykonuje ten blok if
// warunek jest prawdziwy
} w przeciwnym razie {
// Wykonuje ten blok if
// warunek jest fałszywy
}
Przykład :
// Program to illustrate
// the use of if...else statement
package main
import "fmt"
func main() {
// taking a local variable
var v int = 2400
// using the if statement for
// checking condition
if(v < 2000) {
// print following if
// the condition evaluates to true
fmt.Printf("v is less than 2000\n")
} else {
// print following if
// the condition evaluates to true
fmt.Printf("v is greater than 2000\n")
}
}
Zagnieżdżona instrukcja if
W Go zagnieżdżone if jest instrukcją if, która jest celem innego wyrażenia if lub else. Instrukcja if zagnieżdżona w innej instrukcji if jest nazywana zagnieżdżoną instrukcją if. Tak, możemy zagnieżdżać instrukcje if w instrukcjach if w GoLang. Innymi słowy, możemy zagnieździć instrukcję if w innej instrukcji if.
Składnia:
if (condition1) {
// Executes when the condition1 is true
if (condition2) {
// Executes when the condition2 is true
}
}
Przykład :
// Program to illustrate
// the use of nested if statement
package main
import "fmt"
func main() {
// taking the two local variable
var v1 int = 500
var v2 int = 800
// using if statement
if( v1 == 600 ) {
// if condition is true then
// check the following
if( v2 == 800 ) {
// if the condition is true
// then display following
fmt.Printf("Value of v1 is 500 and v2 is
800\n" );
}
}
}
Drabinka ifjeśli
else
if
Użytkownik może tutaj wybierać spośród wielu alternatyw. Instrukcje if są wykonywane w podanej kolejności. Gdy spełniony jest jeden z warunków, wykonywana jest instrukcja związana z tym if; reszta drabiny jest pomijana. Jeśli żadne z wymagań nie jest spełnione, wykonywana jest ostatnia instrukcja else.
Ważne notatki:
o Instrukcja if może mieć wartość zero lub jeden i musi wystąpić po każdej innej instrukcji if.
o Instrukcja else if w instrukcji if może zawierać od zera do wielu innych instrukcji if i musi wystąpić przed klauzulą else.
o Jeśli instrukcja else if powiedzie się, nie ma potrzeby wypróbowywania żadnej z pozostałych instrukcji else if lub else.
Składnia:
if(condition_1) {
// this block will execute when the
condition_1 is true
} else if(condition_2) {
// this block will execute when the condition2
is true
}
.
else {
// this block will execute when none
// of condition is true
}
Przykład:
// Program to illustrate
// the use of if..else..if ladder
package main
import "fmt"
func main() {
// taking a local variable
var v1 int = 800
// checking condition
if(v1 == 120) {
// if condition is true then
// display following */
fmt.Printf("Value of v1 is 120\n")
} else if(v1 == 250) {
fmt.Printf("Value of a is 250\n")
} else if(v1 == 310) {
fmt.Printf("Value of a is 310\n")
} else {
// if none of the conditions is true
fmt.Printf("None of values is matching\n")
}
}
Przejdź do pętli GoLang
Język programowania Go ma tylko jedną pętlę, którą jest pętla for. Pętla for jest formą struktury kontroli powtórzeń, która pozwala nam zaprojektować pętlę, która zostanie wykonana określoną liczbę razy. Ta pętla for może być używana na kilka sposobów w języku programowania Go, w tym:
1. Jak najbardziej podstawowa pętla for: jest porównywalna z tym, co widzimy w innych językach programowania, takich jak C, C++, C#, Java itp.
Składnia:
for initialization; condition; post{
// statement
}
Tutaj instrukcja inicjalizacji jest opcjonalna i jest uruchamiana przed rozpoczęciem pętli for. Instrukcja inicjalizacji jest zawsze zawarta w instrukcji podstawowej, takiej jak deklaracje zmiennych, instrukcje inkrementacji lub przypisania lub wywołania funkcji. Instrukcja warunku zawiera wyrażenie logiczne oceniane na początku każdej iteracji pętli. Pętla jest wykonywana, jeśli wartość instrukcji warunkowej jest prawdziwa. Instrukcja post jest wykonywana po treści pętli for. Po oświadczeniu post, oświadczenie warunku jest ponownie oceniane; jeśli wartość instrukcji warunkowej jest fałszywa, pętla zostaje zakończona.
Przykład:
/ Program to illustrate
// the use of simple for loop
package main
import "fmt"
// the main function
func main() {
// for loop
// This loop starts when x = 0
// executes till x<4 condition is true
// post statement is x++
for x := 0; x < 4; x++{
fmt.Printf("helloeveryone\n")
}
}
2. Pętla for jako pętla nieskończona: Usuwając wszystkie trzy wyrażenia z pętli for, pętla for może być wykorzystana jako pętla nieskończona. Gdy użytkownik nie umieści instrukcji warunku w pętli for, oznacza to, że instrukcja warunku jest prawdziwa, a pętla wchodzi w pętlę nieskończoną.
Składnia:
for
{
// (Instrukcje)
}
Przykład:
// Program to illustrate
// the use of an infinite loop
package main
import "fmt"
// the main function
func main() {
// infinite loop
for {
fmt.Printf("Helloeveryone\n")
}
}
3. Pętla while for: Pętla for może być również używana jako pętla while. Pętla ta jest powtarzana aż do spełnienia określonego warunku. Pętla kończy się, gdy wartość podanego warunku jest fałszywa.
Składnia:
for warunek {
// instrukcje
}
Przykład:
/ Program to illustrate
// for loop as while Loop
package main
import "fmt"
// the main function
func main() {
// while loop for loop executes till
// x < 3 condition is true
x:= 0
for x < 3 {
x += 2
}
fmt.Println(x)
}
4. Prosty zakres w pętli for: Zakres może być również użyty w pętli.
Składnia:
for x, y:= zakres zmiennej{
// instrukcje
}
Tutaj zmienne x i y są miejscem przechowywania wartości iteracji. Są one czasami określane jako zmienne iteracyjne. Druga zmienna, y, nie jest wymagana. Przed rozpoczęciem pętli wyrażenie zakresu jest oceniane raz.
Przykład:
// Program to illustrate
// the use of simple range loop
package main
import "fmt"
// the main function
func main() {
// Here rvariable is array
rvariable:= []string{"HEW", "Hello",
"Helloeveryoneworld"}
// x and y stores the value of rvariable
// x store index number of individual string
and
// y store individual string of the given
array
for x, y:= range rvariable {
fmt.Println(x, y)
}
}
5. Używanie pętli for dla napisów: Pętla for może iterować po punkcie kodowym łańcucha Unicode .
Składnia:
for index chr:= zakres str{
// instrukcje}
W tym przypadku indeks jest zmienną przechowującą pierwszy bajt punktu kodowego zakodowanego w UTF-8, chr jest zmienną przechowującą znaki podanego ciągu, a str jest ciągiem.
Przykład:
// Program to illustrate
// the use for loop using string
package main
import "fmt"
// the main function
func main() {
// String as range in the for loop
for x, y:= range "XxyCd" {
fmt.Printf("Index number of %U is %d\n",
y, x)
}
}
6. Dla map: Pętla for może przechodzić przez parę klucz i wartość mapy.
Składnia:
for klucz, wartość := zakres map {
// instrukcje
}
Przykład:
// Program to illustrate
// the use for loop using maps
package main
import "fmt"
// the main function
func main() {
// using the maps
mmap := map[int]string{
22:"Peeks",
33:"POP",
44:"PeeksofPeeks",
}
for key, value:= range mmap {
fmt.Println(key, value)
}
}
7. For channel: Pętla for może iterować po kolejnych danych przesyłanych w kanale, aż kanał zostanie zamknięty.
Składnia:
for item := range Chnl {
// statement(s)
}
Przykład:
// program to illustrate
// the use for loop using channel
package main
import "fmt"
// the main function
func main() {
// using the channel
chnl := make(chan int)
go func(){
chnl <- 1000
chnl <- 10000
chnl <- 100000
chnl <- 1000000
close(chnl)
}()
for x:= range chnl {
fmt.Println(x)
}
}
Ważne notatki:
o Nawiasy nie obejmują trzech instrukcji pętli for.
o Pętla wymaga nawiasów klamrowych.
o Nawias otwierający i instrukcja post powinny znajdować się w tej samej linii.
o Jeśli tablica, łańcuch, wycinek lub mapa są puste, pętla for nie zgłasza błędu i kontynuuje swój przebieg. Innymi słowy, jeśli tablica, łańcuch, wycinek lub mapa mają wartość zero, liczba iteracji pętli for wynosi zero.
Instrukcja switch Go
Instrukcja switch jest przykładem wielokierunkowej instrukcji rozgałęzienia. Oferuje efektywną metodę przenoszenia wykonania do różnych obszarów kodu w zależności od wartości wyrażenia. Język programowania Go pozwala na dwa rodzaje instrukcji switch:
o Przełącznik ekspresji
o Przełącznik typu
Wyrażenie switch
Wyrażenie switch jest analogiczne do instrukcji switch w C, C++ i Javie. Pozwala nam efektywnie kierować wykonanie do różnych obszarów kodu w oparciu o wartość wyrażenia.
Składnia:
switch optstatement; optexpression{
case expression1: Statement
case expression2: Statement
.
.
default: Statement
}
Ważne notatki:
o W przełączniku wyrażeń zarówno optstatement, jak i optexpression są wyrażeniami opcjonalnymi.
o Jeśli występują zarówno optstatement, jak i optexpression, należy je rozdzielić średnikiem (;).
o Jeśli w przełączniku nie ma wyrażenia, kompilator zakłada, że wyrażenie jest prawdziwe.
o Instrukcja opcjonalna, często znana jako optstatement, zawiera podstawowe instrukcje, takie jak deklaracje zmiennych, instrukcje przyrostu lub przypisania, wywołania funkcji itp.
o Jeśli zmienna pojawia się w instrukcji opcjonalnej, jej zakres jest ograniczony do tej instrukcji switch.
o Nie ma instrukcji break w instrukcji case i default instrukcji switch. Możemy jednak użyć instrukcji break i fallthrough, jeśli wymaga tego nasza aplikacja.
o W instrukcji switch instrukcja default jest opcjonalna.
o Sprawa może mieć wiele wartości oddzielonych przecinkiem (,).
o Jeśli przypadek nie zawiera wyrażenia, kompilator zakłada, że wyrażenie jest prawdziwe.
Pierwszy przykład:
// Program to illustrate
// the concept of Expression switch statement
package main
import "fmt"
func main() {
// the switch statement with both
// optional statement, i.e, day:=4
// and the expression, i.e, day
switch day:=5; day{
case 1:
fmt.Println("Sunday")
case 2:
fmt.Println("Monday")
case 3:
fmt.Println("Tuesday")
case 4:
fmt.Println("Wednesday")
case 5:
fmt.Println("Thursday")
case 6:
fmt.Println("Friday")
case 7:
fmt.Println("Saturday")
default:
fmt.Println("Invalid")
}
}
Drugi przykład :
// Program to illustrate
// the concept of Expression switch statement
package main
import "fmt"
func main() {
var value int = 3
// Switch statement without an
// optional statement and expression
switch {
case value == 1:
fmt.Println("Hey")
case value == 2:
fmt.Println("Hello")
case value == 3:
fmt.Println("Namstae")
default:
fmt.Println("Invalid")
}
}
Trzeci przykład:
// Program to illustrate
// the concept of Expression switch statement
package main
import "fmt"
func main() {
var value string = "four"
// Switch statement without the default
statement
// Multiple values in the case statement
switch value {
case "one":
fmt.Println("C")
case "two", "three":
fmt.Println("C#")
case "four", "five", "six":
fmt.Println("Go")
}
}
Przełącznik typu
Podczas porównywania typów stosowany jest przełącznik typu. Przypadek w tym przełączniku obejmuje typ, który będzie porównywany z typem w wyrażeniu przełącznika.
Składnia :
switch optstatement; typeswitchexpression{
case typelist 1: Statement
case typelist 2: Statement
.
.
default: Statement
}
Ważne notatki:
o Instrukcja opcjonalna, w skrócie optstatement, jest porównywalna z wyrażeniem switch.
o Sprawa może mieć wiele wartości oddzielonych przecinkiem (,).
o Instrukcje case i default w instrukcji typu switch nie zawierają instrukcji break. Możemy jednak użyć instrukcji break i fallthrough, jeśli wymaga tego nasza aplikacja.
o W instrukcji typu switch instrukcja default jest opcjonalna.
o Typeswitchexpression jest wyrażeniem, które w konsekwencji tworzy typ.
o Jeśli wyrażenie jest przypisane do zmiennej w typeswitchexpression za pomocą operatora :=, typ tej zmiennej jest określany przez typ zawarty w klauzuli case. Jeśli klauzula case zawiera dwa lub więcej typów, typem zmiennej jest typ, w którym została ona wygenerowana w typeswitchexpression.
Przykład:
// Program to illustrate
// the concept of Type switch statement
package main
import "fmt"
func main() {
var value interface{}
switch x:= value.(type) {
case bool:
fmt.Println("The value is of boolean type")
case float64:
fmt.Println("The value is of float64 type")
case int:
fmt.Println("value is of int type")
default:
fmt.Printf("value is of type: %T", x)
}
}
Tablice, wycinki i mapy
TABLICE
Tablice w języku komputerowym GoLang są podobne do tych w innych językach programowania. W oprogramowaniu może być konieczne przechowywanie zbioru danych tego samego typu, na przykład listy ocen uczniów. Tablica służy do przechowywania tego rodzaju kolekcji w programie. Tablica to sekwencja o stałej długości wykorzystywana w pamięci do przechowywania jednorodnych elementów. Ze względu na ograniczoną długość tablica nie jest tak popularna jak Slice w języku Go. Tablica może zawierać zero lub więcej niż zero elementów. Elementy tablicy są indeksowane za pomocą operatora indeksu [] z ich pozycją od zera, co oznacza, że indeksem pierwszego elementu jest tablica[0], a indeksem ostatniego elementu jest tablica[len(tablica)-1].
Tworzenie i dostęp do tablicy
Tablice są tworzone na dwa sposoby w języku programowania Go.
Używanie słowa kluczowego var
W Go za pomocą słowa kluczowego var tworzona jest tablica określonego typu z nazwą, rozmiarem i elementami.
Składnia:
Var arrayname[length]Type
lub
var arrayname[length]Typle{item1, item2, item3,
…...itemN}
Ważne notatki:
o Tablice w Go są zmienne; dlatego możemy zastosować składnię array[index] po lewej stronie przypisania, aby ustawić elementy tablicy na podany indeks.
Var nazwatablicy[indeks] = element
o Dostęp do elementów tablicy możemy uzyskać za pomocą wartości indeksu lub pętli for.
o Typ tablicy w języku programowania Go jest jednowymiarowy.
o Długość tablicy jest stała i nie można jej zmienić.
o Zduplikowane elementy mogą być przechowywane w tablicy.
Przykład
// Program to illustrate how to
// create an array using var keyword
// and accessing elements of
// the array using their index value
package main
import "fmt"
func main() {
// Creating array of string type
// Using the var keyword
var myarr[3]string
// Elements are assigned using the index
myarr[0] = "HEW"
myarr[1] = "Helloevryoneoworld"
myarr[2] = "Hello"
// Accessing elements of the array
// Using the index value
fmt.Println("Elements of Array:")
fmt.Println("Element 1: ", myarr[0])
fmt.Println("Element 2: ", myarr[1])
fmt.Println("Element 3: ", myarr[2])
}
Używanie skróconej deklaracji
Tablice w Go można również deklarować za pomocą deklaracji skróconej. Jest bardziej elastyczny niż początkowe twierdzenie.
Składnia:
arrayname:= [length]Type{item1, item2, item3,…
itemN}
Przykład:
// Program to illustrate how to create
// array using shorthand declaration
// and accessing elements of
// the array using for loop
package main
import "fmt"
func main() {
// Shorthand declaration of the array
arr:= [4]string{"hello", "hew", "Hello1431",
"Helloeveryoneworld"}
// Accessing elements of the
// array Using for loop
fmt.Println("Elements of the array:")
for x:= 0; x < 3; x++{
fmt.Println(arr[x])
}
}
Tablica wielowymiarowa
Chociaż wiemy już, że tablice są jednowymiarowe, możemy stworzyć tablicę wielowymiarową. Tablice tego samego rodzaju nazywane są tablicami wielowymiarowymi. Możemy zbudować wielowymiarową tablicę w Go, używając następującej składni:
Nazwa tablicy[Długość1][Długość2]..[DługośćN]Typ
Jak pokazano w poniższym przykładzie, możemy zbudować tablicę wielowymiarową, używając słowa kluczowego Var lub skróconej deklaracji.
Uwaga: Jeśli komórka nie zostanie zainicjowana wartością przez użytkownika w tablicy wielowymiarowej, kompilator zrobi to automatycznie. W GoLangu nie ma czegoś takiego jak niezainicjowana koncepcja.
Przykład:
// Program to illustrate
// the concept of multi-dimension array
package main
import "fmt"
func main() {
// Creating, initializing
// 2-dimensional array
// Using the shorthand declaration
// Here (,) Comma is necessary
arry:= [3][3]string{{"C", "C++", "PHP"},
{"Go", "C#", "Scala"},
{"Python", "C#", "HTML"},}
// Accessing values of
// the array Using for loop
fmt.Println("Elements of Array 1")
for a:= 0; a < 3; a++{
for b:= 0; b < 3; b++{
fmt.Println(arry[a][b])
}
}
// Creating a 2-dimensional
// array using the var keyword
// and initializing a multi
// -dimensional array using index
var arry1 [2][2] int
arry1[0][0] = 100
arry1[0][1] = 200
arry1[1][0] = 300
arry1[1][1] = 400
// Accessing values of the array
fmt.Println("Elements of the array 2")
for x:= 0; x<2; x++{
for y:= 0; y<2; y++{
fmt.Println(arry1[x][y])
}
}
}
Ważne uwagi dotyczące tablicy
1. Jeśli tablica nie została jawnie zainicjowana, domyślną wartością tej tablicy jest 0.
Przykład:
// Program to illustrate an array
package main
import "fmt"
func main() {
// Creating an array of the int type
// which stores the two elements
// Here, we do not initialize
// array so the value of array
// is zero
var myarry[2]int
fmt.Println("Elements of the Array :", myarry)
}
2. Długość tablicy można znaleźć za pomocą funkcji len(), jak pokazano w poniższym przykładzie:
// Program to illustrate how to find
// length of the array
package main
import "fmt"
func main() {
// Creating array
// Using the shorthand declaration
arry1:= [3]int{9,7,6}
arry2:= [...]int{9,7,6,4,5,3,2,4}
arry3:= [3]int{9,3,5}
// Finding length of the
// array using the len method
fmt.Println("The Length of the array 1 is:",
len(arry1))
fmt.Println("The Length of the array 2 is:",
len(arry2))
fmt.Println("The Length of the array 3 is:",
len(arry3))
}
3. Jeśli wielokropek "… pojawia się w miejscu długości tablicy, długość tablicy jest określona przez zainicjowane elementy. Jak pokazano w poniższym przykładzie:
// Program to illustrate
// the concept of ellipsis in an array
package main
import "fmt"
func main() {
// Creating an array whose size is determined
// by number of elements present in it
// Using the ellipsis
myarray:= [...]string{"HEW", "hew", "hello",
"Helloeveryoneworld", "HELLO"}
fmt.Println("Elements of array: ", myarray)
// Length of array
// is determine by
// Using the len() method
fmt.Println("Length of array is:", len(myarray))
}
4. Możemy iterować po elementach tablicy, iterując po jej zakresie. Jak pokazano w poniższym przykładzie:
// Program to illustrate
// how to iterate array
package main
import "fmt"
func main() {
// Creating an array whose size
// is represented by ellipsis
myarray:= [...]int{79, 49, 29, 20,
49, 49, 48, 39}
// Iterate array using for the loop
for y:=0; y < len(myarray); y++{
fmt.Printf("%d\n", myarray[y])
}
}
5. Tablica w Go jest typu wartościowego, a nie referencyjnego. W rezultacie, gdy tablica jest przypisywana do nowej zmiennej, wszelkie modyfikacje wprowadzone w nowej zmiennej nie mają wpływu na pierwotną tablicę. Jak pokazano w poniższym przykładzie:
// Program to illustrate value type array
package main
import "fmt"
func main() {
// Creating array whose size
// is represented by ellipsis
my_array:= [...]int{200, 300, 500, 100, 800}
fmt.Println("Original array(Before):", my_array)
// Creating new variable
// and initialize with the my_array
new_array := my_array
fmt.Println("New array(before):", new_array)
// Change value at index 0 to 500
new_array[0] = 500
fmt.Println("The New array(After):", new_array)
fmt.Println("The Original array(After):", my_array)
}
6. Jeśli typ elementu tablicy jest równoważny, to typ tablicy jest również porównywalny. W rezultacie możemy bezpośrednio porównać dwie tablice za pomocą operatora ==. Jak pokazano w poniższym przykładzie:
// Program to illustrate
// how to compare the two arrays
package main
import "fmt"
func main() {
// Arrays
arry1:= [3]int{8,7,5}
arry2:= [...]int{8,7,5}
arry3:= [3]int{8,5,3}
// Comparing arrays using == operator
fmt.Println(arry1==arry2)
fmt.Println(arry2==arry3)
fmt.Println(arry1==arry3)
// This will give error because
// type of arr1 and arr4 is mismatch
/*
arry4:= [4]int{8,7,5}
fmt.Println(arry1==arry4)
*/
}
Jak skopiować tablicę do innej tablicy w GoLang?
Tablice w języku komputerowym GoLang są podobne do tych w innych językach programowania. W programie może zaistnieć potrzeba przechowywania zbioru danych tego samego typu, np. listy ocen uczniów. Tablica służy do przechowywania tego rodzaju kolekcji w programie. Tablica to sekwencja o stałej długości wykorzystywana w pamięci do przechowywania jednorodnych elementów. GoLang nie zapewnia wbudowanej metody kopiowania jednej tablicy do drugiej. Możemy jednak zrobić klon tablicy, po prostu przypisując tablicę przez wartość lub odwołanie do nowej zmiennej. Jeśli wykonamy kopię tablicy według wartości i zmodyfikujemy wartości oryginalnej tablicy, nie będzie to odzwierciedlać zmian w kopii tej tablicy. A jeśli wykonamy kopię tablicy przez odniesienie i zmodyfikujemy wartości oryginalnej tablicy, odzwierciedli to zmiany w duplikacie tej tablicy. Jak widać na poniższych próbkach:
Składnia:
// tworzenie kopii tablicy według wartości
arry := arr1
// Tworzenie kopii tablicy przez referencję
arry := &arr1
Przyjrzyjmy się kilku przypadkom, które pomogą nam zrozumieć tę koncepcję:
Pierwszy przykład:
// Program to illustrate how
// to copy array by value
package main
import "fmt"
func main() {
// Creating, initializing an array
// Using the shorthand declaration
my_arry1 := [5]string{"C", "Go", "Java",
" Scala ", "C#"}
// Copying array into new variable
// Here, elements are passed by value
my_arry2 := my_arry1
fmt.Println("Array_1: ", my_arry1)
fmt.Println("Array_2:", my_arry2)
my_arry1[0] = "C++"
// when we copy an array
// into the another array by value
then changes made in the original
// array do not reflect in copy of that array
fmt.Println("\nThe Array_1: ", my_arry1)
fmt.Println("The Array_2: ", my_arry2)
}
Drugi przykład:
// Program to illustrate how to
// copy array by reference
package main
import "fmt"
func main() {
// Creating, initializing an array
// Using the shorthand declaration
my_arry1 := [6]int{14, 416, 47, 69, 44, 32}
// Copying array into new variable
// Here, elements are passed by reference
my_arry2 := &my_arry1
fmt.Println("Array_1: ", my_arry1)
fmt.Println("Array_2:", *my_arry2)
my_arry1[5] = 200000
// when we copy an array
// into the another array by reference
// then changes made in original
// array will reflect in
// the copy of that array
fmt.Println("\nArray_1: ", my_arry1)
fmt.Println("Array_2:", *my_arry2)
}
Jak możemy przekazać tablicę do funkcji w GoLang?
Tablice w języku komputerowym GoLang są podobne do tych w innych językach programowania. W programie może być konieczne przechowywanie zbioru danych tego samego typu, na przykład listy ocen uczniów. Tablica służy do przechowywania tego rodzaju kolekcji w programie. Tablica to sekwencja o stałej długości wykorzystywana w pamięci do przechowywania jednorodnych elementów. Możemy wysłać tablicę jako argument do funkcji w języku programowania Go. Aby przekazać tablicę jako argument do funkcji, najpierw utwórz parametr formalny o następującej składni:
Składnia:
// For the sized array
func function_name(variablename [size]type){
// Code
}
Za pomocą tej składni możemy przekazać do funkcji jedną lub więcej tablic wymiarowych. Zilustrujmy to pojęcie przykładem:
// Program to illustrate how to pass an
// array as an argument in function
package main
import "fmt"
// This function accept
// an array as argument
func myfun(a [5]int, size int) int {
var x, val, y int
for x = 0; x < size; x++ {
val += a[x]
}
y = val / size
return y
}
// the main function
func main() {
// Creating, initializing an array
var arr = [5]int{57, 29, 69, 25, 14}
var rest int
// Passing an array as an argument
rest = myfun(arr, 5)
fmt.Printf("Final result is: %d ", rest)
}
Objaśnienie: W przykładzie mamy metodę o nazwie myfun(), która pobiera tablicę jako dane wejściowe. W funkcji main przekazaliśmy arr[5] typu int do funkcji z rozmiarem tablicy, a funkcja zwróciła średnią z tablicy.
WYCINKI
Slice to struktura danych Go, która jest potężniejsza, bardziej elastyczna i wygodniejsza niż tablica. Nie można umieścić wielu komponentów w tym samym wycinku, ponieważ jest to sekwencja o zmiennej długości zawierająca elementy tego samego rodzaju. Można go porównać do tablicy, ponieważ zawiera długość i wartość indeksu. Jednak rozmiar wycinka można rozszerzyć, w przeciwieństwie do tablicy. Wewnętrznie wycinek i tablica są ze sobą połączone; wycinek jest odniesieniem do podstawowej tablicy. Zduplikowane elementy mogą być przechowywane w wycinku. W wycinku początkowy punkt indeksu to zawsze 0, a ostatni to (długość wycinka - 1).
Deklaracja wycinka
Wycinek jest określany podobnie jak tablica, ale nie podaje rozmiaru wycinka. W związku z tym może się rozszerzać i kurczyć w razie potrzeby.
Składnia:
[]T
lub
[]T{}
lub
[]T{value1, value2, value3, …...value n}
T oznacza w tym przypadku typ elementu. Jako przykład:
var myslice[]int
Komponenty wycinka
Wycinek składa się z trzech części:
o Wskaźnik: Wskaźnik jest używany do wskazania pierwszego elementu tablicy dostępnego za pośrednictwem wycinka. W tym przypadku nie jest wymagane, aby wskazany element był pierwszym elementem tablicy.
o Długość: Długość tablicy to całkowita liczba elementów w tablicy.
o Pojemność: Największy rozmiar, do którego może się rozszerzyć, jest reprezentowany przez pojemność.
Przyjrzyjmy się każdemu z tych komponentów na przykładzie:
// Program to illustrate the
// working of the slice components
package main
import "fmt"
func main() {
// Array Creation
arry := [7]string{"This", "is", "the", "example",
"of", "Go", "Programming"}
// Display array
fmt.Println("Array:", arry)
// Creating a slice
myslice := arry[1:6]
// Display the slice
fmt.Println("Slice:", myslice)
// Display the length of slice
fmt.Printf("The Length of the slice: %d",
len(myslice))
// Display the capacity of the slice
fmt.Printf("\nThe Capacity of the slice: %d",
cap(myslice))
}
Objaśnienie: W poprzednim przykładzie generujemy wycinek z tablicy. Ponieważ dolna granica wycinka jest ustawiona na jeden, wskaźnik wycinka wskazywał tutaj indeks 1. W związku z tym zaczął uzyskiwać dostęp do elementów od indeksu 1. Długość wycinka wynosi 5, co wskazuje, że w wycinku znajduje się łącznie 5 elementów, a pojemność wycinka wynosi 6, co oznacza, że może on przechowywać maksymalnie 6 elementów .
Jak możemy utworzyć i zainicjować Wycinek?
Wycinek w Go można zbudować i uruchomić w następujący sposób:
Korzystanie z literału wycinka
Użyj literału wycinka, aby wygenerować Wycinek. Konstrukcja literału wycinka jest podobna do literału tablicowego, z wyjątkiem tego, że nie można definiować rozmiaru wycinka w nawiasach kwadratowych []. Literał plastra jest przedstawiony po prawej stronie tego wyrażenia w poniższym przykładzie:
var myslice1 = []string{"Hello", "from", "Everyone"}
Uwaga: Pamiętaj, że gdy tworzymy wycinek z literałem łańcuchowym, najpierw tworzy on tablicę, a następnie zwraca do niej odwołanie do wycinka.
Przykład:
// Program to illustrate how
// to create a slice using slice literal
package main
import "fmt"
func main() {
// Creating slice using the var keyword
var myslice1 = []string{"Hello", "from",
"Everyone"}
fmt.Println("My Slice 1:", myslice1)
// Creating a slice
//using the shorthand declaration
myslice2 := []int{14, 35, 57, 49, 41, 24, 45}
fmt.Println("My Slice 2:", myslice2)
}
Korzystanie z tablicy
Ponieważ wycinek jest odniesieniem do tablicy, możemy zbudować wycinek z dostarczonej tablicy. Aby utworzyć wycinek z danej tablicy, najpierw określ dolną i górną granicę, co oznacza, że wycinek może akceptować elementy z tablicy, zaczynając od dolnej granicy i kończąc na górnej granicy. Wyklucza elementy z górnej granicy powyżej. Jak pokazano w poniższym przykładzie:
Składnia:
arrayname[low:high]
Ta składnia zwróci nowy wycinek. Należy zauważyć, że dolna granica domyślnie wynosi 0, podczas gdy górna granica jest ustawiona na całkowitą liczbę elementów w określonej tablicy.
Przykład :
// Program to illustrate how to
// create the slices from array
package main
import "fmt"
func main() {
// Array Creation
arry := [4]string{"Hello", "from",
"Developer", "HFD"}
// Creating slices from given array
var myslice1 = aryr[1:2]
myslice2 := arry[0:]
myslice3 := arry[:2]
myslice4 := arry[:]
// Display the result
fmt.Println("My Array: ", arry)
fmt.Println("My Slice 1: ", myslice1)
fmt.Println("My Slice 2: ", myslice2)
fmt.Println("My Slice 3: ", myslice3)
fmt.Println("My Slice 4: ", myslice4)
}
Korzystanie z istniejącego wycinka
Możliwe jest utworzenie nowego wycinka z dostarczonego wycinka. Aby utworzyć nowy wycinek z danego wycinka, najpierw określ dolną i górną granicę, co wskazuje, że Wycinek może pobierać komponenty z danego wycinka, zaczynając od dolnej i górnej granicy. Wyklucza elementy z górnej granicy powyżej. Jak pokazano w poniższym przykładzie:
Składnia:
slicename[low:high]
Ta składnia zwróci nowy wycinek. Należy zauważyć, że dolna granica domyślnie wynosi 0, podczas gdy górna granica jest ustawiona na całkowitą liczbę elementów w określonym wycinku.
Przykład:
// Program to illustrate how to
// create slices from slice
package main
import "fmt"
func main() {
// Creating s slice
oRignAl_slice := []int{80, 20, 50, 10,
54, 89, 70}
// Creating the slices from the given slice
var myslice1 = oRignAl_slice[1:5]
myslice2 := oRignAl_slice[0:]
myslice3 := oRignAl_slice[:6]
myslice4 := oRignAl_slice[:]
myslice5 := myslice3[2:4]
// Display result
fmt.Println("Original Slice:", oRignAl_slice)
fmt.Println("New Slice 1:", myslice1)
fmt.Println("New Slice 2:", myslice2)
fmt.Println("New Slice 3:", myslice3)
fmt.Println("New Slice 4:", myslice4)
fmt.Println("New Slice 5:", myslice5)
}
Korzystanie z funkcji make().
Możemy również użyć funkcji make() biblioteki go do wygenerowania wycinka. Ta funkcja ma trzy parametry wejściowe: typ, długość i pojemność. Wartość pojemności jest w tym przypadku opcjonalna. Zwraca wycinek, który odwołuje się do podstawowej tablicy i przypisuje podstawowej tablicy rozmiar równy podanej pojemności. W większości przypadków metoda make() tworzy pusty wycinek. W tym kontekście puste wycinki mają puste odwołanie do tablicy.
Składnia:
func make([]T, len, cap) []T
Przykład:
// Program to illustrate how to create slices
// Using the make function
package main
import "fmt"
func main() {
// Creating array of size 7 and slice this
array till 4
// and return the reference of the slice
// Using make function
var myslice1 = make([]int, 4, 7)
fmt.Printf("Slice 1 = %v, \nlength = %d, \
ncapacity = %d\n",
myslice1, len(myslice1),
cap(myslice1))
// Creating the another array of size 7
// and return the reference of slice
// Using the make function
var myslice2 = make([]int, 7)
fmt.Printf("Slice 2 = %v, \nlength = %d, \
ncapacity = %d\n",
myslice2, len(myslice2),
cap(myslice2))
}
Jak iterować po wycinku
Możliwe jest iterowanie po wycinku na następujące sposoby:
Korzystanie z pętli for
Jest to najłatwiejsza technika iteracji wycinków, jak widać w poniższym przykładzie:
// program to illustrate
// the iterating over a slice using for loop
package main
import "fmt"
func main() {
// Creating slice
myslice := []string{"This", "is", "the",
"example",
"of", "Go", "language"}
// Iterate using the for loop
for x := 0; x < len(myslice); x++ {
fmt.Println(myslice[x])
}
}
Użycie zakresu w pętli for
Użycie zakresu w pętli for pozwala nam iterować po wycinku. Indeks i wartość elementu można uzyskać za pomocą zakresu w pętli for, jak pokazano w poniższym przykładzie:
// Program to illustrate the iterating
// over a slice using range in for loop
package main
import "fmt"
func main() {
// Creating a slice
myslice := []string{"This", "is", "the", "example",
"of", "Go",
"programing"}
// Iterate the slice using range in for loop
for index, ele := range myslice {
fmt.Printf("Index = %d and element = %s\n",
index+3, ele)
}
}
Używanie pustego identyfikatora w pętli for
Jeśli nie chcemy pobierać wartości indeksu elementów w zakresie pętli for, zamiast zmiennej indeksu możemy użyć spacji (_), jak pokazano w poniższym przykładzie:
// program to illustrate the iterating over
// a slice using a range in for loop without an index
package main
import "fmt"
func main() {
// Creating slice
myslice := []string{"This", "is", "the",
"example", "of", "Go", "programing"}
// Iterate the slice
// using range in for loop without index
for _, ele := range myslice {
fmt.Printf("Element = %s\n", ele)
}
}
Ważne uwagi dotyczące wycinka
Kawałek wartości zerowej
W języku programowania Go możemy zbudować wycinek zerowy, który nie ma żadnych elementów. W rezultacie zarówno pojemność, jak i długość tego wycinka wynoszą 0. Jak widać w poniższym przykładzie, wycinek zerowy nie zawiera odwołania do tablicy:
// Program to illustrate a zero value slice
package main
import "fmt"
func main() {
// Creating zero value slice
var myslice []string
fmt.Printf("Length is = %d\n", len(myslice))
fmt.Printf("Capacity is = %d ", cap(myslice))
}
Modyfikowanie wycinków
Ponieważ Wycinek jest typem referencyjnym, może odwoływać się do podstawowej tablicy. Tak więc, jeśli zmodyfikujemy jakiekolwiek elementy w wycinku, zmiany powinny również zostać odzwierciedlone w tablicy, do której się odwołujemy. Innymi słowy, jeśli dokonamy zmian w wycinku, zmiany zostaną odzwierciedlone w tablicy, jak widać w poniższym przykładzie
// Program to illustrate
// how to modify slice
package main
import "fmt"
func main() {
// Creating zero value slice
arry := [6]int{25, 86, 97, 33, 49, 21}
slc := arry[0:4]
// Before the modifying
fmt.Println("Original_Array: ", arry)
fmt.Println("Original_Slice: ", slc)
// After the modification
slc[0] = 10
slc[1] = 100
slc[2] = 1000
fmt.Println("\nNew_Array: ", arr)
fmt.Println("New_Slice: ", slc)
}
Porównanie wycinków
W wycinku możemy użyć tylko operatora == do określenia, czy dany wycinek jest zerowy, czy nie. Jeśli spróbujemy porównać dwa wycinki za pomocą operatora ==, otrzymamy błąd, jak pokazano w poniższym przykładzie:
// Program to check if
// the slice is nil or not
package main
import "fmt"
func main() {
// creating the slices
st1 := []int{22, 38, 46}
var st2 []int
// If we try to run this commented
// code compiler will give error
/*st3:= []int{13, 55, 69}
fmt.Println(st1==st3)
*/
// Checking if the given slice is nil or not
fmt.Println(st1 == nil)
fmt.Println(st2 == nil)
}
Uwaga: Aby porównać dwa wycinki, użyj pętli for w zakresie pasującym do każdego elementu lub użyj funkcji DeepEqual.
Wielowymiarowy Wycinek
Wycinek wielowymiarowy jest podobny do tablicy wielowymiarowej, z tą różnicą, że wycinek nie zawiera rozmiaru.
Przykład:
// Program to illustrate multi-dimensional slice
package main
import "fmt"
func main() {
// Creating the multi-dimensional slice
st1 := [][]int{{13, 39},
{46, 57},
{99, 30},
{26, 76},
}
// Accessing the multi-dimensional slice
fmt.Println("Slice 1 : ", st1)
// Creating multi-dimensional slice
st2 := [][]string{
[]string{"Hello", "for"},
[]string{"everyone", "HFE"},
[]string{"hfw", "hello"},
}
// Accessing the multi-dimensional slice
fmt.Println("Slice 2 : ", st2)
}
Sortowanie Wycinka
Możemy sortować elementy w wycinku w języku programowania Go. Pakiet sort jest zawarty w standardowej bibliotece języka Go i oferuje kilka technik sortowania do sortowania wycinków int, float64 i stringów. Funkcje te zawsze sortują elementy w kolejności rosnącej dostępnej w przekroju.
Przykład:
// Program to illustrate how to sort
// elements present in the slice
package main
import (
"fmt"
"sort"
)
func main() {
// Creating the Slice
slc1 := []string{"C++", "Java", " Python ",
"Go", "Python"}
slc2 := []int{35, 87, 13, 91, 34, 41, 86, 58,
69}
fmt.Println("Before the sorting:")
fmt.Println("Slice 1: ", slc1)
fmt.Println("Slice 2: ", slc2)
// Performing sort operation on the
// slice using the sort function
sort.Strings(slc1)
sort.Ints(slc2)
fmt.Println("\nAfter sorting:")
fmt.Println("Slice 1: ", slc1)
fmt.Println("Slice 2: ", slc2)
}
Złożony literał wycinka
Wycinek i Złożony Literal to dwa słowa. Wycinek to złożony typ danych, który podobnie jak tablica zawiera elementy tego samego typu danych. Istotna różnica między tablicą a plasterkiem polega na tym, że rozmiar wycinka może zmieniać się dynamicznie, ale tablica nie. Wartości dla tablic, struktur, wycinków i map są tworzone przy użyciu literału złożonego. Za każdym razem, gdy są oceniane, tworzona jest nowa wartość. Składają się z typu literału, po którym następuje lista elementów w nawiasach klamrowych. Po przeczytaniu tego zrozumiemy, czym jest literał złożony i zdziwimy się, że już to wiemy. Przyjrzyjmy się, jak utworzyć wycinek i użyć literału złożonego:
// Program to show the slice composite literal
package main
import "fmt"
func main() {
// Slice with the composite literal
// Slice allows us to group together
// the values of same type
// here the type of values is int
st1 := []int{53, 26, 19, 84}
// displaying the values
fmt.Println(st1)
}
Rozumiemy, co oznacza termin "literał złożony". W rezultacie literały złożone są używane do przypisywania wartości lub inicjowania tablic, wycinków itp. Są one często używane do łączenia kolekcji wartości porównywalnego sortowania. W GoLang, jak sortujemy wycinek intów? Slice to struktura danych Go, która jest bardziej wszechstronna, potężniejsza i wygodniejsza niż tablica. Wycinek to sekwencja o zmiennej długości zawierająca elementy tego samego rodzaju; w tym samym wycinku nie można przechowywać wielu komponentów. Język programowania Go pozwala nam uporządkować elementy wycinka na podstawie ich typu. W rezultacie wycinek typu int jest sortowany przy użyciu poniższych funkcji. Ponieważ te funkcje są określone w pakiecie sort, musimy zaimportować pakiet sort do naszej aplikacji, aby z nich korzystać:
Ints
Ta funkcja sortuje tylko wycinek liczb całkowitych, a elementy w wycinku są sortowane w porządku rosnącym.
Składnia:
func Ints(slc []int)
W tym przypadku slc reprezentuje wycinek intów. Zilustrujmy to pojęcie przykładem:
// Program to demonstrate how
// to sort slice of ints
package main
import (
"fmt"
"sort"
)
// the main function
func main() {
// Creating, initializing slices
// Using the shorthand declaration
scl1 := []int{300, 500, 200, 300, 400, 700, 800}
scl2 := []int{-13, 267, -54, 69, 0, 22, -4}
// Displaying the slices
fmt.Println("Slices(Before):")
fmt.Println("Slice 1: ", scl1)
fmt.Println("Slice 2: ", scl2)
// Sortingslice of ints
// Using Ints function
sort.Ints (scl1)
sort.Ints (scl2)
// Displaying result
fmt.Println("\nSlices(After):")
fmt.Println("Slice 1 : ", scl1)
fmt.Println("Slice 2 : ",scl2)
}
IntsAre Sorted
Ta funkcja określa, czy dostarczony wycinek liczb typu int jest posortowany (w porządku rosnącym), czy nie. Jeśli wycinek jest w postaci posortowanej, ta funkcja zwraca wartość true; w przeciwnym razie zwraca wartość false.
Składnia:
func IntsAreSorted(scl []int) bool
W tym przypadku scl reprezentuje wycinek intów. Zilustrujmy to pojęcie przykładem:
// Program to demonstrate how to check
// whether a given slice of ints is in
// sorted the form or not
package main
import (
"fmt"
"sort"
)
// the main function
func main() {
// Creating, initializing slices
// Using the shorthand declaration
scl1 := []int{200, 100, 800, 300, 400, 500, 700}
scl2 := []int{-13, 547, -24, 97, 0, 18, -5}
// Displaying the slices
fmt.Println("Slices:")
fmt.Println("Slice 1: ", scl1)
fmt.Println("Slice 2: ", scl2)
// Checking slice is in sorted form or not
// Using IntsAreSorted function
rest1 := sort.IntsAreSorted(scl1)
rest2 := sort.IntsAreSorted(scl2)
// Displaying result
fmt.Println("\nResult:")
fmt.Println("Is Slice 1 is sorted?: ", rest1)
fmt.Println("Is Slice 2 is sorted?: ", rest2)
}
Jak można przyciąć kawałek bajtów w GoLang?
Slice to struktura danych Go, która jest bardziej wszechstronna, potężniejsza i wygodniejsza niż tablica. Wycinek to sekwencja o zmiennej długości zawierająca elementy tego samego rodzaju; w tym samym wycinku nie można przechowywać wielu komponentów. Metoda Trim() w wycinku bajtów Go pozwala nam przyciąć wszystkie początkowe i końcowe punkty kodowe zakodowane w UTF-8 z określonego wycinka. Ta metoda tworzy podwycinek oryginalnego wycinka, usuwając wszystkie początkowe i końcowe punkty kodowe zakodowane w formacie UTF-8 z podanego ciągu. Jeśli dostarczony wycinek bajtów nie zawiera wymaganego ciągu, ta metoda zwraca oryginalny wycinek bez zmian. Ponieważ jest to określone w pakiecie bytes, musimy zaimportować pakiet bytes do naszej aplikacji, aby użyć funkcji Trim.
Składnia:
func Trim(ori_slice[]byte, cut_string string) []byte
Oryginalny wycinek bajtów jest reprezentowany przez ori_slice, a cut_string reprezentuje łańcuch, który chcemy przyciąć w danym wycinku. Przeanalizujmy to pojęcie na następujących przykładach:
Pierwszy przykład:
// Program to demonstrate the concept of trim in
the slice of bytes
package main
import (
"bytes"
"fmt"
)
func main() {
// Creating, initializing
// the slice of bytes
// Using the shorthand declaration
slice_1 := []byte{'!', '!', 'H', 'e', 'e',
'l', 'o', 'o',
'o', 'r', 'W', 'o', 'r', 'l',
'd', '#', '#'}
slice_2 := []byte{'*', '*', 'G', 'r', 'a',
'p', 'e', '^', '^'}
slice_3 := []byte{'%', 'h', 'e', 'l', 'l',
'o', '%'}
// Displaying slices
fmt.Println("The Original Slice:")
fmt.Printf("Slice 1: %s", slice_1)
fmt.Printf("\nSlice 2: %s", slice_2)
fmt.Printf("\nSlice 3: %s", slice_3)
// Trimming the specified leading
// and trailing Unicodes points
// from given slice of bytes
// Using Trim function
rest1 := bytes.Trim(slice_1, "!#")
rest2 := bytes.Trim(slice_2, "*^")
rest3 := bytes.Trim(slice_3, "@")
// Display results
fmt.Printf("New Slice:\n")
fmt.Printf("\nSlice 1: %s", rest1)
fmt.Printf("\nSlice 2: %s", rest2)
fmt.Printf("\nSlice 3: %s", rest3)
}
Drugi przykład:
// Program to demonstrate the concept of trim in
the slice of bytes
package main
import (
"bytes"
"fmt"
)
func main() {
// Creating, trimming the slice of bytes
// Using the Trim function
rest1 := bytes.Trim([]byte("****Welcome to
GoWorld****"), "*")
rest2 := bytes.Trim([]byte("!!!!Learning how
to trim slice of bytes@@@@"), "!@")
rest3 := bytes.Trim([]byte("^^hello&&"), "$")
// Display results
fmt.Printf("Final Slice:\n")
fmt.Printf("\nSlice 1: %s", rest1)
fmt.Printf("\nSlice 2: %s", rest2)
fmt.Printf("\nSlice 3: %s", rest3)
}
Jak podzielić kawałek bajtów w GoLang?
Slice to struktura danych Go, która jest bardziej wszechstronna, potężniejsza i wygodniejsza niż tablica. Wycinek to sekwencja o zmiennej długości zawierająca elementy tego samego rodzaju; w tym samym wycinku nie można przechowywać wielu komponentów. Dostarczony wycinek bajtów możemy podzielić w Go za pomocą metody Split(). Ta metoda dzieli wycinek bajtów na wszystkie podwycinki podzielone przez podany separator i zwraca wycinek zawierający wszystkie te podwycinki. Ponieważ jest to określone w pakiecie bytes, musimy zaimportować pakiet bytes do naszego programu, aby użyć funkcji Split.
Składnia:
func Split(o_slice, sep []byte) [][]byte
W tym przypadku o_slice to wycinek bajtów, a sep to separator. Jeśli sep jest pusty, będzie się dzielić po każdej sekwencji UTF-8. Przeanalizujmy to pojęcie na następujących przykładach:
Pierwszy przykład:
// Program to illustrate the concept
// of splitting a slice of bytes
package main
import (
"bytes"
"fmt"
)
func main() {
// Creating, initializing the slice of bytes
// Using the shorthand declaration
slice_1 := []byte{'!', '!', 'H', 'e', 'l',
'l', 'o',
'f', 'o', 'r', 'W', 'o', 'r', 'l', 'd',
'#', '#'}
slice_2 := []byte{'G', 'r', 'a', 'p', 'e'}
slice_3 := []byte{'%', 'h', '%', 'e', '%',
'l',
'%', 'l', '%', 'o', '%'}
// Displaying slices
fmt.Println("Original Slice:")
fmt.Printf("Slice 1: %s", slice_1)
fmt.Printf("\nSlice 2: %s", slice_2)
fmt.Printf("\nSlice 3: %s", slice_3)
// Splitting slice of bytes
// Using the Split function
rest1 := bytes.Split(slice_1, []byte("eek"))
rest2 := bytes.Split(slice_2, []byte(""))
rest3 := bytes.Split(slice_3, []byte("%"))
// Display results
fmt.Printf("\n\nAfter splitting:")
fmt.Printf("\nSlice 1: %s", rest1)
fmt.Printf("\nSlice 2: %s", rest2)
fmt.Printf("\nSlice 3: %s", rest3)
}
Drugi przykład:
// Program to illustrate the concept
// of splitting a slice of bytes
package main
import (
"bytes"
"fmt"
)
func main() {
// Creating, Splitting the slice of bytes
// Using the Split function
rest1 := bytes.Split([]byte("****Welcome, to,
Tutorial****"),
[]byte(","))
rest2 := bytes.Split([]byte("Learning x how x
to x trim x a x slice of bytes"),
[]byte("x"))
rest3 := bytes.Split([]byte("Helloworld,
world"), []byte(""))
rest4 := bytes.Split([]byte(""), []byte(","))
// Display results
fmt.Printf("Final Value:\n")
fmt.Printf("\nSlice 1: %s", rest1)
fmt.Printf("\nSlice 2: %s", rest2)
fmt.Printf("\nSlice 3: %s", rest3)
fmt.Printf("\nSlice 4: %s", rest4)
}
ŁAŃCUCHY ZNAKÓW
Łańcuchy w Go różnią się od tych w innych językach, takich jak Java, C++, Python itp. Jest to ciąg znaków o zmiennej szerokości, z których każdy jest reprezentowany przez jeden lub więcej bajtów zakodowanych w UTF-8. Innymi słowy, ciągi są niezmiennym łańcuchem dowolnych bajtów (w tym bajtów o wartości zerowej) lub ciągi są fragmentem bajtów tylko do odczytu, których bajty mogą być wyrażone w tekście Unicode przy użyciu kodowania UTF-8. Ze względu na kodowanie UTF-8 ciąg GoLang może zawierać treść, która jest mieszanką wszystkich języków na świecie, nie powodując zamieszania ani nie ograniczając strony. Ciągi znaków są zazwyczaj ujęte w podwójne cudzysłowy "", jak pokazano w poniższym przykładzie:
// Program to illustrate
// how to create strings
package main
import "fmt"
func main() {
// Creating, initializing a
// variable with a string
// Using the shorthand declaration
My_value_1 := "Welcome to Home"
// Using the var keyword
var My_value_2 string
My_value_2 = "World"
// Displaying the strings
fmt.Println("String 1: ", My_value_1)
fmt.Println("String 2: ", My_value_2)
}
Literały łańcuchowe
Literały łańcuchowe są tworzone na dwa sposoby w języku programowania Go.
Korzystanie z podwójnych cudzysłowów("")
W tym przypadku literały łańcuchowe są tworzone przy użyciu podwójnych cudzysłowów (""). Ten rodzaj ciągu może zawierać znaki zmiany znaczenia, jak opisano w poniższej tabeli, ale nie może rozciągać się na kilka wierszy. Literały łańcuchowe tego rodzaju są powszechnie używane w programowaniu GoLang.
Znak ucieczki: Opis
\\ : Ukośnik wsteczny
\000 : Znak Unicode z podanym 3-cyfrowym 8-bitowym ósemkowym punktem kodowym
\' : Pojedynczy cudzysłów('). Jest dozwolone tylko wewnątrz literałów znakowych
\" : Cudzysłów("). Jest dozwolone tylko wewnątrz interpretowanych literałów łańcuchowych
\a : dzwonek ASCII
\b : Backspace ASCII
\f : Wysuw strony ASCII
\n : Przesunięcie wiersza ASCII
\r : Powrót karetki ASCII
\t : karta ASCII
\uhhhh: Znak Unicode z podanym 4-cyfrowym 16-bitowym kodem szesnastkowym Znak Unicode z podanym 8-cyfrowym 32-bitowym kodem szesnastkowym
\v : pionowa karta ASCII
\xhh : Znak Unicode z podanym 2-cyfrowym 8-bitowym szesnastkowym punktem kodowym
Używanie znaczników wstecznych (")
Literały łańcuchowe są tworzone za pomocą backticks(") i w tym kontekście są również znane jako literały surowe. Literały surowe nie pozwalają na znaki specjalne, obejmują wiele wierszy i zawierają dowolne inne znaki niż znak wsteczny. Jest powszechnie używany do tworzenia komunikatów wielowierszowych, wyrażenia regularne i HTML.
Przykład:
// Program to illustrate string literals
package main
import "fmt"
func main() {
// Creating, initializing a
// variable with string literal
// Using the double-quote
My_value_1 := "Welcome to World"
// Adding escape character
My_value_2 := "Welcome!\nWorld "
// Using backticks
My_value_3 := 'Hello!Everyone'
// Adding the escape character
// in the raw literals
My_value_4 := 'Hello!\nGeeksforGeeks'
// Displaying the strings
fmt.Println("The String 1: ", My_value_1)
fmt.Println("The String 2: ", My_value_2)
fmt.Println("The String 3: ", My_value_3)
fmt.Println("The String 4: ", My_value_4)
}
Ważne punkty dotyczące ciągów
Ciągi są niezmienne
Ciągi są niezmienne w Go. Po utworzeniu łańcucha zmiana wartości nie jest łatwa. Innymi słowy, łańcuchy są tylko do odczytu. Jeśli spróbujemy coś zmienić, kompilator zgłosi błąd.
Przykład:
// Program to illustrate
// the string are immutable
package main
import "fmt"
// the main function
func main() {
// Creating, initializing a string
// using the shorthand declaration
mystr := "Welcome to World"
fmt.Println("String:", mystr)
/* if we trying to change
the value of string
then compiler will
throw error, i.e,
cannot assign to mystr[1]
mystry[1]= 'G'
fmt.Println("String:", mystry)
*/
}
Jak iterować po łańcuchu
Użyj pętli for rang, aby przejść przez łańcuch. Ta pętla może iterować po punkcie kodu Unicode łańcucha.
Składnia:
for index, chr:= range str{
// Statement
}
W tym przypadku indeks jest zmienną przechowującą pierwszy bajt punktu kodowego zakodowanego w UTF-8, chr jest zmienną przechowującą znaki podanego ciągu, a str jest ciągiem.
Przykład:
// Program to illustrate how
// to iterate over string
// using the for range loop
package main
import "fmt"
// the main function
func main() {
// String as a range in for loop
for index, st := range "Helloeveryone" {
fmt.Printf("Index number of %c is
%d\n", st, index)
}
}
Jak uzyskać dostęp do pojedynczego bajtu łańcucha
Możemy uzyskać dostęp do każdego bajtu podanego tekstu, ponieważ jest to ciąg bajtów.
Przykład:
// Program to illustrate how to
// access bytes of the string
package main
import "fmt"
// Main function
func main() {
// Creating, initializing a string
str := "Welcome to World"
// Accessing the bytes of the given string
for x := 0; x < len(str); x++ {
fmt.Printf("\nCharacter = %c Bytes = %v",
str, str)
}
}
Jak zrobić ciąg znaków z kawałka bajtów
W Go możemy utworzyć ciąg znaków z kawałka bajtów.
Przykład:
package main
import (
"fmt"
"reflect"
"strings"
)
func main() {
stry1 := []string{"Drum", "of", "India", "On",
"Dec"}
fmt.Println(stry1)
fmt.Println(reflect.TypeOf(stry1))
stry2 := strings.Join(stry1, " ")
fmt.Println(stry2)
fmt.Println(reflect.TypeOf(stry2))
stry3 := strings.Join(stry1, ", ")
fmt.Println(stry3)
fmt.Println(reflect.TypeOf(stry3))
}
Jak możemy określić długość łańcucha w GoLang?
Długość łańcucha znaków w GoLangu możemy znaleźć za pomocą dwóch funkcji: len() i RuneCountInString(). Pakiet UTF-8 zawiera metodę RuneCountInString(), która zwraca całkowitą runę w łańcuchu. A metoda len() zwraca długość łańcucha w bajtach.
Przykład:
// Program to illustrate how to
// find the length of the string
package main
import (
"fmt"
"unicode/utf8"
)
// the main function
func main() {
// Creating, initializing a string
// using the shorthand declaration
mystr := "Welcome to Everyone???"
// Finding length of the string
// Using len() function
length1 := len(mystr)
// Using the RuneCountInString() function
length2 := utf8.RuneCountInString(mystr)
// Displaying length of the string
fmt.Println("string:", mystr)
fmt.Println("Length 1:", length1)
fmt.Println("Length 2:", length2)
}
Jak przycinamy string w GoLang?
Łańcuchy w Go różnią się od tych w innych językach, takich jak Java, C++, Python itp. Jest to ciąg znaków o zmiennej szerokości, z których każdy jest reprezentowany przez jeden lub więcej bajtów zakodowanych w UTF-8. Możemy przycinać ciąg na różne sposoby, korzystając z poniższych metod. Te funkcje są określone w pakiecie strings; dlatego musimy zaimportować pakiet strings do Twojej aplikacji, aby z nich korzystać.
Trim
Ta funkcja przycina tekst, usuwając wszystkie początkowe i końcowe punkty kodu Unicode podane w tej funkcji.
Składnia:
func Trim(str string, cutstr string) string
W tym przypadku str reprezentuje bieżący łańcuch, a cutstr reprezentuje elementy w określonym łańcuchu, które chcemy usunąć.
Przykład:
// Program to illustrate
// how to trim string
package main
import (
"fmt"
"strings"
)
// the main method
func main() {
// Creating, initializing string
// Using the shorthand declaration
stry1 := "!!Welcome to Everyone !!"
stry2 := "@@This is the example of Golang$$"
// Displaying strings
fmt.Println("Strings before the trimming:")
fmt.Println("String 1: ", stry1)
fmt.Println("String 2:", stry2)
// Trimming given strings
// Using Trim() function
rest1 := strings.Trim(stry1, "!")
rest2 := strings.Trim(stry2, "@$")
// Displaying results
fmt.Println("\nStrings after the trimming:")
fmt.Println("Result 1: ", rest1)
fmt.Println("Result 2:", rest2)
}
TrimLeft
Funkcja TrimLeft służy do przycinania punktów kodu Unicode łańcucha po lewej stronie (podanej w funkcji).
Składnia:
func TrimLeft(str string, cutstr string) string
W tym przypadku str reprezentuje bieżący łańcuch, a cutstr reprezentuje elementy po lewej stronie określonego ciągu, które chcemy przyciąć.
Przykład:
// Program to illustrate how to
// trim the left-hand side elements
// from string
package mainv
import (
"fmt"
"strings"
)
// the main method
func main() {
// Creating, initializing string
// Using the shorthand declaration
stry1 := "!!Welcome to Everyone **"
stry2 := "@@This is the example of Golang$$"
// Displaying the strings
fmt.Println("Strings before trimming:")
fmt.Println("String 1: ", stry1)
fmt.Println("String 2:", stry2)
// Trimming the given strings
// Using the TrimLeft() function
rest1 := strings.TrimLeft(str1, "!*")
rest2 := strings.TrimLeft(str2, "@")
// Displaying results
fmt.Println("\nStrings after trimming:")
fmt.Println("Result 1: ", rest1)
fmt.Println("Result 2:", rest2)
}
TrimRight
Ta funkcja przycina prawą stronę łańcucha (podaną w funkcji)
Punkty kodu Unicode.
Składnia:
func TrimRight(str string, cutstr string) string
W tym przypadku str reprezentuje bieżący łańcuch, a cutstr reprezentuje komponenty po prawej stronie określonego ciągu, które chcemy przyciąć.
Przykład:
// Program to illustrate how to
// trim the right-hand side elements
// from string
package main
import (
"fmt"
"strings"
)
// the main method
func main() {
// Creating, initializing the
// string using the shorthand declaration
stry1 := "!!Welcome to Everyone **"
stry2 := "@@This is the example of Golang$$"
// Displaying the strings
fmt.Println("Strings before the trimming:")
fmt.Println("String 1: ", stry1)
fmt.Println("String 2:", stry2)
// Trimming given strings
// Using the TrimRight() function
rest1 := strings.TrimRight(stry1, "!*")
rest2 := strings.TrimRight(stry2, "$")
// Displaying results
fmt.Println("\nStrings after trimming:")
fmt.Println("Result 1: ", rest1)
fmt.Println("Result 2:", rest2)
}
TrimSpace
Ta metoda usuwa wszystkie wiodące i końcowe spacje z podanego ciągu.
Składnia:
func TrimSpace(str string) string
Przykład:
// Program to illustrate how to
// trim the white space from string
package main
import (
"fmt"
"strings"
)
// the main method
func main() {
// Creating, initializing string
// Using the shorthand declaration
stry1 := " **Welcome to Everyone** "
stry2 := " ##This is the example of Golang## "
// Displaying the strings
fmt.Println("Strings before the trimming:")
fmt.Println(stry1, stry2)
// Trimming the white space from given strings
// Using TrimSpace() function
rest1 := strings.TrimSpace(stry1)
rest2 := strings.TrimSpace(stry2)
// Displaying results
fmt.Println("\nStrings after the trimming:")
fmt.Println(rest1, rest2)
}
TrimSuffix
Ta metoda usuwa końcowy sufiks ciągu. Jeśli podany ciąg nie zawiera określonego ciągu sufiksu, ta metoda zwraca oryginalny ciąg w niezmienionej postaci.
Składnia:
func TrimSuffix(str, suffstr string) string
Oryginalny ciąg jest reprezentowany przez str, podczas gdy ciąg sufiksu jest reprezentowany przez suffstr.
Przykład:
// Program to illustrate how to
// trim suffix string from
// the given string
package main
import (
"fmt"
"strings"
)
// the main method
func main() {
// Creating, initializing string
// Using the shorthand declaration
stry1 := "Welcome, Everyone"
stry2 := "This is the, example of Golang"
// Displaying the strings
fmt.Println("Strings before the trimming:")
fmt.Println("String 1: ", stry1)
fmt.Println("String 2:", stry2)
// Trimming the suffix string from given strings
// Using the TrimSuffix() function
rest1 := strings.TrimSuffix(str1, "Helloworld")
rest2 := strings.TrimSuffix(str2, "Helloo")
// Displaying results
fmt.Println("\nStrings after the trimming:")
fmt.Println("Result 1: ", rest1)
fmt.Println("Result 2:", rest2)
}
TrimPrefix
Ta metoda usuwa wiodący przedrostek ciągu. Jeśli podany ciąg nie zawiera żądanego ciągu prefiksu, ta metoda zwraca oryginalny ciąg w niezmienionej postaci.
Składnia:
func TrimPrefix(str, suffstr string) string
Oryginalny ciąg jest reprezentowany przez str, podczas gdy ciąg przedrostka jest reprezentowany przez suffstr.
Przykład:
// Program to illustrate how to
// trim prefix string from
// the given string
package main
import (
"fmt"
"strings"
)
// the Main method
func main() {
// Creating, initializing string
// Using the shorthand declaration
stry1 := "Welcome, Everyone"
stry2 := "This is the, example of Golang"
// Displaying the strings
fmt.Println("Strings before the trimming:")
fmt.Println("String 1: ", stry1)
fmt.Println("String 2: ", stry2)
// Trimming the prefix string from given
strings
// Using the TrimPrefix() function
rest1 := strings.TrimPrefix(str1, "Hello")
rest2 := strings.TrimPrefix(str2, "World")
// Displaying results
fmt.Println("\nStrings after the trimming:")
fmt.Println("Result 1: ", rest1)
fmt.Println("Result 2: ", rest2)
}
Jak dzielimy łańcuch w GoLang?
Łańcuchy w Go różnią się od tych w innych językach, takich jak Java, C++, Python itp. Jest to ciąg znaków o zmiennej szerokości, z których każdy jest reprezentowany przez jeden lub więcej bajtów zakodowanych w UTF-8. Za pomocą poniższych funkcji możemy podzielić ciąg na wycinek w ciągach Go. Ponieważ te funkcje są określone w pakiecie strings, musimy zaimportować pakiet strings do naszego programu, aby z nich korzystać:
Split
Ta funkcja dzieli łańcuch na wszystkie podłańcuchy oddzielone określonym separatorem i zwraca wycinek zawierający te podłańcuchy.
Składnia:
func Split(str, sep string) []string
Używany jest tutaj łańcuch str i używany jest separator sep. Jeśli str nie zawiera podanego sep, a sep nie jest puste, zwróci wycinek o długości 1, który zawiera wyłącznie str. Jeśli parametr sep pozostanie pusty, będzie dzielić po każdej sekwencji UTF-8. Alternatywnie, jeśli zarówno str, jak i sep są puste, utworzy pusty wycinek.
Przykład:
// Program to demonstrate how to split a string
package main
import (
"fmt"
"strings"
)
// the main function
func main() {
// Creating, initializing the strings
stry1 := "Welcome, to the, our channel,
Helloeveryone"
stry2 := "My dog name is Dollar"
stry3 := "I like to play Ludo"
// Displaying the strings
fmt.Println("String 1: ", stry1)
fmt.Println("String 2: ", stry2)
fmt.Println("String 3: ", stry3)
// Splitting given strings
// Using the Split() function
rest1 := strings.Split(stry1, ",")
rest2 := strings.Split(stry2, "")
rest3 := strings.Split(stry3, "!")
rest4 := strings.Split("", "Helloeveryone,
hello")
// Displaying result
fmt.Println("\nResult 1: ", rest1)
fmt.Println("Result 2: ", rest2)
fmt.Println("Result 3: ", rest3)
fmt.Println("Result 4: ", rest4)
}
SplitAfter
Dzieli ciąg na wszystkie podciągi po każdym wystąpieniu podanego separatora i zwraca wycinek zawierający te podciągi.
Składnia:
func SplitAfter(str, sep string) []string
Używany jest tutaj łańcuch str i używany jest separator sep. Jeśli str nie zawiera podanego sep, a sep nie jest puste, zwróci wycinek o długości 1, który zawiera wyłącznie str. Jeśli parametr sep pozostanie pusty, będzie dzielić po każdej sekwencji UTF-8. Alternatywnie, jeśli zarówno str, jak i sep są puste, utworzy pusty wycinek.
Przykład:
// Program to demonstrate how to split a string
package main
import (
"fmt"
"strings"
)
// the main function
func main() {
// Creating, initializing the strings
stry1 := "Welcome, to the, online session,
Helloeveryone"
stry2 := "My cat name is puffi"
stry3 := "I like to play chess"
// Displaying the strings
fmt.Println("String 1: ", stry1)
fmt.Println("String 2: ", stry2)
fmt.Println("String 3: ", stry3)
// Splitting given strings
// Using the SplitAfter() function
rest1 := strings.SplitAfter(str1, ",")
rest2 := strings.SplitAfter(str2, "")
rest3 := strings.SplitAfter(str3, "!")
rest4 := strings.SplitAfter("",
"Helloeveryone, Hello")
// Displaying result
fmt.Println("\nResult 1: ", rest1)
fmt.Println("Result 2: ", rest2)
fmt.Println("Result 3: ", rest3)
fmt.Println("Result 4: ", rest4)
}
SplitAfterN
Dzieli ciąg na wszystkie podciągi po każdym użyciu podanego separatora i zwraca wycinek zawierający te podciągi.
Składnia:
func SplitAfterN(str, sep string, m int) []string
W tym przypadku str to łańcuch, sep to separator, a m to liczba podłańcuchów do zwrócenia. Jeśli m>0, zwróci co najwyżej m podłańcuchów, przy czym końcowy podłańcuch nie zostanie podzielony. Jeśli m == zero, zwróci zero. Jeśli m<0, zwraca wszystkie podłańcuchy.
Przykład:
// Program to demonstrate how to split a string
package main
import (
"fmt"
"strings"
)
// the main function
func main() {
// Creating, initializing the strings
stry1 := "Welcome, to the, online session,
Helloeveryone"
stry2 := "My cat name is puffi"
stry3 := "I like to play chess"
// Displaying strings
fmt.Println("String 1: ", stry1)
fmt.Println("String 2: ", stry2)
fmt.Println("String 3: ", stry3)
// Splitting given strings
// Using SplitAfterN() function
rest1 := strings.SplitAfterN(stry1, ",", 2)
rest2 := strings.SplitAfterN(stry2, "", 4)
rest3 := strings.SplitAfterN(stry3, "!", 1)
rest4 := strings.SplitAfterN("",
"Helloeveryone, hello", 3)
// Displaying result
fmt.Println("\nResult 1: ", rest1)
fmt.Println("Result 2: ", rest2)
fmt.Println("Result 3: ", rest3)
fmt.Println("Result 4: ", rest4)
}
W GoLang istnieje kilka sposobów porównywania ciągów znaków. Łańcuch w Go jest niezmiennym łańcuchem dowolnych bajtów zakodowanych przy użyciu kodowania UTF-8. Mamy dwie możliwości porównywania łańcuchów znaków:
Korzystanie z operatorów porównania
Łańcuchy Go umożliwiają operatory porównania, takie jak ==, !=, >=, <=, <, >. Operatory == i != służą do określenia, czy podane łańcuchy są równe, natomiast operatory >=, <=, <, > określają kolejność leksykalną. Wyniki tych operatorów są typu Boolean, co oznacza, że warunek jest spełniony. Zwróci wartość true; w przeciwnym razie fałszywe.
Pierwszy przykład:
// Program to illustrate the concept
// of == and != operator with the strings
package main
import "fmt"
// the main function
func main() {
// Creating, initializing strings
// using the shorthand declaration
stry1 := "Hello"
stry2 := "Helo"
stry3 := "Helloeveryone"
stry4 := "Hello"
// Checking string are equal
// or not using == operator
res1 := str1 == str2
res2 := str2 == str3
res3 := str3 == str4
res4 := str1 == str4
fmt.Println("Result 1: ", res1)
fmt.Println("Result 2: ", res2)
fmt.Println("Result 3: ", res3)
fmt.Println("Result 4: ", res4)
// Checking the string are not equal
// using != operator
res5 := str1 != str2
res6 := str2 != str3
res7 := str3 != str4
res8 := str1 != str4
fmt.Println("\nResult 5: ", res5)
fmt.Println("Result 6: ", res6)
fmt.Println("Result 7: ", res7)
fmt.Println("Result 8: ", res8)
}
Drugi przykład:
// Program to illustrate concept
// of comparison operator with the strings
package main
import "fmt"
// the main function
func main() {
// Creating, initializing
// slice of string using
// the shorthand declaration
myslice := []string{"Hello", "Hello",
"hfw", "HFW", "from"}
fmt.Println("Slice: ", myslice)
// Using the comparison operator
result1 := "HFW" > "Hello"
fmt.Println("Result 1: ", result1)
result2 := "HFW" < "hello"
fmt.Println("Result 2: ", result2)
result3 := "Hello" >= "from"
fmt.Println("Result 3: ", result3)
result4 := "Hello" <= "from"
fmt.Println("Result 4: ", result4)
result5 := "Hello" == "Hello"
fmt.Println("Result 5: ", result5)
result6 := "Hello" != "from"
fmt.Println("Result 6: ", result6)
}
Korzystanie z metody Compare().
Możemy również porównać dwa ciągi znaków za pomocą wbudowanej funkcji pakietu strings Compare(). Po leksykograficznym porównaniu dwóch łańcuchów ta metoda generuje wartość całkowitą. Zwracane wartości są następujące:
Return 0, if stry1 == stry2.
Return 1, if stry1 > stry2.
Return -1, if stry1 < stry2.
Składnia:
func Compare(stry1, stry2 string) int
Przykład:
// Program to illustrate how to compare
// the string using compare() function
package main
import (
"fmt"
"strings"
)
func main() {
// Comparing string using the Compare function
fmt.Println(strings.Compare("hfw", "Hello"))
fmt.Println(strings.Compare("Helloeveryone",
"Hello"))
fmt.Println(strings.Compare("Hello", " HFW"))
fmt.Println(strings.Compare("HelLo", "HelLo"))
}
MAPY
Mapa to silna, pomysłowa i elastyczna struktura danych w języku programowania Go. Mapy w języku GoLang to zbiór par klucz-wartość, które nie są uporządkowane. Jest powszechnie używany, ponieważ umożliwia szybkie wyszukiwanie i wartości, które można pobrać, zaktualizować lub usunąć za pomocą klawiszy.
o Jest to odwołanie do tablicy skrótów.
o Przejście jest niedrogie ze względu na typ referencyjny; na przykład na procesorze 64-bitowym wymaga 8 bajtów, podczas gdy na komputerze 32-bitowym zajmuje 4 bajty.
o Klucz na mapie musi być unikalny i zawsze typu, który jest porównywany za pomocą operatora == lub typu, który obsługuje operator !=. W rezultacie większość wbudowanych typów, takich jak int, float64, rune, string, podobna tablica i struktura, wskaźnik itd., może być używana jako klucze. Typy danych, takie jak wycinki i nieporównywalne tablice i struktury oraz niestandardowe typy danych, które nie są porównywalne, nie są używane jako klucze map.
o Wartości w mapach nie są unikalne jak klucze i mogą być dowolnego typu, np. int, float64, string, rune, pointer, typ referencyjny, typ mapy itp.
o Klucze i wartości muszą być tego samego typu; różne klucze i wartości w tych samych mapach są niedozwolone. Jednak typ klucza i wartości typu mogą się różnić.
o Tablica mieszająca, mapa mieszająca, mapa nieuporządkowana, słownik lub tablica asocjacyjna to nazwy innych map.
o Możemy dodać wartość do mapy dopiero po jej zainicjowaniu. Jeśli dodamy wartość do niezainicjowanej mapy, kompilator zgłosi błąd.
Jak tworzymy i inicjalizujemy mapy?
Mapy w języku programowania Go można tworzyć i inicjalizować na dwa sposoby:
Prosty
Możemy użyć tego sposobu do skonstruowania i zainicjowania mapy bez użycia funkcji make():
1. Tworzenie mapy: Używając następującej składni, możemy łatwo stworzyć mapę:
// Empty map
map[KeyType]ValueType{}
// Map with the keyvalue pair
map[KeyType]ValueType{key1: value1, &helip;, keyN:
valueN}
Przykład:
var mymap map[int]string
Wartość zerowa mapy w mapach jest zerowa, a mapa zerowa nie zawiera żadnych kluczy. Jeśli wstawimy parę klucz-wartość do mapy nil, kompilator zgłosi błąd wykonania.
2. Używanie literałów map do inicjalizacji mapy: Literały map są najprostszym sposobem wypełnienia mapy danymi; oddziel parę klucz-wartość dwukropkiem, a ostatni końcowy dwukropek jest wymagany; w przeciwnym razie kompilator wygeneruje błąd.
Przykład:
// Program to illustrate how to
// create, initialize maps
package main
import "fmt"
func main() {
// Creating, initializing empty map
// Using the var keyword
var map_1 map[int]int
// Checking if map is nil or not
if map_1 == nil {
fmt.Println("True")
} else {
fmt.Println("False")
}
// Creating, initializing a map
// Using the shorthand declaration and
// using the map literals
map_2 := map[int]string{
90: "Duck",
91: "Cow",
92: "Cat",
93: "Bird",
94: "Boat",
}
fmt.Println("Map-2: ", map_2)
}
Korzystanie z funkcji make().
Możemy również utworzyć mapę za pomocą funkcji make(). Ta funkcja jest funkcją wbudowaną iw tej metodzie musimy przekazać typ mapy i zwrócić zainicjowaną mapę.
Składnia:
make(map[KeyType]ValueType, initial_Capacity)
make(map[KeyType]ValueType)
Przykład:
// Program to illustrate how to
// create, initialize a map
// Using the make() function
package main
import "fmt"
func main() {
// Creating map
// Using the make() function
var Mymap = make(map[float64]string)
fmt.Println(Mymap)
// As we know that make() function always
returns a map which is initialized
// we can add values in it
Mymap[1.3] = "Ridhi"
Mymap[1.5] = "Sunita"
fmt.Println(Mymap)
}
Ważne uwagi
Jak iterujemy po mapie?
Możemy użyć pętli for do iteracji po mapie. Ponieważ mapa jest zbiorem nieuporządkowanym, wartość tej pętli może się różnić.
Przykład:
// Program to illustrate how
// to iterate map using for rang loop
package main
import "fmt"
// the main function
func main() {
// Creating, initializing a map
m_a_p := map[int]string{
90: "Duck",
91: "Cow",
92: "Cat",
93: "Bird",
94: "Dog",
}
// Iterating the map using for rang loop
for id, pet := range m_a_p {
fmt.Println(id, pet)
}
}
Jak dodać pary klucz-wartość do mapy
W mapach możemy dodawać pary klucz-wartość do zainicjowanej mapy, używając następującej składni:
map-name[key]=value
Jeśli spróbujemy dodać klucz, który już istnieje na mapie, po prostu zastąpi on lub zaktualizuje wartość tego klucza nową wartością.
Przykład:
// Program to illustrate how to add
key-value pair in the map using make() function
package main
import "fmt"
// the main function
func main() {
// Creating, initializing a map
m_a_p := map[int]string{
90: "Duck",
91: "Cow",
92: "Dog",
93: "Cat",
94: "Rabbit",
}
fmt.Println("Original map: ", m_a_p)
// Adding the new key-value pairs in the map
m_a_p[95] = "Parrot"
m_a_p[96] = "Crow"
fmt.Println("Map after adding the new keyvalue
pair:\n", m_a_p)
// Updating the values of map
m_a_p[91] = "PIG"
m_a_p[93] = "MONKEY"
fmt.Println("\nMap after updating the values
of map:\n", m_a_p)
}
Jak odzyskać wartość powiązaną z kluczem na mapie
Na mapach użyj następującej składni, aby uzyskać wartość za pomocą klucza:
nazwa_mapy [klucz]
Jeśli klucz nie istnieje w danej mapie, zwróci wartość zerową, czyli zero. A jeśli klucz zostanie znaleziony na danej mapie, zwróci wartość powiązaną z tym kluczem.
Przykład:
// Program to illustrate how to
// retrieve the value of key
package main
import "fmt"
// the ain function
func main() {
// Creating, initializing a map
m_a_p := map[int]string{
90: "Duck",
91: "Cow",
92: "Cat",
93: "Dog",
94: "Rabbit",
}
fmt.Println("Original map: ", m_a_p)
// Retrieving values with help of keys
value_1 := m_a_p[91]
value_2 := m_a_p[92]
fmt.Println("Value of key[91]: ", value_1)
fmt.Println("Value of key[92]: ", value_2)
}
Jak sprawdzić, czy klucz jest obecny na mapie
W mapach możemy użyć następującej składni, aby określić, czy dany klucz istnieje, czy nie:
Składnia:
// With the value
// It will give the value, check the result
value, checkvariablename:= mapname[key]
lub
// Without the value using the blank identifier
// It will only give check result
_, checkvariablename:= mapname[key]
Jeśli wartość zmiennej checkvariablename jest prawdziwa, klucz istnieje w podanej mapie; jeśli wartość checkvariablename jest false, klucz nie istnieje w danej mapie.
Przykład:
// Program to illustrate how to
// check key is available or not
package main
import "fmt"
// the main function
func main() {
// Creating. initializing a map
m_a_p := map[int]string{
90: "Cow",
91: "Cat",
92: "Duck",
93: "Dog",
94: "Rabbit",
}
fmt.Println("Original map: ", m_a_p)
// Checking key is available
or not in the m_a_p map
pet_name, ok := m_a_p[90]
fmt.Println("\nThe Key present or not:", ok)
fmt.Println("The Value:", pet_name)
// Using the blank identifier
_, ok1 := m_a_p[92]
fmt.Println("\nThe Key present or not:", ok1)
}
Jak usunąć klucz z mapy
Metoda delete() w mapach pozwala nam usunąć klucz istniejący w mapie. Jest to wbudowana funkcja, która nie zwraca żadnej wartości i nic nie robi, jeśli klucz nie istnieje w określonej mapie. Wystarczy przekazać do tej metody mapę i klucz, który chcemy usunąć z mapy.
Składnia:
delete(mapname, key)
Przykład:
// Program to illustrate how to delete key
package main
import "fmt"
// the main function
func main() {
// Creating, initializing a map
m_a_p := map[int]string{
90: "Duck",
91: "Cow",
92: "Cat",
93: "Dog",
94: "Rabbit",
}
fmt.Println("Original map: ", m_a_p)
// Deleting keys
// Using the delete function
delete(m_a_p, 91)
delete(m_a_p, 92)
fmt.Println("Map after deletion: ", m_a_p)
}
Modyfikacja mapy
Jak wszyscy wiemy, mapy mają charakter referencyjny. W rezultacie, kiedy przypisujemy istniejącą mapę do nowej zmiennej, obie mapy odnoszą się do tej samej podstawowej struktury danych. W rezultacie, gdy zaktualizujemy jedną mapę, znajdzie to odzwierciedlenie w innej.
Przykład:
// Program to illustrate the
// modification concept in map
package main
import "fmt"
// the main function
func main() {
// Creating, initializing a map
m_a_p := map[int]string{
90: "Duck",
91: "Cow",
92: "Cat",
93: "Duck",
94: "Rabbit",
}
fmt.Println("Original map: ", m_a_p)
// Assigned map into a new variable
new_map := m_a_p
// Perform the modification in new_map
new_map[96] = "Monkey"
new_map[98] = "Donkey"
// Display after modification
fmt.Println("The New map: ", new_map)
fmt.Println("\nModification done in old
map:\n", m_a_p)
}
Funkcje i rekurencja
Przejdź do FUNKCJE JĘZYKOWE
Funkcje to często bloki kodu lub instrukcje w programie, które umożliwiają użytkownikowi ponowne użycie tego samego kodu, oszczędzając pamięć, oszczędzając czas i, co najważniejsze, poprawiając czytelność kodu. Funkcja jest w istocie zbiorem instrukcji, które wykonują dane zadanie i dostarczają wynik wywołującemu. Funkcja może również wykonać określone zadanie bez zwracania żadnych wyników.
Deklaracja funkcji
Deklaracja funkcji jest metodą konstruowania funkcji.
Składnia:
func nazwa-funkcji(Parameterlist)(Returntype){
// ciało funkcji
}
W deklaracji funkcji znajdują się:
o func: Jest to słowo kluczowe w języku programowania Go używane do definiowania funkcji.
o nazwa-funkcji: To jest nazwa funkcji.
o Lista parametrów: Określa nazwę i typ argumentów funkcji.
o Returntype: Ten parametr jest opcjonalny i zawiera typy wartości zwracanych przez funkcję. Jeśli zamierzamy użyć zwracanego typu w naszej funkcji będziemy musieli dołączyć instrukcję return
Wywoływanie funkcji
Kiedy użytkownik chce wykonać funkcję, wywołuje ją lub wywołuje. Aby skorzystać z możliwości funkcji, należy ją wywołać. Jak pokazano w poniższym przykładzie, mamy funkcję o nazwie area() z dwoma parametrami. Teraz nazywamy tę funkcję po imieniu w funkcji main, tj. area(13, 11) z dwoma parametrami.
Przykład:
// Program to illustrate
// the use of function
package main
import "fmt"
// area() is used to find
// area of rectangle
// area() function two parameters,
// i.e, length and width
func area(length, width int)int{
arr := length* width
return arr
}
// the main function
func main() {
// Display area of the rectangle
// with the method calling
fmt.Printf("Area of rectangle is : %d",
area(13, 11))
}
Argumenty funkcji
Argumenty dostarczane do funkcji nazywane są w Go parametrami rzeczywistymi, podczas gdy parametry odbierane przez funkcję nazywane są parametrami formalnymi.
Uwaga: język Go domyślnie używa techniki call by value aby przekazać parametry w funkcji.
Język programowania Go udostępnia dwie metody przekazywania parametrów do naszej funkcji.
Wywołanie według wartości
W ten sposób przekazywania parametrów wartości parametrów rzeczywistych są przekazywane do parametrów formalnych funkcji, a dwa rodzaje parametrów są przechowywane w różnych miejscach pamięci. W rezultacie wszelkie zmiany dokonane w obrębie funkcji nie znajdują odzwierciedlenia w rzeczywistych argumentach wywołujących.
Przykład:
// Program to illustrate
// the concept of call by value
package main
import "fmt"
// function which swap the values
func swap(x, y int)int{
var o int
o= x
x=y
y=o
return o
}
// the main function
func main() {
var a int = 20
var b int = 30
fmt.Printf("a = %d and b = %d", a, b)
// call by values
swap(a, b)
fmt.Printf("\n a = %d and b = %d",a, b)
}
Wywołanie przez referencje
Ponieważ zarówno parametry rzeczywiste, jak i parametry formalne odnoszą się do identycznych lokalizacji, wszelkie zmiany dokonane w ramach funkcji mają odzwierciedlenie w rzeczywistych parametrach wywołującego.
Przykład:
// Program to illustrate
// the concept of call by reference
package main
import "fmt"
// function which swap the values
func swap(x, y *int)int{
var o int
o = *x
*x = *y
*y = o
return o
}
// the main function
func main() {
var a int = 20
var b int = 10
fmt.Printf("a = %d and b = %d", a, b)
// call by reference
swap(&a, &b)
fmt.Printf("\n a = %d and b = %d", a, b)
}
FUNKCJA ZWRACAJĄCA WIELE WARTOŚCI
Instrukcja return w języku programowania Go pozwala nam zwrócić wiele wartości z funkcji. Innymi słowy, pojedyncza instrukcja return w funkcji może zwrócić wiele wartości. Zwracane wartości są tego samego typu, co parametry podane na liście parametrów.
Składnia:
func functionname(parameterlist)(returntypelist){
// code…
}
Przykład:// Program to illustrate how a
// function return the multiple values
package main
import "fmt"
// myfunc return 3 values of int type
func myfunc(x, y int)(int, int, int ){
return x - y, x * y, x + y
}
// the main Method
func main() {
// return values are assigned into different
variables
var myvar1, myvar2, myvar3 = myfunc(4, 2)
// Display-values
fmt.Printf("The Result is: %d", myvar1 )
fmt.Printf("\nThe Result is: %d", myvar2)
fmt.Printf("\nThe Result is: %d", myvar3)
}
Nadawanie nazw zwracanym wartościom
Zwracanym wartościom w języku programowania Go można nadać nazwy. Takich nazw zmiennych możemy używać również w naszym kodzie. Nie jest wymagane dołączanie instrukcji return do tych identyfikatorów, ponieważ kompilator Go rozpozna, że te zmienne muszą zostać odesłane. Nagi powrót to nazwa nadana tej formie zwrotu. Zastosowanie samego zwrotu minimalizuje redundancję w naszym programie.
Składnia:
func functionname(para1, para2 int)(name1 int, name2 int){
// code
}
name1 i name2 to nazwy zwracanych wartości, podczas gdy para1 i para2 to argumenty funkcji.
Przykład:
// illustrate how to give names to return values
package main
import "fmt"
// myfunc return 2 values of the int type
// here, return value name
// is rectangle & square
func myfunc(x, y int)( rectangle int, square int )
{
rectangle = x*y
square = x*x
return
}
func main() {
// The return values are assigned into the two
different variables
var area1, area2 = myfunc(4, 8)
// Display the values
fmt.Printf("Area of the rectangle is: %d",
area1 )
fmt.Printf("\nThe Area of the square is: %d",
area2)
}
FUNKCJE ZMIENNE
Funkcja wariadyczna to taka, która jest wywoływana ze zmienną liczbą parametrów. Innymi słowy, funkcja variadic akceptuje zero lub więcej danych wejściowych od użytkownika. fmt. Printf jest przykładem funkcji wariadycznej; wymaga jednego stałego argumentu na początku i może zaakceptować dowolną liczbę argumentów później.
Ważne notatki:
o Ostatni typ parametru w deklaracji funkcji variadic jest poprzedzony wielokropkiem, czyli (
). Oznacza to, że funkcja może być wywoływana z dowolną liczbą tego rodzaju parametrów.
Składnia:
function function-name(para1, para2...type)type{
// code
}
o W ramach funkcji
typ działa podobnie do plasterka. Załóżmy, że mamy sygnaturę funkcji, taką jak add(b…nt)int, a argument a jest typu []int.
o W funkcji variadic możesz również podać istniejący wycinek. Jak pokazano w drugim przykładzie, wysyłamy wycinek całej tablicy do funkcji, aby to zrobić.
o Gdy do funkcji variadic nie są przekazywane żadne argumenty, wycinek w obrębie funkcji jest równy zero.
o Funkcje wariacyjne są powszechnie używane do formatowania ciągów znaków.
o W metodzie variadycznej można również przekazać kilka przekrojów.
o Parametry Variadic nie mogą być używane jako wartości zwracane, chociaż mogą być zwracane jako wycinki.
Pierwszy przykład:
// Program to illustrate
// the concept of variadic function
package main
import(
"fmt"
"strings"
)
// Variadic function to join the strings
func joinstr(element...string)string{
return strings.Join(element, "-")
}
func main() {
// zero argument
fmt.Println(joinstr())
// the multiple arguments
fmt.Println(joinstr("Hello", "HEW"))
fmt.Println(joinstr("Hello", "Everyone",
"World"))
fmt.Println(joinstr("H", "E", "L", "L", "O"))
}
Drugi przykład:
// Program to illustrate
// the concept of variadic function
package main
import(
"fmt"
"strings"
)
// The Variadic function to join strings
func joinstr(element...string)string{
return strings.Join(element, "-")
}
func main() {
// pass a slice in the variadic function
element:= []string{"hello", "FROM", "world"}
fmt.Println(joinstr(element…))
}
Kiedy korzystamy z funkcji variadic:
o Funkcja variadic służy do przekazywania wycinka w funkcji.
o Używamy funkcji zmiennej, gdy nie znamy liczby parametrów.
o Kiedy używamy funkcji zmiennej w twoim oprogramowaniu, poprawia się czytelność.
Funkcje anonimowe
Funkcja anonimowa jest cechą języka programowania Go. Funkcja anonimowa nie ma nazwy, gdy musimy napisać funkcję wbudowaną. Anonimowa funkcja w Go może skonstruować zamknięcie. Funkcja anonimowa jest również określana jako literał funkcji.
Składnia:
func(parameter-list)(returntype){
// code
// Use the return statement if returntype are
given
// if returntype is not given, then do not
// use the return statement
return
}()
Przykład:
// Program to illustrate how
// to create anonymous function
package main
import "fmt"
func main() {
// the anonymous function
func(){
fmt.Println("Welcome to World")
}()
}
Ważne notatki:
o Anonimową funkcję można przypisać do zmiennej w języku programowania Go. Kiedy przypisujemy funkcję do zmiennej, typ zmiennej zmienia się na funkcję i możemy to nazwać wywołaniem funkcji, jak pokazano w poniższym przykładzie:
// Program to illustrate
// the use of an anonymous function
package main
import "fmt"
func main() {
// Assigning anonymous
// function to variable
value := func(){
fmt.Println("Welcome to World")
}
value()
}
o W funkcji anonimowej możemy również przekazywać parametry.
Przykład:
// Program to pass arguments
// in anonymous function
package main
import "fmt"func main() {
// Passing arguments in the anonymous function
func(ele string){
fmt.Println(ele)
}("Helloeveryone")
}
o Funkcja anonimowa może również zostać przekazana jako argument do innej funkcji.
Przykład:
// Program to pass an anonymous
// function as an argument into
// the other function
package main
import "fmt"
// Passing anonymous function
// as argument
func XYZ(i func(a, b string)string){
fmt.Println(i ("Hello", "for"))
}
func main() {
value:= func(a, b string) string{
return a + b + "Hello"
}
XYZ(value)
}
o Inna funkcja może również zwrócić funkcję anonimową.
Przykład:
// Program to illustrate
// the use of anonymous function
package main
import "fmt"
// Returning the anonymous function
func XYZ() func(a, b string) string{
myf := func(a, b string)string{
return a + b + "Everyone"
} return myf
}func main() {
value := XYZ()
fmt.Println(value("Hello ", "to "))
}
Funkcje GoLang main() i init().
Język programowania Go rezerwuje dwie funkcje do celów specjalnych:
main() i init().
Funkcja main()
Główny pakiet w Go to specjalny pakiet używany z aplikacjami wykonywalnymi, w tym z metodą main(). Funkcja main() jest unikalną funkcją, która służy jako punkt wejścia programu wykonywalnego. Nie przyjmuje ani nie zwraca żadnych argumentów. Go wywołuje metodę main() automatycznie, więc nie ma potrzeby jej bezpośredniego wywoływania, a każdy program wykonywalny musi mieć jeden pakiet główny i funkcję main().
Przykład:
// Program to illustrate
// the concept of main() function
// Declaration of main package
package main
// Importing packages
import (
"fmt"
"sort"
"strings"
"time"
)
// Main function
func main() {
// Sorting the given slice
st := []int{335, 79, 113, 14, 86, 12, 467, 9}
sort.Ints(st)
fmt.Println("Sorted slice: ", st)
// Finding the index
fmt.Println("Index value: ", strings.
Index("Hello", "ks"))
// Finding the time
fmt.Println("Time: ", time.Now().Unix())
}
Funkcja init()
Funkcja init(), podobnie jak funkcja main, nie przyjmuje żadnych argumentów i nic nie zwraca. Ta funkcja jest zawarta w każdym pakiecie i jest wywoływana, gdy pakiet jest ładowany po raz pierwszy. Ta funkcja jest zdefiniowana niejawnie, więc nie możemy uzyskać do niej dostępu w innym miejscu. Możemy skonstruować wiele funkcji init() w tej samej aplikacji i będą one wykonywane w kolejności, w jakiej zostały utworzone. Funkcje init() mogą być umieszczone w dowolnym miejscu programu i są wywoływane w leksykalnej kolejności nazw plików (porządek alfabetyczny). Dopuszczalne jest dołączanie instrukcji, jeśli używana jest funkcja init(), ale należy pamiętać, że metoda init() jest wykonywana przed wywołaniem funkcji main(); dlatego nie jest zależny od funkcji main(). Głównym celem funkcji init() jest inicjalizacja zmiennych globalnych, których nie można zainicjować w kontekście globalnym.
Przykład:
// Program to illustrate
// the concept of init() function
// Declaration of main package
package main
// the importing package
import "fmt"
// the multiple init() function
func init() {
fmt.Println("Welcome everyone")
}
func init() {
fmt.Println("Hello everyone ")
}
// the main function
func main() {
fmt.Println("Welcome to home")
}
Co to jest pusty identyfikator (podkreślenie) w GoLang?
W GoLang _(podkreślenie) jest określane jako pusty identyfikator. Identyfikatory to zdefiniowane przez użytkownika nazwy komponentów oprogramowania używane do identyfikacji. GoLang zapewnia funkcję, która pozwala nam zadeklarować i wykorzystać nieużywaną zmienną przy użyciu pustego identyfikatora. Nieużywane zmienne są definiowane przez użytkownika w całym programie, ale nigdy nie są przez niego wykorzystywane. Te zmienne sprawiają, że program jest prawie nieczytelny. Ponieważ GoLang jest bardziej zwięzłym i czytelnym językiem programowania, nie umożliwia programiście określenia niepotrzebnej zmiennej; jeśli to zrobimy, kompilator zgłosi błąd. Gdy funkcja zwraca kilka wartości, ale potrzebujemy tylko kilku z nich, a niektóre odrzucamy, możemy użyć pustego identyfikatora. Informuje kompilator, że ta zmienna nie jest potrzebna i może ją zignorować bez powodowania błędu. Ukrywa wartości zmiennych i czyni program zrozumiałym. W rezultacie za każdym razem, gdy podajemy wartość Identyfikatora banku, staje się on bezużyteczny.
Pierwszy przykład: W poniższym programie funkcja mul_div zwraca dwie wartości, które przechowujemy w identyfikatorach mul i div. Jednak w całym programie używamy tylko jednej zmiennej, mul. W rezultacie kompilator zgłosi błąd, jeśli element div zostanie zadeklarowany, ale nie zostanie wykorzystany.
// Program to show compiler
// throws an error if variable is
// declared but not used
package main
import "fmt"
// the main function
func main() {
// calling function
// function returns two values which are
// assigned to mul and div the identifier
mul, div := mul_div(110, 9)
// only using the mul variable
// compiler will give an error
fmt.Println("110 x 9 = ", mul)
}
// function returning the twov
// values of integer type
func mul_div(nm1 int, nm2 int) (int, int) {
// returning values
return nm1 * nm2, nm1 / nm2
}
Drugi przykład: Aby naprawić powyższy program, użyjmy Blank Identyfikator. Po prostu użyj _(podkreślenia) zamiast identyfikacji elementu div. Pozwala kompilatorowi zignorować zadeklarowany i niewykorzystany błąd dla tej konkretnej zmiennej.
// Program to the use of Blank identifier
package main
import "fmt"
// the main function
func main() {
// calling function
// function returns two values which are
// assigned to mul and blank identifier
mul, _ := mul_div(110, 8)
// only using the mul variable
fmt.Println("110 x 8 = ", mul)
}
// function returning the two
// values of integer type
func mul_div(nm1 int, nm2 int) (int, int) {
// returning the values
return nm1 * nm2, nm1 / nm2
}
Ważne notatki:
o Wiele pustych identyfikatorów może być używanych w tym samym programie. W rezultacie program GoLang może zawierać wiele zmiennych o tej samie nazwie identyfikatora, pusty identyfikator.
o Istnieje wiele sytuacji, w których wartości muszą zostać przypisane tylko po to, aby uzupełnić składnię, mimo że wartości nigdy nie będą wykorzystywane w programie. Jak w funkcji, która zwraca wiele wartości. W takich przypadkach często stosuje się pusty identyfikator.
o W przypadku pustego identyfikatora możemy wykorzystać dowolną wartość dowolnego typu.
SŁOWO KLUCZOWE DEFER
Instrukcje odroczenia w języku Go odkładają wykonanie funkcji lub metody albo metody anonimowej do czasu powrotu pobliskich funkcji. Odroczone parametry wywołania funkcji lub metody, innymi słowy, oceniają natychmiast, ale nie wykonują, dopóki nie powróci pobliska funkcja. Możemy skonstruować opóźnioną metodę, funkcję lub funkcję anonimową za pomocą słowa kluczowego defer.
Składnia:
// Function
defer func func-name(parameterlist Type)
returntype{
// Code
}
// Method
defer func (receiver Type)
methodname(parameterlist){
// Code
}
defer func (parameterlist)(returntype){
// code
}()
Ważne notatki:
o Wiele instrukcji odroczenia jest dozwolonych w tym samym programie w Go i są one wykonywane w sekwencji LIFO (Last-In, First-Out), jak pokazano w drugim przykładzie.
o Parametry instrukcji odroczenia są oceniane w momencie wykonania instrukcji odroczenia, a nie w momencie jej wywołania.
o Instrukcje odroczenia są powszechnie używane w celu zagwarantowania zamknięcia plików, gdy ich użycie nie jest już potrzebne, w celu zamknięcia kanału lub przechwycenia paniki w programie.
Zilustrujmy to pojęcie przykładem:
Pierwszy przykład:
// Program to illustrate
// the concept of the defer statement
package main
import "fmt"
// Functions
func mul(x1, x2 int) int {
rest := x1 * x2
fmt.Println("Result: ", rest)
return 0
}
func show() {
fmt.Println("Hello, Everyone")
}
// the main function
func main() {
// Calling the mul() function
// Here the mul function behaves
// like normal function
mul(43, 25)
// Calling the mul()function
// Using defer keyword
// Here mul() function
// is defer function
defer mul(27, 46)
// Calling show() function
show()
}
Objaśnienie: W powyższym przykładzie istnieją dwie metody o nazwach mul() i show() (). Podczas gdy funkcja show() jest zwykle wywoływana w funkcji main(), funkcja mul() jest wywoływana na dwa sposoby:
Najpierw wywołujemy funkcję mul normalnie (bez słowa kluczowego defer), tj. mul(43, 25), i jest ona wykonywana, gdy funkcja jest wywoływana. Po drugie, używamy słowa kluczowego defer, aby odnieść się do funkcji mul() jako funkcji odroczonej, tj. defer odrocz mul(27, 46) i wykonuje się, gdy wszystkie otaczające metody powrócą.
Drugi przykład:
// Program to illustrate
// the multiple defer statements, to illustrate
LIFO policy
package main
import "fmt"
// Functions
func add(x1, x2 int) int {
rest := x1 + x2
fmt.Println("Result: ", rest)
return 0
}
// the main function
func main() {
fmt.Println("Starting")
// Multiple defer statements
// Executes in the LIFO order
defer fmt.Println("Ending")
defer add(37, 59)
defer add(12, 12)
}
PANIC w GoLang
Panic, podobnie jak wyjątek, pojawia się podczas wykonywania w języku programowania G. Innymi słowy, panika pojawia się, gdy w programie Go wystąpi nieoczekiwana okoliczność, powodująca przerwanie wykonywania programu. Czasami panika pojawia się w czasie wykonywania, gdy pojawia się określony warunek, taki jak dostęp do tablicy poza zakresem, jak pokazano w pierwszym przykładzie, a innym razem jest to celowo rzucane przez programistę, aby obsłużyć najgorszy scenariusz w programie Go za pomocą panika(), jak pokazano w drugim przykładzie. Funkcja paniki jest nieodłączną funkcją zdefiniowaną we wbudowanym pakiecie języka Go. Ta funkcja zatrzymuje przepływ kontroli i zaczyna panikować.
Składnia:
func panic(v interface{})
Jest w stanie zaakceptować każdy rodzaj argumentacji. Gdy w programie Go wystąpi panika, program zatrzymuje się w czasie wykonywania, a na ekranie wyjściowym wyświetlany jest komunikat o błędzie i ślad stosu aż do punktu, w którym wystąpiła panika. Ogólnie rzecz biorąc, kiedy w programie Go pojawia się panika, program nie kończy się natychmiast; zamiast tego kończy się, gdy Go zakończy wszystkie oczekujące prace dla tego programu. Na przykład, jeśli funkcja A wywołuje panikę, wykonywanie funkcji A zostaje zatrzymane, a jeśli w A dostępne są jakieś opóźnione funkcje, działają one normalnie. Następnie funkcja A powraca do swojego wywołującego, a A zachowuje się jak wywołanie paniki do dzwoniącego. Jak widać w trzecim przykładzie, ta procedura jest kontynuowana, dopóki nie zostaną zwrócone wszystkie funkcje w bieżącym goroutine, kiedy to program kończy się niepowodzeniem.
Pierwszy przykład:
// Program which illustrates the
// concept of panic
package main
import "fmt"
// the main function
func main() {
// Creating array of string type
// Using the var keyword
var myarr [3]string
// Elements are assigned using an index
myarr[0] = "HE"
myarr[1] = "Helloeveryone"
myarr[2] = "Hello"
// Accessing elements
// of the array
// Using the index value
fmt.Println("The Elements of Array:")
fmt.Println("The Element 1: ", myarr[0])
// Program panics because the
// size of the array is 3
// we try to access
// the index 5 which is not
// available in current array,
// it gives an runtime error
fmt.Println("The Element 2: ", myarr[5])
}
Drugi przykład:
// Program which illustrates
// how to create own panic
// Using the panic function
package main
import "fmt"
// Function
func entry(lang *string, aname *string) {
// When value of lang
// is nil it will panic
if lang == nil {
panic("Error: The Language cannot be nil")
}
// When value of aname
// is nil it will panic
if aname == nil {
panic("Error: The Author name cannot be
nil")
}
// When values of the lang and aname
// are non-nil values it will print
// the normal output
fmt.Printf("The Author Language: %s \n Author
Name: %s\n", *lang, *aname)
}
// the main function
func main() {
A_lang := "GO-Language"
// Here in the entry function, we pass
// a non-nil, nil values
// Due to nil value this method panics
entry(&A_lang, nil)
}
Trzeci przykład:
// Program which illustrates
// the concept of Defer while panicking
package main
import (
"fmt"
)
// Function
func entry(lang *string, aname *string) {
// the Defer statement
defer fmt.Println("The Defer statement in the
entry function")
// When value of lang
// is nil it will panic
if lang == nil {
panic("Error: The Language cannot be nil")
}
// When value of aname
// is nil it will panic
if aname == nil {
panic("Error: The Author name cannot be
nil")
}
// When values of the lang and aname
// are non-nil values it will
// print the normal output
fmt.Printf("The Author Language: %s \n Author
Name: %s\n", *lang, *aname)
}
// the main function
func main() {
A_lang := "GO-Language"
// the Defer statement
defer fmt.Println("the Defer statement in the
main function")
// in entry function, we pass
// one non-nil and one-nil value
// Due to nil value this method panics
entry(&A_lang, nil)
}
Zauważ, że instrukcja lub funkcja Defer jest wykonywana zawsze, nawet jeśli program panikuje.
Użycie panic<
o Możemy użyć paniki, aby wskazać nienaprawialny błąd, w wyniku którego program nie może kontynuować działania.
o Jeśli chcemy, aby w naszym programie pojawił się błąd w określonych okolicznościach, możemy użyć panic.
ODZYSKIWANIE
Podobnie jak bloki try/catch w językach takich jak Java, C# i inne są używane do przechwytywania wyjątków, funkcja recovery w Go służy do obsługi paniki. Jest to wbudowana funkcja zdefiniowana we wbudowanym pakiecie języka Go. Ta metoda jest używana głównie do odzyskania kontroli nad spanikowanym goroutine. Innymi słowy, zajmuje się panicznym zachowaniem goroutine.
Składnia:
func recover() interface{}
Szybkie punkty
o Funkcja odzyskiwania jest zawsze wywoływana w ramach funkcji opóźnionej, a nigdy w funkcji zwykłej. Używając funkcji odzyskiwania z normalnej funkcji lub poza funkcją opóźnioną, sekwencja paniki jest kontynuowana, jak pokazano w pierwszym przykładzie. Jak pokazano w drugim przykładzie, funkcja odzyskiwania jest zawsze wywoływana wewnątrz funkcji odroczonej, ponieważ funkcja odroczona nie zatrzymuje swojego wykonywania, jeśli program panikuje, więc funkcja odzyskiwania zatrzymuje sekwencję paniki, po prostu przywracając normalne wykonanie goroutine i pobierając przekazaną wartość błędu na panikę.
o Funkcja przywracania będzie działać tylko wtedy, gdy wywołamy ją w tym samym trybie, w którym wystąpiła panika. Nie zadziała tak, jak pokazano w trzecim przykładzie, jeśli wywołamy go w oddzielnej goroutine.
o Jeśli chcemy znaleźć ślad stosu, skorzystajmy z metody PrintStack z pakietu Debug.
Pierwszy przykład:
// Program which illustrates
// the concept of recover
package main
import "fmt"
// This function is created to handle
panic occurs in entry function
// but it does not handle panic
occurred in entry function
// because it called in normal
function
func handlepanic() {
if a := recover(); a != nil {
fmt.Println("RECOVER", a)
}
}
// Function
func entry(lang *string, aname *string) {
// Normal function
handlepanic()
// When value of lang
// is nil it will panic
if lang == nil {
panic("Error: Language cannot be nil")
}
// When value of aname
// is nil it will panic
if aname == nil {
panic("Error: Author name cannot be nil")
}
fmt.Printf("The Author Language: %s \n Author
Name: %s\n", *lang, *aname)
fmt.Printf("Return successfully from entry
function")
}
// The main function
func main() {
A_lang := "GO Language"
entry(&A_lang, nil)
fmt.Printf("Return successfully from the main
function")
}
ZAMKNIĘCIE
Funkcja anonimowa jest cechą języka programowania Go. Anonimowa funkcja może stanowić zamknięcie. Zamknięcie jest rodzajem anonimowej funkcji, która odwołuje się do zmiennych określonych poza funkcją. Jest to analogiczne do dostępu do zmiennych globalnych dostępnych przed deklaracją funkcji.
Przykład:
// Program to illustrate how
// to create Closure
package main
import "fmt"
func main() {
// Declaring variable
HFW := 0
// Assigning an anonymous
// function to variable
counter := func() int {
HFW += 1
return HFW
}
fmt.Println(counter())
fmt.Println(counter())
}
Objaśnienie: Zmienna HFW nie została przekazana jako argument funkcji anonimowej, ale jest dostępna dla tej funkcji. Ten przykład ma niewielki problem, ponieważ każda inna funkcja określona w main musi mieć dostęp do zmiennej globalnej HFW i może ją aktualizować bez wywoływania funkcji licznika. W rezultacie zamknięcie zapewnia również inną korzyść: izolację danych.
// Program to illustrate how
// to create the data isolation
package main
import "fmt"
// newCounter function to
// isolate the global variable
func newCounter() func() int {
HFW := 0
return func() int {
HFW += 1
return HFW
}
}
func main() {
// newCounter function is assigned to a
variable
counter := newCounter()
// invoke the counter
fmt.Println(counter())
// invoke the counter
fmt.Println(counter())
}
Objaśnienie: Zamknięcie odwołuje się do zmiennej HFW nawet po zakończeniu funkcji newCounter(), ale żaden inny kod poza metodą newCounter() nie ma do niej dostępu. W ten sposób utrzymywana jest trwałość danych w wywołaniach funkcji, jednocześnie izolując dane z innych programów.
REKURENCJA
Rekurencja to proces, w którym funkcja wywołuje samą siebie, niejawnie lub jawnie, a powiązana funkcja jest znana jako funkcja rekurencyjna. Funkcja anonimowa jest szczególną cechą języka programowania Go. Jest to funkcja, która nie ma nazwy. Służy do tworzenia funkcji wbudowanej. Można również określić i zdefiniować anonimowe funkcje rekurencyjne. Rekurencyjne funkcje anonimowe są również określane jako literały funkcji rekurencyjnych.
Składnia
func(parameterlist)(returntype){
// code
// call the same function
// within function for recursion
// Use the return statement only
// if return-type are given.
return
}()
Pierwszy przykład :
// Program to show
// how to create recursive
// Anonymous function
package main
import "fmt"
func main() {
// Anonymous function
var recursiveAnonymous func()
recursiveAnonymous = func() {
// Printing message to show
// the function call and iteration.
fmt.Println("The Anonymous functions could
be recursive.")
// Calling the same function
recursively
recursiveAnonymous()
}
// the main calling of function
recursiveAnonymous()
}
Drugi przykład:
// Program to show
// how to create recursive
// Anonymous function
package main
import (
"fmt"
)
func main() {
// the Anonymous function
var recursiveAnonymous func(int)
// Passing arguments to Anonymous function
recursiveAnonymous = func(variable int) {
// Checking condition to return
if variable == -1 {
fmt.Println("Welcome to our Channel")
return
} else {
fmt.Println(variable)
// Calling the same
// function recursively
recursiveAnonymous(variable - 1)
}
}
// the main calling
// of function
recursiveAnonymous(10)
}
Typy rekurencji
Istnieje kilka odmian rekurencji, co ilustrują poniższe przykłady.
Bezpośrednia rekurencja
Rekurencja bezpośrednia to rodzaj rekurencji, w której funkcja wywołuje samą siebie bezpośrednio, bez pomocy innej funkcji. Poniższy przykład ilustruje koncepcję bezpośredniej rekurencji:
// Program to illustrate
// the concept of direct recursion
package main
import (
"fmt"
)
// the recursive function for
// calculating factorial of a positive integer
func factorial_calc(number int) int {
// this is base condition
// if number is 0 or 1 the function will return 1
if number == 0 || number == 1 {
return 1
}
// if the negative argument is
// given, it prints error message & returns -1
if number < 0 {
fmt.Println("Invalid-number")
return -1
}
// the recursive call to itself with argument
decremented
// by 1 integer so that it
// eventually reaches base case
return number*factorial_calc(number - 1)
}
// main function
func main() {
// passing 0 as a parameter
answer1 := factorial_calc(0)
fmt.Println(answer1, "\n")
// passing a positive integer
answer2 := factorial_calc(5)
fmt.Println(answer2, "\n")
// passing negative integer
// prints error message
// with return value of -1
answer3 := factorial_calc(-1)
fmt.Println(answer3, "\n")
// passing positive integer
answer4 := factorial_calc(10)
fmt.Println(answer4, "\n")
}
Rekurencja pośrednia
Rekurencja pośrednia to rodzaj rekurencji, w której funkcja wywołuje inną funkcję, która następnie wywołuje funkcję wywołującą. Inna funkcja służy do wspomagania tej formy rekurencji. Funkcja wywołuje samą siebie, ale robi to pośrednio za pośrednictwem innej funkcji. Poniższy przykład ilustruje koncepcję rekurencji pośredniej:
// Program to illustrate
// the concept of indirect recursion
package main
import (
"fmt"
)
// the recursive function for printing all numbers
// upto number x
func print_one(x int) {
// if number is positive
// print the number
// call second function
if x >= 0 {
fmt.Println("In first function:", x)
// call to the second function
// which calls this first
// function indirectly
print_two(x - 1)
}
}
func print_two(x int) {
// if number is positive
// print the number, call second function
if x >= 0 {
fmt.Println("In second function:", x)
// call to first function
print_one(x - 1)
}
}
// main function
func main() {
// passing positive
// parameter which prints all
// the numbers from 1 - 10
print_one(10)
// this will not print anything as it does not
// follow base case
print_one(-1)
}
Uwaga: Rekurencja wzajemna odnosi się do rekurencji pośredniej z tylko dwiema funkcjami. Aby wspomóc rekurencję pośrednią, może istnieć więcej niż dwie funkcje.
Rekurencja ogona
Wywołanie ogona to wywołanie podprogramu, które jest ostatnim lub ostatnim wywołaniem funkcji. Kiedy wywołanie ogona ponownie wywołuje tę samą funkcję, mówi się, że funkcja jest rekurencyjna ogona. Wywołanie rekurencyjne jest ostatnią czynnością wykonywaną przez funkcję w tym przypadku.
Przykład:
// Program to illustrate
// the concept of tail recursion
package main
import (
"fmt"
)
// the tail recursive function
// to print all the numbers
// from x to 1
func print_num(x int) {
// if number is still
// positive, print it
// and call the function
// with decremented value
if x > 0 {
fmt.Println(x)
// last statement in
// the recursive function
// tail recursive call
print_num(x-1)
}
}
// the main function
func main() {
// passing positive
// number, prints 5 to 1
print_num(5)
}
Rekurencja głowy
Wywołanie rekurencyjne jest początkową instrukcją w funkcji w rekurencji głowy. Nie ma żadnych dalszych instrukcji ani operacji poprzedzających wywołanie. Funkcja nie musi niczego przetwarzać po wywołaniu, a wszystkie operacje są zakończone po powrocie.
Przykład:
// Program to illustrate
// the concept of head recursion
package main
import (
"fmt"
)
// the head recursive function
// to print all the numbers
// from 1 to x
func print_num(x int) {
// if the number is still
// less than x, call
// function with decremented value
if x > 0 {
// the first statement in function
print_num(x-1)
// printing is done at
// the returning time
fmt.Println(x)
}
}
// the main function
func main() {
// passing positive
// number, prints 5 to 1
print_num(5)
}
Uwaga: Warto zauważyć, że wynik rekurencji głowy jest dokładnie odwrotny do wyniku rekurencji ogona. Dzieje się tak dlatego, że w rekurencji ogonowej funkcja najpierw wypisuje liczbę, a następnie wywołuje samą siebie, ale w rekurencji czołowej funkcja wywołuje samą siebie, dopóki nie osiągnie przypadku podstawowego, a następnie rozpoczyna drukowanie podczas powrotu.
Nieskończona rekurencja
Wszystkie funkcje rekurencyjne były określonymi lub skończonymi funkcjami rekurencyjnymi, co oznacza, że kończyły się, gdy osiągnęły warunek podstawowy. Rekurencja nieskończona to rekurencja, która nigdy nie jest zbieżna do przypadku podstawowego i trwa w nieskończoność. To często prowadzi do awarii systemu lub wycieków pamięci.
Przykład:
// Program to illustrate
// the concept of infinite recursion
package main
import (
"fmt"
)
// infinite-recursion function
func print_hello() {
// printing infinite-times
fmt.Println("Helloeveryone")
print_hello()
}
// the main function
func main() {
// call to infinite recursive-function
print_hello()
}
Rekurencja funkcji anonimowej
W GoLang istnieje koncepcja znana jako funkcje, które nie mają nazwy. Są to tak zwane funkcje anonimowe. Anonimowe funkcje w GoLang mogą być również używane do rekurencji, jak widać w poniższych przykładach.
Pierwszy przykład:
// Program to illustrate
// the concept of anonymous function recursion
package main
import (
"fmt"
)
// main function
func main() {
// declaring anonymous function
// that takes integer value
var anon_func func(int)
// defining the anonymous
// function that prints the numbers from x to 1
anon_func = func(number int) {
// the base case
if number == 0 {
return
} else {
fmt.Println(number)
// calling anonymous function
recursively
anon_func(number-1)
}
}
// call to anonymous recursive function
anon_func(5)
}
Drugi przykład:
// Program which illustrates the
// concept of recover
package main
import (
"fmt"
)
// This function handles panic
// occur in the entry function
// with help of the recover function
func handlepanic() {
if x := recover(); x != nil {
fmt.Println("RECOVER", x)
}
}
// Function
func entry(lang *string, aname *string) {
// the Deferred function
defer handlepanic()
// When value of lang is nil it will panic
if lang == nil {
panic("Error: The Language cannot be nil")
}
// When value of aname
// is nil it will panic
if aname == nil {
panic("Error: The Author name cannot be
nil")
}
fmt.Printf("The Author Language: %s \n Author
Name: %s\n", *lang, *aname)
fmt.Printf("The Return successfully from entry
function")
}
// the main function
func main() {
A_lang := "GO-Language"
entry(&A_lang, nil)
fmt.Printf("The Return successfully from main
function")
}
Trzeci przykład
// Program which illustrates
// the recover in a goroutine
package main
import (
"fmt"
"time"
)
// For the recovery
func handlepanic() {
if x := recover(); x != nil {
fmt.Println("RECOVER", x)
}
}
/* Here, this panic is not handled by recover
function because of recover function is not
called in the same goroutine in which
panic occurs */
// the Function 1
func myfun1() {
defer handlepanic()
fmt.Println("Welcome to the Function1")
go myfun2()
time.Sleep(10 * time.Second)
}
// the Function 2
func myfun2() {
fmt.Println("Welcome to Function2")
panic("Panicked!!")
}
// the main function
func main() {
myfun1()
fmt.Println("The Return successfully from main
function")
}
Wskaźniki
WSKAŹNIKI GoLang
Wskaźniki to zmienne w języku programowania Go lub GoLang używane do przechowywania adresu pamięci innej zmiennej. Wskaźniki są również znane jako zmienne specjalne w GoLangu. Zmienne służą do przechowywania danych w systemie pod określonym adresem pamięci. Adresy pamięci są zawsze w formacie szesnastkowym (zaczynając od 0x jak 0xFFAAF itd.).
Jaki jest cel wskaźnika?
Aby zrozumieć tę potrzebę, musimy najpierw zrozumieć ideę zmiennych. Zmienne to nazwy przypisane do lokalizacji pamięci, w których przechowywane są rzeczywiste dane. Aby odzyskać zapisane dane, musimy znać adres tej konkretnej lokalizacji pamięci. Ręczne zapamiętywanie wszystkich lokalizacji pamięci (format szesnastkowy) jest narzutem, dlatego używamy zmiennych do przechowywania danych, a zmienne można pobrać po prostu za pomocą ich nazwy. GoLang pozwala nam również zapisać liczbę szesnastkową do zmiennej przy użyciu wyrażenia dosłownego, co oznacza, że każda liczba zaczynająca się od 0x jest liczbą szesnastkową.
Przykład: W poniższym programie zapisujemy liczbę szesnastkową w zmiennej. Widzimy jednak, że typem wartości jest int i jest ona zapisywana jako wartość dziesiętna lub możemy powiedzieć, że przechowywana jest wartość dziesiętna typu int. Ale istotą tego przykładu jest to, że przechowujemy wartość szesnastkową, ale nie jest to wskaźnik, ponieważ nie odnosi się do miejsca w pamięci innej zmiennej. Jest to po prostu zmienna określona przez użytkownika. W rezultacie wymagane są wskaźniki.
// Program to demonstrate the variables
// storing hexadecimal values
package main
import "fmt"
func main() {
// storing hexadecimal
// values in the variables
c := 0xFF
d := 0x9C
// Displaying values
fmt.Printf("The Type of variable x is %T\n", c)
fmt.Printf("The Value of x in hexadecimal is
%X\n", c)
fmt.Printf("The Value of x in decimal is
%v\n", c)
fmt.Printf("The Type of variable y is %T\n", d)
fmt.Printf("The Value of y in hexadecimal is
%X\n", d)
fmt.Printf("The Value of y in decimal is
%v\n", d)
}
Wskaźnik jest rodzajem zmiennej, która zawiera adresy pamięci innych zmiennych i punktów, w których znajduje się pamięć, oraz podaje metody określania wartości przechowywanej w tej lokalizacji pamięci. Czasami jest określany jako specjalny typ zmiennej, ponieważ jest praktycznie dokładnie określony jako zmienna, ale z * (operator dereferencji).
Deklaracja i inicjalizacja wskaźników
Zanim zaczniemy, we wskaźnikach użyjemy dwóch kluczowych operatorów, a mianowicie:
o Operator dereferencji "*", powszechnie znany jako operator zmiennej wskaźnika, służy do definiowania zmiennej wskaźnika i uzyskiwania dostępu do wartości zawartej w adresie.
o Operator &, znany również jako operator adresu, służy do zwracania adresu zmiennej lub pobierania adresu zmiennej za pomocą wskaźnika.
Deklarowanie wskaźnika
var pointername *Data_Type
Jako przykład rozważmy następujący wskaźnik łańcuchowy, który może zawierać tylko adresy pamięci zmiennych łańcuchowych.
var st *string
Inicjalizacja wskaźnika
Aby to zrobić, użyj operatora adresu, aby zainicjować wskaźnik adresem pamięci innej zmiennej, jak pokazano w poniższym przykładzie:
// the normal variable declaration
var x = 45
// Initialization of pointer st with
// the memory address of variable x
var st *int = &x
Przykład:
// program to demonstrate declaration and
// initialization of pointers
package main
import "fmt"
func main() {
// taking normal variable
var a int = 4798
// the declaration of pointer
var b *int
// the initialization of pointer
b = &a
// displaying result
fmt.Println("The Value stored in a = ", a)
fmt.Println("The Address of a = ", &a)
fmt.Println("The Value stored in variable b =
", b)
}
Ważne uwagi
1. Wartość domyślna lub zerowa wskaźnika to zawsze zero. Alternatywnie, niezainicjowany wskaźnik zawsze będzie miał wartość zero.
Przykład:
// Program to demonstrate the
// nil value of the pointer
package main
import "fmt"
func main() {
// taking pointer
var st *int
// displaying result
fmt.Println("st = ", st)
}
2. Deklarację i inicjalizację wskaźników można wykonać w jednej linii.
Przykład:
var st *int = &x
3. Jeśli oprócz deklaracji wskaźnika wymienimy typ danych, wskaźnik będzie w stanie obsłużyć lokalizację pamięci określonej zmiennej typu danych. Na przykład, jeśli weźmiemy wskaźnik typu łańcuchowego, adres zmiennej, którą podamy wskaźnikowi, będzie tylko zmienną typu danych łańcuchowych, a nie jakiegokolwiek innego rodzaju.
4. Aby uniknąć powyższego problemu, możemy skorzystać z koncepcji wnioskowania o typie słowa kluczowego var. Typ danych nie musi być określony podczas deklaracji. Kompilator może określić typ zmiennej wskaźnika w taki sam sposób, jak typ zwykłej zmiennej. W tym przypadku nie będziemy używać operatora *. Zostanie on określony wewnętrznie przez kompilator, gdy inicjujemy zmienną przy użyciu adresu innej zmiennej.
Przykład :
// Program to demonstrate the
// use of type inference in
// the pointer variables
package main
import "fmt"
func main() {
// using the var keyword
// we are not defining any type with the
variable
var x = 328
// taking pointer variable using
// the var keyword without specifying the type
var a = &x
fmt.Println("The Value stored in x = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer
variable a = ", a)
}
5. Możemy alternatywnie zdefiniować i zainicjować zmienne wskaźnikowe używając składni skróconej (:=). Jeśli przekażemy jej adres zmiennej za pomocą operatora &(address), kompilator wewnętrznie określi zmienną wskaźnika.
Przykład:
// program to demonstrate the
// use of shorthand syntax in Pointer variables
package main
import "fmt"
func main() {
// using the := operator to declare and
// initialize the variable
x := 328
// taking pointer variable using
// := by assigning it with
// the address of variable y
a := &x
fmt.Println("The Value stored in x = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer
variable a = ", a)
}
Wskaźnik dereferencji
Operator * jest również znany jako operator dereferencji. Służy nie tylko do określania zmiennej wskaźnikowej, ale także do uzyskiwania dostępu do wartości zmiennej, na którą wskazuje wskaźnik, w procesie znanym jako pośrednie lub dereferencyjne. Wartość w lokalizacji jest czasami nazywana operatorem *. Spójrzmy na przykład, który pomoże nam zrozumieć to pojęcie:
// Program to illustrate
// the concept of dereferencing a pointer
package main
import "fmt"
func main() {
// using the var keyword
// we are not defining any type with the variable
var x = 328
// taking pointer variable using
// the var keyword without specifying the type
var a = &x
fmt.Println("The Value stored in x = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer variable
a = ", a)
// this is dereferencing a pointer
// using * operator before the pointer
// variable to access value stored at the variable
at which it is pointing
fmt.Println("The Value stored in y(*a) = ", *a)
}
Zamiast przypisywać zmiennej nową wartość, możemy zmienić wartość wskaźnika lub miejsca w pamięci.
Przykład :
// Program to illustrate the above mentioned
concept
package main
import "fmt"
func main() {
// using the var keyword
// we are not defining any type with the variable
var x = 458
// taking pointer variable using
// the var keyword without specifying the type
var a = &x
fmt.Println("The Value stored in y before
changing = ", x)
fmt.Println("The Address of x = ", &x)
fmt.Println("The Value stored in pointer
variable a = ", a)
// this is dereferencing pointer
// using the * operator before pointer
// variable to access value stored at the
variable at which it is pointing
fmt.Println("The Value stored in x(*a) Before
Changing = ", *a)
// changing the value of x by assigning
// the new value to the pointer
*a = 500
fmt.Println("Value stored in x(*a) after
Changing = ",x)
}
Jak w GoLangu możemy utworzyć instancję struct za pomocą nowego słowa kluczowego?
Struct służy głównie jako kontener dla wszystkich innych typów danych. Możemy łatwo manipulować/uzyskiwać dostęp do danych przydzielonych do struktury, wykorzystując odwołanie do struktury. W GoLangu możemy utworzyć strukturę za pomocą słowa kluczowego new oraz operatora adresu wskaźnika, jak pokazano w poniższym przykładzie.
Przykład: W tym przypadku widzimy, że tworzymy instancję struktury za pomocą słowa kluczowego new.
// Program to show how to instantiate struct
// using new keyword
package main
import "fmt"
type emp struct {
name string
empid int
salary int
}
func main() {
// emp1 is a pointer to an instance of emp
// using the new keyword
emp1 := new(emp)
emp1.name = "ABC"
emp1.empid = 2325
emp1.salary = 37000
fmt.Println(emp1)
// emp2 is an instance of emp
var emp2 = new(emp)
emp2.name = "XYZ"
emp2.salary = 40000
fmt.Println(emp2)
}
WSKAŹNIKI DO FUNKCJI
Wskaźniki to zmienne w języku programowania Go lub GoLang używane do przechowywania adresu pamięci innej zmiennej. Możemy również przekazywać wskaźniki do funkcji w taki sam sposób jak zmienne. Można to osiągnąć na dwa sposoby.
Utwórz wskaźnik i przekaż go do funkcji
W poniższym programie używamy funkcji ptf z parametrem wskaźnika typu całkowitego, instruując funkcję, aby akceptowała tylko argumenty typu wskaźnika. Ta funkcja zasadniczo zmodyfikowała wartość zmiennej y. Na początku y ma wartość 200. Jednak po wywołaniu funkcji wartość zmieniła się na 638, co widać na wyjściu.
// Program to create a pointer and
// passing it to the function
package main
import "fmt"
// taking function with integer
// the type pointer as an parameter
func ptf(b *int) {
// dereferencing
*b = 638
}
// the main function
func main() {
// taking normal variable
var y = 200
fmt.Printf("Value of y before function call
is: %d\n", y)
// taking pointer variable and
// assigning the address
// of y to it
var pb *int = &y
// calling tfunction by
// passing the pointer to function
ptf(pb)
fmt.Printf("Value of y after function call is:
%d\n", y)
}
Przekazywanie adresu zmiennej do wywołania funkcji
W poniższym programie nie tworzymy wskaźnika do przechowywania adresu zmiennej y, jak to zrobiliśmy w poprzednim programie. Bezpośrednio przekazujemy adres y do wywołania funkcji, które działa w taki sam sposób, jak wcześniej podany sposób.
// Program to create a pointer and
// passing address of the variable to the function
package main
import "fmt"
// taking function with integer
// the type pointer as an parameter
func ptf(b *int) {
// dereferencing
*b = 638
}
// the main function
func main() {
// taking normal variable
var y = 200
fmt.Printf("Value of y before function call is:
%d\n", y)
// calling the function by
// passing address of
// the variable y
ptf(&y)
fmt.Printf("Value of y after function call is:
%d\n", y)
}
Uwaga: Zmienne i wskaźniki w poprzednich programach można również deklarować za pomocą operatora krótkiej deklaracji (:=).
WSKAŹNIK DO STRUKTURY
Wskaźnik to zmienna przechowująca adres pamięci innej zmiennej. Wskaźniki są również znane jako zmienne specjalne w GoLangu. Zmienne służą do przechowywania danych w systemie pod określonym adresem pamięci. Można również użyć wskaźnika do struktury. W GoLang struktura jest typem zdefiniowanym przez użytkownika, który pozwala nam grupować/łączyć elementy możliwie różnych rodzajów w jeden typ. Aby użyć wskaźnika do struktury, użyj operatora &, znanego również jako operator adresu. GoLang pozwala programistom używać wskaźników do uzyskiwania dostępu do pól struktury bez jawnego dereferencji.
Pierwszy przykład: Stworzymy strukturę o nazwie Pracownik, która zawiera dwie zmienne. Utwórz instancję struktury, tj. emp, w funkcji main. Następnie możemy wysłać adres struktury do wskaźnika, który reprezentuje wskaźnik do idei struktury. Nie ma potrzeby jawnego używania dereferencji, ponieważ zapewni to taki sam efekt, jak pokazano w następującym programie:
// Program to illustrate
// the concept of the Pointer to struct
package main
import "fmt"
// taking structure
type Employee struct {
// taking the variables
name string
empid int
}
// the main Function
func main() {
// creating instance of the Employee struct type
emp := Employee{"XYZ", 17028}
// Here, it is the pointer to struct
pts := &emp
fmt.Println(pts)
// accessing struct fields using pointer
// but here we are not using
// the dereferencing explicitly
fmt.Println(pts.name)
// same as above by explicitly using the
// dereferencing concept means
// the result will be the same
fmt.Println((*pts).name)
}
Drugi przykład: możemy również użyć wskaźnika do zmiany wartości elementów struktury lub literałów struktury, jak widać w poniższym programie:
// Program to illustrate
// the concept of Pointer to struct
package main
import "fmt"
// taking structure
type Employee struct {
// taking the variables
name string
empid int
}
// the main Function
func main() {
// creating instance of the
// Employee struct type
emp := Employee{"XYZ", 12038}
// Here, it is the pointer to struct
pts := &emp
// displaying values
fmt.Println(pts)
// updating value of name
pts.name = "ABC"
fmt.Println(pts)
}
WSKAŹNIK DO WSKAŹNIKA (PODWÓJNY WSKAŹNIK) W Go
Wskaźniki to zmienne w języku programowania Go lub GoLang używane do przechowywania adresu pamięci innej zmiennej. Ponieważ wskaźnik jest zmienną specjalną, może wskazywać na dowolną zmienną, nawet na inny wskaźnik. Zasadniczo wydaje się, że jest to łańcuch wskaźników. Kiedy definiujemy wskaźnik do wskaźnika, pierwszy wskaźnik przechowuje adres drugiego wskaźnika. Podwójne wskaźniki to inna nazwa tej koncepcji.
Jak zadeklarować wskaźnik do wskaźnika
Deklarowanie wskaźnika do wskaźnika jest tym samym, co deklarowanie wskaźnika w Go. Różnica polega na tym, że przed nazwą wskaźnika musimy umieścić dodatkowe "*". Zwykle dzieje się tak, gdy deklarujemy zmienną wskaźnika za pomocą słowa kluczowego var i typu. Poniższe przykłady i ilustracje znacznie lepiej zilustrują tę koncepcję. Pierwszy przykład: W poniższym programie wskaźnik pt2 zapisuje położenie wskaźnika pt1. Dereferencja pt2, tj. *pt2, zwraca adres zmiennej V lub wartość wskaźnika pt1. Jeśli spróbujemy **pt2, otrzymasz wartość zmiennej V, która wynosi 200.
// Program to illustrate
// the concept of the Pointer to Pointer
package main
import "fmt"
// the main Function
func main() {
// taking variable
// of the integer type
var V int = 200
// taking a pointer
// of integer type
var pt1 *int = &V
// taking pointer to
// pointer to pt1
// storing the address
// of pt1 into pt2
var pt2 **int = &pt1
fmt.Println("Value of Variable V is = ", V)
fmt.Println("The Address of variable V is = ",
&V)
fmt.Println("Value of pt1 is = ", pt1)
fmt.Println("The Address of pt1 is = ", &pt1)
fmt.Println("Value of pt2 is = ", pt2)
// Dereferencing pointer to pointer
fmt.Println("The Value at the address of pt2
is or *pt2 = ", *pt2)
// double pointer will give the value of
variable V
fmt.Println("*(The Value at the address of pt2
is) or **pt2 = ", **pt2)
}
Drugi przykład: Wprowadźmy pewne zmiany w poprzednim programie. Przypisywanie nowej wartości do wskaźników poprzez modyfikację ich wartości za pomocą dereferencji, jak widać w poniższym programie:
// Program to illustrate
// the concept of Pointer to Pointer
package main
import "fmt"
// the main Function
func main() {
// taking variable
// of the integer type
var v int = 200
// taking pointer
// of the integer type
var pt1 *int = &v
// taking pointer to
// the pointer to pt1
// storing address
// of pt1 into pt2
var pt2 **int = &pt1
fmt.Println("Value of Variable v is = ", v)
// changing value of v by assigning
// new value to the pointer pt1
*pt1 = 400
fmt.Println("The Value stored in v after
changing pt1 = ", v)
// changing value of v by assigning
// the new value to the pointer pt2
**pt2 = 600
fmt.Println("The Value stored in v after
changing pt2 = ", v)
}
PORÓWNANIE WSKAŹNIKÓW
Wskaźniki to zmienne w języku programowania Go lub GoLang używane do przechowywania adresu pamięci innej zmiennej. Wskaźniki są również znane jako zmienne specjalne w GoLangu. Zmienne służą do przechowywania danych w systemie pod określonym adresem pamięci. Adresy pamięci są zawsze w formacie szesnastkowym (zaczynając od 0x jak 0xFFAAF itd.). W języku programowania Go możemy porównać dwa wskaźniki. Dwie wartości wskaźników są identyczne tylko wtedy, gdy wskazują na to samo miejsce w pamięci lub są zerowe. Możemy porównywać wskaźniki za pomocą operatorów == i != podanych w języku programowania Go:
1. Operator ==: Zwraca wartość true, jeśli oba wskaźniki wskazują na tę samą zmienną. Alternatywnie, jeśli oba wskaźniki odnoszą się do różnych zmiennych, zwróć wartość false.
Składnia:
pointer_1 == pointer_2
Przykład:
// program to illustrate
// the concept of comparing two pointers
package main
import "fmt"
func main() {
val1 := 5325
val2 := 469
// Creating, initializing pointers
var p1 *int
p1 = &val1
p2 := &val2
p3 := &val1
// Comparing the pointers with each other
// Using == operator
res1 := &p1 == &p2
fmt.Println("Is p1 pointer is equal to the p2
pointer: ", res1)
res2 := p1 == p2
fmt.Println("Is p1 pointer is equal to the p2
pointer: ", res2)
res3 := p1 == p3
fmt.Println("Is p1 pointer is equal to the p3
pointer: ", res3)
res4 := p2 == p3
fmt.Println("Is p2 pointer is equal to the p3
pointer: ", res4)
res5 := &p3 == &p1
fmt.Println("Is p3 pointer is equal to the p1
pointer: ", res5)
}
2. Operator !=: Jeśli oba wskaźniki odnoszą się do tej samej zmiennej, ten operator zwraca fałsz. Zamiast tego, jeśli oba wskaźniki odnoszą się do oddzielnych zmiennych, zwróć wartość true.
Składnia:
pointer_1 != pointer_2
Przykład:
// Program to illustrate
// the concept of comparing two pointers
package main
import "fmt"
func main() {
val1 := 22459
val2 := 467
// Creating, initializing pointers
var p1 *int
p1 = &val1
p2 := &val2
p3 := &val1
// Comparing the pointers with each other
// Using the != operator
res1 := &p1 != &p2
fmt.Println("Is p1 pointer not equal to the p2
pointer: ", res1)
res2 := p1 != p2
fmt.Println("Is p1 pointer not equal to the p2
pointer: ", res2)
res3 := p1 != p3
fmt.Println("Is p1 pointer not equal to the p3
pointer: ", res3)
res4 := p2 != p3
fmt.Println("Is p2 pointer not equal to the p3
pointer: ", res4)
res5 := &p3 != &p1
fmt.Println("Is p3 pointer not equal to the p1
pointer: ", res5)
}
Struktury i interfejsy
W Części 8 omówiliśmy wskaźniki, a tu omówimy struktury, metody i interfejsy.
STRUKTURY GoLang
W GoLang struktura lub struct jest typem zdefiniowanym przez użytkownika, który pozwala nam grupować/łączyć elementy możliwie różnych typów w jeden typ. Struktura może reprezentować dowolną rzeczywistą rzecz z kolekcją właściwości/pól. Generalnie idea ta jest związana z klasami w programowaniu obiektowym. Jest to lekka klasa, która nie obsługuje dziedziczenia, ale obsługuje kompozycję. Na przykład adres zawiera nazwę, ulicę, miasto, województwo i kod PIN. Jak widać poniżej, logiczne jest połączenie wszystkich trzech cech w jeden adres struktury.
Deklaracja struktury:
type Address struct {
name string
streetno string
city string
state string
Pin-code int
}
Słowo kluczowe type dodaje nowy typ w poprzednim kodzie. Po nim następuje nazwa typu (Address) i słowo kluczowe struct, wskazujące, że definiujemy strukturę. Wewnątrz nawiasów klamrowych struktura zawiera listę kilku pól. Każde pole ma zarówno nazwę, jak i rodzaj. Nota bene: Możemy je również uczynić bardziej zwartymi, łącząc wiele pól tego samego rodzaju, jak pokazano w poniższym przykładzie:
type Address struct {
name, streetno, city, state string
Pin-code int
}
Aby zdefiniować strukturę:
Składnia deklarowania struktury jest przedstawiona poniżej:
var x Adres
Powyższy kod tworzy zmienną typu Adres, która początkowo jest inicjowana na zero. Zero wskazuje, że wszystkie pola zostały ustawione na odpowiadającą im wartość zerową dla struktury. Tak więc pola nazwa, numer ulicy, miasto i stan są ustawione na " ", a pole Kod PIN jest ustawione na 0. Możemy również użyć literału struktury do zainicjowania zmiennej typu struktury, jak pokazano poniżej :
var x = Address{"Abishek", "PritamNagar", "Delhi", "Noida", 293616}
Notatka:
o Pamiętaj, aby przekazywać wartości pól w takiej samej kolejności, jak określono w strukturze. Ponadto trudno jest zastosować powyższe podejście do zainicjowania tylko podzbioru pól.
o Go udostępnia również nazwę: składnia wartości (kolejność pól nie ma znaczenia przy stosowaniu tej składni). W rezultacie możemy zainicjować tylko podzbiór pól. Wszystkie niezainicjowane pola mają domyślną wartość zero.
Przykład:
var x = Address{Name:"Abhishek",
streetno:"PritamNagar", state:"Delhi", Pin-code:
293616} //city:""
// Program to show how to
// declare and define struct
package main
import "fmt"
// Defining struct type
type Address struct {
Name string
city string
Pin-code int
}
func main() {
// Declaring variable of a 'struct' type
// All the struct fields are initialized with
their zero value
var x Address
fmt.Println(x)
// Declaring and initializing a
// struct using struct literal
x1 := Address{"Anisha", "Delhi", 3663272}
fmt.Println("Address1: ", x1)
// Naming fields while
// initializing a struct
x2 := Address{Name: "Abhishek", city: "Balli",
Pincode: 287011}
fmt.Println("Address2: ", x2)
// Uninitialized fields are set to
// their corresponding zerovalue
x3 := Address{Name: "Amritsar"}
fmt.Println("Address3: ", x3)
}
Jak możemy dostać się do pól strukturalnych?
Aby uzyskać dostęp do określonych pól struktury, musimy użyć operatora kropki (.).
Przykład:
// program to show how to
// access fields of struct
package main
import "fmt"
// defining struct
type Car struct {
Name, Modelno, Color string
WeightinKg float64
}
// the main Function
func main() {
x := Car{Name: "BMW", Modelno: "BTC2",
Color: "Black", WeightinKg: 1720}
// Accessing the struct fields
// using dot operator
fmt.Println("Car Name: ", x.Name)
fmt.Println("Car Color: ", x.Color)
// Assigning a new value
// to a struct field
x.Color = "White"
// Displaying result
fmt.Println("Car: ", x)
}
Wskaźniki do struktury
Wskaźniki to zmienne w języku programowania Go lub GoLang używane do przechowywania adresu pamięci innej zmiennej. Jak widać w poniższym przykładzie, możemy również zbudować odwołanie do struktury:
// Program to illustrate
// pointer to the struct
package main
import "fmt"
// defining structure
type Employee struct {
first-name, last-name string
age, salary int
}
func main() {
// passing address of the struct variable
// empy is a pointer to the Employee struct
empy := &Employee{"Samrit", "Anders", 35, 7000}
// (*empy).first-name is the syntax to access
// the first-name field of the empy struct
fmt.Println("First Name:", (*empy).first-name)
fmt.Println("Age:", (*empy).age)
}
Możemy użyć empy.imię zamiast jawnej dereferencji (*empy) w GoLang. Aby uzyskać dostęp do pola imienia, wpisz imię. Poniżej znajduje się przykład, który to demonstruje:
// Program to illustrate the
// pointer to the struct
package main
import "fmt"
// Defining structure
type Employee struct {
first-name, last-name string
age, salary int
}
// the main Function
func main() {
// taking pointer to the struct
empy := &Employee{"Samrit", "Anders", 59, 7000}
// empy.first-name is used to access
// the field first-name
fmt.Println("First Name: ", empy.first-name)
fmt.Println("Age: ", empy.age)
}
Zagnieżdżona struktura GoLanga
Struktura, znana również jako struktura w GoLangu, jest typem zdefiniowanym przez użytkownika, który pozwala nam grupować elementy wielu rodzajów w jedną jednostkę. Struktura może reprezentować dowolną rzeczywistą rzecz z różnymi atrybutami lub polami. Język programowania Go obsługuje struktury zagnieżdżone. Struktura zagnieżdżona to struktura będąca polem innej struktury. Struktura zagnieżdżona to struktura zamknięta w innej strukturze.
Składnia:
type structname1 struct{
// Fields
}
type structname2 struct{
variablename structname1
}
Przyjrzyjmy się kilku przypadkom, które pomogą nam zrozumieć tę koncepcję:
Pierwszy przykład:
// Program to illustrate the
// nested structure
package main
import "fmt"
// Creating the structure
type Author struct {
name string
branchno string
year int
}
// Creating the nested structure
type HR struct {
// structure as field
details Author
}
func main() {
// Initializing fields
// of the structure
results := HR{
details: Author{"Sonali", "EDE", 2014},
}
// Display values
fmt.Println("\nDetails of the Author")
fmt.Println(results)
}
Drugi przykład:
// Program to illustrate the
// nested structure
package main
import "fmt"
// Creating the structure
type Students struct {
name string
branchno string
year int
}
// Creating the nested structure
type Teachers struct {
name string
subject string
expr int
details Students
}
func main() {
// Initializing fields
// of the structure
results := Teachers{
name: "Sunita",
subject: "PHP",
expr: 2,
details: Student{"Rahil", "CDE", 4},
}
// Display the values
fmt.Println("Details of the Teachers")
fmt.Println("Teacher's name: ", results.name)
fmt.Println("Subject: ", results.subject)
fmt.Println("Experience: ", results.exp)
fmt.Println("\nDetails of Students")
fmt.Println("Student's name: ", results.
details.name)
fmt.Println("Student's branch name: ",
results.details.branch)
fmt.Println("Year: ", results.details.year)
}
ANONIMOWA STRUKTURA I POLA GoLang
Struktura, znana również jako struktura w GoLangu, jest typem zdefiniowanym przez użytkownika, który pozwala nam organizować elementy wielu rodzajów w jedną jednostkę. Struktura może reprezentować dowolną rzeczywistą rzecz ze zbiorem atrybutów lub pól. Struktura anonimowa W języku programowania Go możemy zbudować strukturę anonimową. Anonimowy budynek nie ma nazwy. Przydatne jest stworzenie struktury, której użyje się tylko raz. Użyj następującej składni, aby utworzyć anonimową strukturę:
variablename := struct{
// fields
}{// Fieldvalues}
Zilustrujmy to pojęcie przykładem:
// Program to illustrate
// the concept of anonymous structure
package main
import "fmt"
// the main function
func main() {
// Creating, initializing
// anonymous structure
Elements := struct {
name string
branch string
language string
Particles int
}{
name: "Pihu",
branch: "ECE",
language: "C#",
Particles: 298,
}
// Display anonymous structure
fmt.Println(Element)
}
Pola anonimowe
Możemy budować anonimowe pola w strukturze Go. Pola anonimowe nie mają nazwy; zamiast tego określamy typ pola, a Go użyje tego typu jako nazwy pola. Anonimowe pola struktury mogą być tworzone przy użyciu następującej składni:
type structname struct{
int
bool
float64
}
Ważne notatki:
o Niedozwolone jest tworzenie dwóch lub więcej pól tego samego typu w strukturze, jak pokazano poniżej:
type students struct{
int
int
}
Jeśli spróbujemy to zrobić, kompilator wygeneruje błąd.
o Dopuszczalne jest łączenie pól anonimowych i nazwanych, jak pokazano poniżej:
type students struct{
name int
prices int
string
}
Poniżej znajduje się przykład wyjaśniający koncepcję pola anonimowego:
// Program to illustrate
// the concept of anonymous structure
package main
import "fmt"
// Creating structure
// with the anonymous fields
type students struct {
int
string
float64
}
// the main function
func main() {
// Assigning the values to anonymous
// fields of the students structure
value := students{143, "Sud", 8200.21}
// Display values of the fields
fmt.Println("Enrollment number : ", value.int)
fmt.Println("Student name : ", value.string)
fmt.Println("Package price : ", value.float64)
}
METODY GoLang
Metody obsługi języka Go są identyczne z funkcjami Go z jednym wyjątkiem: metoda zawiera parametr odbiornika. Metoda może uzyskać dostęp do właściwości odbiornika za pomocą argumentu receiver. W tym przypadku odbiornik może być typu struct lub non-struct. Kiedy piszemy kod, odbiornik i typ odbiornika muszą znajdować się w tym samym pakiecie. Ponadto nie wolno nam pisać metody, której typ odbiornika jest już określony w innym pakiecie, w tym typów wbudowanych, takich jak int, string i tak dalej. Jeśli spróbujemy to zrobić, kompilator wygeneruje błąd.
Składnia:
func(reciver-name Type) method-name(parameterlist)(
return-type){
// Code
}
W ramach metody odbiorca może uzyskać dostęp.
Metoda z odbiornikiem typu strukturalnego
Możemy skonstruować metodę, której odbiornik jest typu struct w języku programowania Go. Ten odbiornik jest dostępny w ramach metody, jak widać na poniższym przykładzie:
// Program to illustrate
// the method with struct type receiver
package main
import "fmt"
// the author structure
type author struct {
name string
branch string
particles int
salary int
}
// Method with a receiver of author type
func (x author) show() {
fmt.Println("Author's Name: ", x.name)
fmt.Println("Branch Name: ", x.branch)
fmt.Println("Published articles: ", x.particles)
fmt.Println("Salary: ", x.salary)
}
// the main function
func main() {
// Initializing values
// of the author structure
rest := author{
name: "Monika",
branch: "CDE",
particles: 204,
salary: 37000,
}
// Calling method
rest.show()
}
Metoda z odbiornikiem typu Non-Struct
W Go możemy zdefiniować metodę z odbiornikiem typu innego niż struct, o ile deklaracje typu i metody znajdują się w tym samym pakiecie. Jeśli są one obecne w wielu pakietach, takich jak int, string itd., kompilator wygeneruje błąd, ponieważ są one zdefiniowane w wielu pakietach.
Przykład:
// Program to illustrate method
// with the non-struct type receiver
package main
import "fmt"
// Type definition
type data int
// Defining method with
// the non-struct type receiver
func (c1 data) multiply(c2 data) data {
return c1 * c2
}
/*
// if you try to run this code,
// then compiler will throw an error
func(c1 int)multiply(c2 int)int{
return c1 * c2
}
*/
// Main function
func main() {
value1 := data(43)
value2 := data(26)
rest := value1.multiply(value2)
fmt.Println("Final result: ", rest)
}
Metody z odbiornikiem wskaźnika
Metoda z odbiorcą wskaźnika jest dozwolona w języku programowania Go. Jeśli modyfikacja zostanie wprowadzona do metody przy użyciu odbiornika wskaźnika, zostanie to odzwierciedlone w wywołującym, co nie jest możliwe w przypadku metod odbiornika wartości.
Składnia:
func (p *Type) method-name(...Type) Type {
// Code
}
Przykład :
// Program to illustrate pointer receiver
package main
import "fmt"
// the author structure
type author struct {
name string
branch string
particles int
}
// Method with a receiver of the author type
func (x *author) show(abranch string) {
(*x).branch = abranch
}
// the main function
func main() {
// Initializing values
// of the author structure
rest := author{
name: "Shona",
branch: "CDE",
}
fmt.Println("Author's name: ", rest.name)
fmt.Println("Branch Name(Before): ", rest.
branch)
// Creating pointer
p := &rest
// Calling show method
p.show("ERE")
fmt.Println("Author's name: ", rest.name)
fmt.Println("Branch Name(After): ", rest.
branch)
}
Metoda może akceptować zarówno wskaźnik, jak i wartość
Jak wszyscy wiemy, gdy funkcja ma argument wartość, przyjmie tylko wartości parametru, a jeśli spróbujemy podać wskaźnik do funkcji wartości, odrzuci go i odwrotnie. Z drugiej strony metoda Go może akceptować zarówno wartość, jak i wskaźnik, w zależności od tego, czy jest określona za pomocą wskaźnika, czy odbiornika wartości. Jak pokazano w poniższym przykładzie:
// Program to illustrate how
// the method can accept pointer and value
package main
import "fmt"
// Author structure
type author struct {
name string
branch string
}
// Method with pointer
// receiver of author type
func (x *author) show_1(abranch string) {
(*x).branch = abranch
}
// Method with a value
// receiver of author type
func (x author) show_2() {
x.name = "Gautam"
fmt.Println("Author's name(Before) : ", x.name)
}
// the main function
func main() {
// Initializing values
// of the author structure
rest := author{
name: "Sonika",
branch: "CSA",
}
fmt.Println("Branch Name(Before): ", rest.
branch)
// Calling show_1 method
// (pointer method) with the value
res.show_1("ECE")
fmt.Println("Branch Name(After): ", rest.
branch)
// Calling show_2 method
// (value method) with a pointer
(&rest).show_2()
fmt.Println("Author's name(After): ", res.namet)
}
Różnica między metodą a funkcją
Metoda: funkcja
Zawiera odbiornik. : Nie zawiera odbiornika.
W programie mogą być definiowane metody o tej samej nazwie, ale różnego rodzaju. : Program nie definiuje funkcji o tej samej nazwie, ale różnych typach
Nie można go użyć do stworzenia obiektu pierwszego rzędu. : Może być używany jako obiekt pierwszego rzędu i może zostać przekazany.
INTERFEJSY
Interfejsy języka Go różnią się od interfejsów innych języków. Interfejs jest specjalnym typem w Go używanym do wyrażania zestawu jednej lub więcej sygnatur metod. Interfejs jest abstrakcyjny, dlatego nie możemy utworzyć jego instancji. Możemy jednak ustanowić zmienną typu interfejsu, której można przypisać konkretną wartość typu, która ma metody wymagane przez interfejs. Innymi słowy, interfejs jest zarówno zestawem metod, jak i typem niestandardowym.
Jak tworzymy interfejs?
W języku programowania Go możemy zdefiniować interfejs o następującej składni:
type interfacename interface{
// Method-signatures
}
Przykład:
// Creating interface
type myinterface interface{
// Methods
func1() int
func2() float64
}
Nazwa interfejsu jest ujęta w słowa kluczowe type i interface, podczas gdy nawiasy klamrowe obejmują sygnatury metod.
Jak implementować interfejsy
Aby zaimplementować interfejs w języku Go, wszystkie metody określone w interfejsie muszą zostać zaimplementowane. Interfejsy języka programowania Go są implementowane niejawnie. I, w przeciwieństwie do innych języków, brakuje mu określonego terminu implementacji interfejsu.
Przykład:
// Program illustrates how
// to implement interface
package main
import "fmt"
// Creating interface
type tank interface {
// Methods
Tarea() float64
Volume() float64
}
type myvalue struct {
radius float64
height float64
}
// Implementing methods of t
ank interface
func (m myvalue) Tarea() float64
{
return 2*m.radius*m.height +
2*3.14*m.radius*m.radius
}
func (m myvalue) Volume() float64
{
return 3.14 * m.radius * m.radius * m.height
}
// the main Method
func main() {
// Accessing elements of the
// tank interface
var tk tank
tk = myvalue{10, 14}
fmt.Println("The Area of tank :", tk.Tarea())
fmt.Println("The Volume of tank:",
tk.Volume())
}
Ważne notatki:
o Wartość zerowa interfejsu wynosi zero.
o Gdy interfejs nie zawiera żadnych metod, jest nazywany interfejsem pustym. W rezultacie wszystkie typy implementują pusty interfejs.
Składnia:
interface{}
o Typy interfejsów: Istnieją dwa typy interfejsów: interfejsy statyczne i dynamiczne interfejsy. Typ statyczny to sam interfejs, np. jak zbiornik w poniższym przykładzie. Ponieważ jednak interfejs nie ma wartości statycznej, zawsze wskazuje wartości dynamiczne. Zmienna typu interfejs zawiera wartość typu, który implementuje interfejs; w związku z tym wartość tego typu jest znana jako wartość dynamiczna, a typ jest typem dynamicznym. Jest również określany jako konkretna wartość i konkretny typ.
Przykład:
// Program to illustrate concept
// of the dynamic values and types
package mainimport "fmt"
// Creating interface
type tank interface {
// Methods
Tarea() float64
Volume() float64
}
func main() {
var tk tank
fmt.Println("The Value of the tank interface
is: ", tk)
fmt.Printf("The Type of the tank interface is:
%T ", tk)
}
W przykładzie mamy interfejs zwany zbiornikiem. W tym przykładzie fmt.Println("Wartość interfejsu zbiornika to: ", tk) zwraca wartość dynamiczną interfejsu, natomiast fmt.Printf("Typ interfejsu zbiornika to: procent T ", tk) zwraca wartość dynamiczną type, czyli zero, ponieważ interfejs nie wie, kto go implementuje.
o Asercje typu: Asercja typu w Go to operacja wykonywana na wartości interfejsu. Innymi słowy, asercja typu jest procedurą wyodrębniania wartości interfejsu.
Składnia:
a.(T)
W tym przypadku a jest wartością lub wyrażeniem interfejsu, a T jest typem, czasami znanym jako typ potwierdzony. Asercja typu służy do określenia, czy typ dynamiczny jego operandu jest zgodny z deklarowanym typem. Jeśli T jest typu konkretnego, asercja typu sprawdza, czy określony typ dynamiczny a jest równy T; jeśli weryfikacja zakończy się pomyślnie, asercja typu zwraca wartość dynamiczną a. Jeśli sprawdzanie nie powiedzie się, operacja zakończy się niepowodzeniem. Jeśli T jest typem interfejsu, potwierdzenie typu sprawdza, czy dostarczony typ dynamiczny a spełnia T; jeśli sprawdzanie powiedzie się, wartość dynamiczna nie zostanie wyodrębniona.
Przykład:
// Program to illustrate the
// type assertion
package main
import "fmt"
func myfun(a interface{}) {
// Extracting the value of a
vals := a.(string)
fmt.Println("Value: ", vals)
}
func main() {
var val interface {
} = "Helloeveryone"
myfun(vals)
}
Jeśli zmienimy polecenie val:= a.(string) w powyższym przykładzie na val:= a.(int), program panikuje. Aby rozwiązać ten problem, stosujemy następującą składnię:
value, ok := a.(T)
Jeśli typem a jest T, wówczas wartość zawiera dynamiczną wartość a, a ok jest ustawiane na true. A jeśli typ a nie jest równy T, to ok jest ustawiane na fałsz, a wartość zawiera wartość zero, a program nie panikuje. Jak pokazano w poniższym programie:
// Program to illustrate the type assertion
package main
import "fmt"
func myfun(a interface{}) {
value, ok := a.(float64)
fmt.Println(value, ok)
}
func main() {
var a1 interface {
} = 97.09
myfun(a1)
var a2 interface {
} = "Helloeveryone"
myfun(a2)
}
o Przełącznik typu: przełącznik typu w interfejsie Go porównuje konkretny typ interfejsu z wieloma typami podanymi w instrukcjach przypadków. Jest identyczny z asercją typu, z jednym wyjątkiem: przypadek określa typy, a nie wartości. Typ można również porównać z typem interfejsu. Jak pokazano w poniższym przykładzie:
// Program to illustrate the type switch
package main
import "fmt"
func myfun(a interface{}) {
// Using the type switch
switch a.(type) {
case int:
fmt.Println("Type: int, Value:", a.(int))
case string:
fmt.Println("\nType: string, Value: ",
a.(string))
case float64:
fmt.Println("\nType: float64, Value: ",
a.(float64))
default:
fmt.Println("\nType not found")
}
}
// the main method
func main() {
myfun("Helloeveryone")
myfun(59.9)
myfun(true)
}
o Użycie interfejsu: Możemy użyć interfejsu, gdy chcemy przekazać wiele rodzajów argumentów do metod lub funkcji, takich jak funkcja Println(). Gdy wiele typów implementuje ten sam interfejs, możemy również użyć interfejsu.
Dlaczego interfejsy Go są świetne
"Interfejs" w programowaniu obiektowym opisuje, co może osiągnąć obiekt. Zazwyczaj ma to postać listy metod, które obiekt musi mieć. C#, Java obsługuje interfejsy i język programowania Go, chociaż interfejsy Go są szczególnie proste w użyciu. Nie musimy deklarować, że typ Go (który działa podobnie do "klasy" w innych językach) implementuje interfejs, tak jak zrobilibyśmy to w C# czy Javie. Po prostu deklarujemy interfejs, a następnie dowolny typ, który ma te metody, może być używany wszędzie tam, gdzie wymagany jest ten interfejs.
Nadmiarowe funkcje
Załóżmy, że mamy pakiet zwierzaków ("pakiet" jest odpowiednikiem "biblioteki" w innych językach) zawierający typy Psy i Koty. Psy mają technikę Aportowania, Koty mają metodę Mruczenia, a zarówno psy, jak i koty mają metody Spaceru i Siadania.
packag pets
import "fmt"
type Dogs struct {
Name string
Breed string
}
func (d Dogs) Walk() {
fmt.Println(d.Name, "walks across room")
}
func (d Dogs) Sit() {
fmt.Println(d.Name, "sits down")
}
func (d Dogs) Fetch() {
fmt.Println(d.Name, "fetches toy")
}
type Cats struct {
Name string
Breed string
}
func (c Cats) Walk() {
fmt.Println(c.Name, "walks across room")
}
func (c Cats) Sit() {
fmt.Println(c.Name, "sits down")
}
func (c Cats) Purr() {
fmt.Println(c.Name, "purrs")
}
Teraz utwórzmy przykład. Program Go, który pokazuje, do czego zdolne są psy i koty. Stworzymy funkcję DemoDog, która bierze psa i wywołuje na nim metody Walk i Sit. Następnie utworzymy funkcję DemoCat, która wykona to samo dla kotów.
package main
import "pets"
func DemoDogs(dog pets.Dogs) {
dog.Walk()
dog.Sit()
}
func DemoCat(cat pets.Cats) {
cat.Walk()
cat.Sit()
}
func main() {
dog := pets.Dogs{"Fido", "Terrier"}
cat := pets.Cats{"Fluffy", "Siamese"}
DemoDogs(dog)
// call outputs:
// Fido walks across room
// Fido sit down
DemoCat(cat)
// call outputs:
// Fluffy walks across room
// Fluffy sit down
}
Niestety procedury DemoDogs i DemoCats są identyczne, z wyjątkiem tego, że jeden bierze Psy, a drugi Koty. Ponieważ moglibyśmy zmienić jedną funkcję, ale nie zaktualizować drugiej, powtarzanie takiego kodu zwiększa ryzyko niespójności. Byłoby idealnie, gdybyśmy mogli pozbyć się DemoCatów i dać Koty tylko DemoDogom; jednak doprowadziłoby to do błędu:
DemoDogs(cat)
// ./demo.go:19: cannot use cat (type pets.Cats)
// as type pets.Dogs in argument to DemoDogs
Wejdź do interfejsu
Ale nie musimy utrzymywać dwóch prawie identycznych funkcji tylko dlatego, że przyjmują różne typy. To jest właśnie problem, dla którego tworzone są interfejsy. Stworzymy interfejs czworonożny z metodami chodu i siedzenia dla wszystkich rodzajów. Następnie zamiast funkcji DemoDogs i DemoCats zastąpimy je pojedynczą funkcją Demo, która akceptuje dowolną wartość FourLegged (niezależnie od tego, czy jest to Dogs, czy Cats).
package main
import "pets"
// This interface represents any type that has Walk
and Sit methods.
type FourLegged interface {
Walk()
Sit()
}
// We can replace DemoDogs and DemoCats
// with this single function.
func Demo(animal FourLegged) {
animal.Walk()
animal.Sit()
}
func main() {
dog := pets.Dogs{"Rido", "Ferrier"}
cat := pets.Cats{"Pluffy", "Diames"}
Demo(dog)
// Above call (again) outputs:
// Fido walks across room
// Fido sit down
Demo(cat)
// The above call (again) outputs:
// Fluffy walks across room
// Fluffy sit down
}
WBUDOWYWANE INTERFEJSY
Interfejs w Go jest zbiorem sygnatur metod i typu, co oznacza, że możesz skonstruować zmienną typu interfejsu. Chociaż język Go nie umożliwia dziedziczenia, interfejs Go tak. Podczas osadzania interfejs może osadzać inne interfejsy lub ich sygnatury metod, z takimi samymi wynikami, jak w pierwszym i drugim przykładzie. W jednym interfejsie możemy osadzić nieograniczoną liczbę interfejsów. A kiedy osadzimy inne interfejsy w interfejsie, jeśli zmienimy metody interfejsów, zmiany zostaną odzwierciedlone również w interfejsie osadzonym, jak pokazano w przykładzie 3.
Składnia:
type interfacename1 interface {
Method1()
}
type interfacename2 interface {
Method2()
}
type finalinterfacename interface {
interfacename1
interfacename2
}
Pierwszy przykład:
// Program to illustrate the concept
// of embedding interfaces
package main
import "fmt"
// Interface 1
type AuthorDetail interface {
details()
}
// Interface 2
type AuthorArticle interface {
articles()
}
// Interface 3 embedded with the interface 1 and 2
type FinalDetail interface {
AuthorDetail
AuthorArticle
}
// Structure
type author struct {
a_name string
branch string
college string
year int
salary int
particles int
tarticles int
}
// Implementing the method of
// the interface 1
func (a author) details() {
fmt.Printf("The Author Name: %s", a.a_name)
fmt.Printf("\nThe Branch: %s and passing year:
%d",
a.branch, a.year)
fmt.Printf("\nThe College Name: %s", a.college)
fmt.Printf("\nThe Salary: %d", a.salary)
fmt.Printf("\nThe Published articles: %d",
a.particle)
}
// Implementing method of the interface 2
func (a author) articles() {
pendingarticle := a.tarticle - a.particle
fmt.Printf("\nPending articles: %d",
pendingarticle)
}
// the main value
func main() {
// Assigning values to the structure
values := author{
a_name: "Ricky",
branch: "Accounts",
college: "XYZ",
year: 2019,
salary: 40000,v
particle: 107,v
tarticle: 206,
}
// Accessing methods of the interface 1 and 2
// Using the FinalDetail interface
var f FinalDetail = values
f.details()
f.articles()
}
Objaśnienie: Jak widać w poprzednim przykładzie, mamy trzy interfejsy. Interfejsy 1 i 2 to interfejsy podstawowe, ale interfejs 3 jest wbudowanym interfejsem zawierającym interfejsy 1 i 2. W rezultacie wszelkie zmiany dokonane w interfejsach 1 i 2 zostaną odzwierciedlone w interfejsie 3. Interfejs 3 ma dostęp do wszystkich metod dostępne w interfejsach 1 i 2.
Drugi przykład:
// Program to illustrate concept of embedding
interfaces
package main
import "fmt"
// Interface 1
type AuthorDetail interface {
details()
}
// Interface 2
type AuthorArticle interface {
article()
}
// Interface 3 embedded with the interface 1 and
2's methods
type FinalDetail interface {
detail()
article()
}
// Structure
type author struct {
a_name string
branch string
college string
year int
salary int
particle int
tarticle int
}
// Implementing method of the interface 1
func (a author) details() {
fmt.Printf("The Author Name: %s", a.a_name)
fmt.Printf("\nThe Branch: %s and passing year:
%d", a.branch, a.year)
fmt.Printf("\nThe College Name: %s",
a.college)
fmt.Printf("\nThe Salary: %d", a.salary)
fmt.Printf("\nThe Published articles: %d",
a.particle)
}
// Implementing method of the interface 2
func (a author) articles() {
pendingarticle := a.tarticle - a.particle
fmt.Printf("\nThe Pending articles: %d",
pendingarticle)
}
// the main value
func main() {
// Assigning the values to structure
values := author{
a_name: "Ricky",
branch: "Accounts",
college: "XYZ",
year: 2019,
salary: 40000,
particle: 107,
tarticle: 206,
}
// Accessing the methods
// of the interface 1 and 2
// Using the FinalDetail interface
var f FinalDetail = values
f.detail()
f.article()
}
Objaśnienie: Jak widać w poprzednim przykładzie, mamy trzy interfejsy. Interfejsy 1 i 2 są interfejsami podstawowymi, natomiast interfejs 3 jest wbudowanym interfejsem zawierającym sygnatury metod dla interfejsów 1 i 2. W konsekwencji wszelkie modyfikacje metod interfejsów 1 i 2 zostaną odzwierciedlone w interfejsie 3. Interfejs 3 ma dostęp do wszystkie metody dostępne w interfejsach 1 i 2.
Trzeci przykład:
// Program to illustrate concept of embedding
interfaces
package main
import "fmt"
// Interface 1
type AuthorDetail interface {
detail()
}
// Interface 2
type AuthorArticle interface {
article()
picked()
}
// Interface 3
// Interface 3 embedded with interface 1's method
and interface 2
// And also contain its own method
type FinalDetail interface {
detail()
AuthorArticle
cdeatil()
}
// Structure
type author struct {
a_name string
branch string
college string
year int
salary int
particle int
tarticle int
cid int
post string
pick int
}
// Implementing method of the interface 1
func (a author) detail() {
fmt.Printf("The Author Name: %s", a.a_name)
fmt.Printf("\nThe Branch: %s and passing year:
%d", a.branch, a.year)
fmt.Printf("\nThe College Name: %s",
a.college)
fmt.Printf("\nThe Salary: %d", a.salary)v
fmt.Printf("\nThe Published articles: %d",
a.particle)
}
// Implementing methods of the interface 2
func (a author) article() {
pendingarticle := a.tarticle - a.particle
fmt.Printf("\nPending articles: %d",
pendingarticle)
}
func (a author) picked() {
fmt.Printf("\nThe Total number of picked
articles: %d", a.pick)
}
// Implementing the method of the embedded
interface
func (a author) cdeatil() {
fmt.Printf("\nAuthor Id: %d", a.cid)
fmt.Printf("\nPost: %s", a.post)
}
// the main value
func main() {
// Assigning values to structure
values := author{
a_name: "Ricky",
branch: "Accounts",
college: "XYZ",
year: 2019,
salary: 40000,
particle: 107,
tarticle: 206,
cid: 3097,
post: "Content writer",
pick: 38,
}
// Accessing methods
// of the interface 1 and 2
// Using the FinalDetails interface
var f FinalDetails = values
f.detail()
f.article()
f.picked()
f.cdeatil()
}
Objaśnienie: Jak widać w poprzednim przykładzie, mamy trzy interfejsy. Interfejsy 1 i 2 to interfejsy podstawowe, podczas gdy interfejs 3 to interfejs osadzony, który zawiera sygnatury metod interfejsów 1 i 2 oraz własną metodę. W rezultacie wszelkie modyfikacje dokonane w metodach interfejsów 1 i 2 zostaną odzwierciedlone w interfejsie 3. A interfejs 3 ma dostęp do wszystkich zawartych w nim metod, w tym w interfejsach 1, 2 i własnych.
DZIEDZICZENIE
Jedną z najbardziej fundamentalnych idei programowania obiektowego jest dziedziczenie, które obejmuje dziedziczenie właściwości wyższej klasy do klasy podstawowej. Ponieważ GoLang nie zapewnia klas, dziedziczenie odbywa się poprzez osadzanie struktur. Nie możemy bezpośrednio rozszerzać struktur, ale zamiast tego musimy zastosować pojęcie znane jako kompozycja, w którym struktura służy do tworzenia dodatkowych obiektów. W rezultacie w GoLang nie ma koncepcji dziedziczenia. W kompozycji struktury podstawowe można osadzać w strukturze potomnej, a metody struktury podstawowej można wywoływać bezpośrednio w strukturze potomnej, jak pokazano w poniższych przykładach.
Pierwszy przykład:
// Program to illustrate
// the concept of inheritance
package main
import (
"fmt"
)
// declaring struct
type Comic struct{
// declaring the struct variable
Universe string
}
// function to return
// universe of comic
func (comic Comic) ComicUniverse() string {
// returns the comic universe
return comic.Universe
}
// declaring struct
type Marvel struct{
// anonymous field,
// this is composition where the
// struct is embedded
Comic
}
// declaring struct
type DC struct{
// anonymous field
Comic
}
// the main function
func main() {
// creating instance
cs1 := Marvel{
// child struct can directly access base
struct variables
Comic{
Universe: "MCU",
},
}
// child struct can directly access base
struct methods
// printing base method using child
fmt.Println("The Universe is:", cs1.
ComicUniverse())
cs2 := DC{
Comic{
Universe : "DC",
},
}
// printing base method using the child
fmt.Println("The Universe is:", cs2.
ComicUniverse())
}
Dziedziczenie wielokrotne występuje, gdy struktura potomna ma dostęp do różnych atrybutów, pól i metod więcej niż jednej struktury podstawowej. Jak widać z poniższego kodu, struktura potomna osadza wszystkie struktury podstawowe:
Drugi przykład:
// Program to illustrate
// the concept of multiple inheritances
package main
import (
"fmt"
)
// declaring first base struct
type first struct{
// declaring the struct variable
base_one string
}
// declaring the second base struct
type second struct{
// declaring the struct variable
base_two string
}
// function to return first struct variable
func (f first) printBase1() string{
// returns string of first struct
return f.base_one
}
// function to return second struct variable
func (s second) printBase2() string{
// returns string of first struct
return s.base_two
}
// child struct which embeds both base structs
type child struct{
// anonymous fields, struct embedding
// of multiple structs
first
second
}
// the main function
func main() {
// declaring instance
// of child struct
cs1 := child{
// child struct can directly access base
struct variables
first{
base_one: "In base struct 1.",
},
second{
base_two: "\nIn base struct 2.\n",
},
}
// child struct can directly access base
struct methods
// printing the base method
// using the instance of child struct
fmt.Println(cs1.printBase1())
fmt.Println(cs1.printBase2())
}
POLIMORFIZM Z WYKORZYSTANIEM INTERFEJSÓW
Termin polimorfizm odnosi się do obecności wielu form. Innymi słowy, polimorfizm to zdolność wiadomości do wyświetlenia w więcej niż jednej formie. Z technicznego punktu widzenia polimorfizm odnosi się do użycia tej samej nazwy metody (ale różnych sygnatur) dla wielu typów. Na przykład dama może mieć jednocześnie wiele cech, na przykład matkę, żonę, siostrę, pracownicę i tak dalej. W rezultacie ta sama osoba wykazuje różne zachowania w różnych ustawieniach. Nazywa się to polimorfizmem. Nie możemy stworzyć polimorfizmu w Go za pomocą klas, ponieważ Go nie zezwala na klasy, ale możemy to osiągnąć za pomocą interfejsów. Jak wspomniano wcześniej, interfejsy są implicite implementowane w Go. Tak więc, kiedy ustanawiamy interfejs i inne rodzaje chcą go zaimplementować, typy te wykorzystują interfejs za pomocą metod interfejsu bez znajomości typu. Zmienna typu interfejsu w interfejsie może zawierać dowolną wartość, która implementuje interfejs. W języku programowania Go ta cecha pomaga interfejsom w osiągnięciu polimorfizmu. Posłużmy się przykładem.
// Program to illustrate the
// concept of polymorphism using the interfaces
package main
import "fmt"
// Interface
type employee interface {
develop() int
name() string
}
// Structure1
type team1 struct {
totalapp_1 int
name_1 string
}
// Methods of employee interface
// are implemented by team1 structure
func (tm1 team1) develop() int {
return tm1.totalapp_1
}
func (tm1 team1) name() string {
return tm1.name_1
}
// Structure 2
type team2 struct {
totalapp_2 int
name_2 string
}
// Methods of the employee interface are
// implemented by team2 structure
func (tm2 team2) develop() int {
return tm2.totalapp_2
}
func (tm2 team2) name() string {
return tm2.name_2
}
func finaldevelop(i []employee) {
totalproject := 0
for _, ele := range i {
fmt.Printf("\nThe Project environment = %s\n
", ele.name())
fmt.Printf("The Total number of project %d\n
", ele.develop())
totalproject += ele.develop()
}
fmt.Printf("\nThe Total projects completed by "+
"the company = %d", totalproject)
}
// The main function
func main() {
res1 := team1{totalapp_1: 20,
name_1: "IOS"}
res2 := team2{totalapp_2: 35,
name_2: "Android"}
final := []employee{res1, res2}
finaldevelop(final)
}
Objaśnienie: W powyższym przykładzie nazwa interfejsu jest używana jako pracownik. Ten interfejs ma dwie metody:Develop() i name(). MetodaDevelop() zwraca całkowitą liczbę projektów, natomiast metoda name() zwraca nazwę środowiska, w którym zostały utworzone. Mamy teraz dwie struktury, team1 i team2. totalapp_1 int, name_1 string, totalapp_2 int i name_2 string to pola w obu strukturach. Struktury te (zespół 1 i zespół 2) implementują teraz metody interfejsu pracownika. Następnie piszemy metodę finaldevelop(), która zwraca całkowitą liczbę projektów utworzonych przez organizację. Wymaga argumentu wycinka interfejsów pracowników. Oszacowuje całkowitą liczbę projektów wygenerowanych przez firmę poprzez iterację w przekroju i wywołanie funkcjiDevelop() na każdym z jej członków. Pokazuje również środowisko projektu, wywołując funkcję name(). Różne metody development() i name() będą wywoływane w zależności od konkretnego typu interfejsu pracownika. Osiągnęliśmy więc polimorfizm w metodzie finaldevelop(). Jeśli dodasz do tego programu kolejny zespół, który implementuje interfejs pracowniczy, funkcja finaldevelop() określi całkowitą liczbę projektów stworzonych przez firmę bez względu na polimorfizm. W tym rozdziale omówiono definicję struktur, deklarację struktury, strukturę zagnieżdżoną i anonimową. Omówiliśmy również metodę z odbiornikiem struct i nontype. Ponadto dowiedzieliśmy się o interfejsach, polimorfizmie i dziedziczeniu.
Współbieżność i Goroutines
GOROUTINES - WSPÓŁBIEŻNOŚĆ W GoLang
Goroutine to szczególna cecha języka programowania Go. Goroutine to funkcja lub metoda, która działa niezależnie i równolegle z innymi Goroutine w naszym programie. Innymi słowy, każda stale wykonywana akcja w języku programowania Go jest określana jako Goroutine. Goroutine można traktować jako lekką nić. W porównaniu z nicią koszt założenia Goroutines jest dość niski. Każdy program zawiera co najmniej jeden Goroutine, który jest określany jako główny Goroutine. Wszystkie Goroutines są podporządkowane głównym Goroutines; jeśli główna goroutine zakończy się, wszystkie goroutines w programie zakończą się. Goroutine zawsze działa w tle. Współbieżność poprawia wydajność dzięki wykorzystaniu wielu rdzeni przetwarzających. Obsługa API Go umożliwia programistom wydajną implementację algorytmów równoległych. Obsługa współbieżności jest opcjonalną funkcją większości głównych języków programowania; jest jednak wbudowany w Go.
Przejdź do programowania współbieżnego
Programowanie współbieżne w pełni wykorzystuje liczne rdzenie procesorów występujące w większości współczesnych systemów. Pojęcie to istnieje od dawna, nawet gdy pojedynczy rdzeń miał tylko jeden rdzeń. Używanie kilku wątków do tworzenia jakiejś formy współbieżności było szeroko rozpowszechnionym podejściem w wielu językach programowania, w tym C/C++, Java i innych. Pojedynczy wątek to zasadniczo mały zestaw instrukcji zaplanowanych do wykonania indywidualnie. Możemy myśleć o tym jako o małym zadaniu w ramach większego projektu. W rezultacie wiele wątków wykonawczych jest łączonych i uruchamianych równolegle w celu wykonania skomplikowanego procesu. Ta spójność na wielu stanowiskach daje wrażenie równoczesnej realizacji. Należy jednak pamiętać, że dowolny ograniczony sprzęt - taki jak pojedynczy procesor - może osiągnąć tylko określoną liczbę zadań, planując działania z podziałem czasu. Dzisiejsze urządzenia komputerowe zasilane są przez wiele rdzeni. W rezultacie język, który potrafi w pełni wykorzystać swój potencjał, jest stale poszukiwany. Główne języki programowania stopniowo uznają tę prawdę i próbują włączyć współbieżność do swoich podstawowych możliwości. Jednak twórcy Go rozumowali: "Dlaczego nie zbudować języka od podstaw z koncepcją współbieżności jako jedną z jego podstawowych cech?" Jeden z takich języków, który zapewnia interfejsy API wysokiego poziomu do pisania współbieżnych programów w Go.
Problemy z wielowątkowością
Aplikacje wielowątkowe są trudne nie tylko do tworzenia i utrzymywania, ale także do debugowania. Ponadto rozbicie dowolnego procesu przy użyciu kilku wątków nie zawsze jest możliwe, aby uczynić go tak wydajnym, jak programowanie współbieżne. Wielowątkowość ma swój własny zestaw kosztów. Środowisko obsługuje wiele zadań, w tym komunikację między procesami i dostęp do pamięci współdzielonej. Deweloperzy mogą skoncentrować się na wykonywanym zadaniu, zamiast wikłać się w szczegóły przetwarzania równoległego. Pamiętając o tych kwestiach, inną opcją jest całkowite poleganie na systemie operacyjnym w zakresie przetwarzania wieloprocesowego. W tym przypadku zadaniem programisty jest radzenie sobie ze złożonością komunikacji międzyprocesowej lub kosztem współbieżności pamięci współdzielonej. Strategię tę można bardzo modyfikować na korzyść wydajności, ale łatwo ją też zepsuć.
Programowanie współbieżne w Go
Go zapewnia potrójne rozwiązanie do programowania współbieżnego.
o Wsparcie na wysokim poziomie sprawia, że współbieżność jest nie tylko łatwiejsza do wdrożenia, ale także łatwiejsza w zarządzaniu.
o Stosowane są goroutines. Nici są cięższe niż gorutyny.
o Bez interwencji programistów zautomatyzowane wyrzucanie elementów bezużytecznych w Go rozwiązuje złożoność zarządzania pamięcią.
Jak radzić sobie z problemami współbieżności w Go
Goroutines ułatwiają budowanie współbieżności i podstawowych prymitywów. Czynność wykonująca jest w tym kontekście określana jako goroutine. Rozważmy program mający dwie funkcje, które nie komunikują się ze sobą. W wykonywaniu sekwencyjnym jedna funkcja kończy swoje wykonanie przed wywołaniem innej. Jednak w Go funkcja może być jednocześnie aktywna i wykonywana. Jest to proste, jeśli funkcje są niepołączone, ale mogą wystąpić komplikacje, gdy są one ze sobą połączone i mają ten sam czas trwania wykonywania. Nawet przy wysokim poziomie obsługi współbieżności w Go, problemów tych nie da się całkowicie uniknąć, zwłaszcza jeśli główna funkcja zakończy swoje wykonanie przed funkcjami, które na niej polegają. W rezultacie musimy być ostrożni, aby główny goroutine czekał, aż wszystkie zadania zostaną wykonane. Innym problemem jest zakleszczenie, które występuje, gdy więcej niż jeden goroutine blokuje określony zasób, aby zachować wyłączność, podczas gdy inny próbuje uzyskać ten sam zamek w tym samym czasie. Tego rodzaju niebezpieczeństwo jest typowe dla programowania współbieżnego, ale Go zawiera poprawkę, która eliminuje potrzebę blokad dzięki wykorzystaniu kanałów. Po zakończeniu zadania często tworzony jest kanał powiadamiający o zakończeniu wykonywania. Inną opcją jest użycie synchronizacji do oczekiwania na raport. Grupa oczekiwania. Jednak zakleszczenie może nadal wystąpić w dowolnym przypadku i co najwyżej można mu zapobiec dzięki starannemu projektowi. Go po prostu oferuje narzędzia do planowania prawidłowego działania współbieżności
Goroutine z WaitGroup Przykład
Możemy ustanowić goroutine, poprzedzając dowolne wywołanie funkcji terminem go. Następnie funkcja działa jak wątek, konstruując goroutine zawierającą ramkę wywołania i planując jej działanie jako wątek. Może uzyskiwać dostęp do dowolnych argumentów, globali lub czegokolwiek dostępnego w jego zasięgu, tak jak każda inna funkcja. Oto podstawowy kod, którego można użyć do określenia, czy witryna działa, czy nie. Identyczny kod jest następnie stosowany do goroutine. Zanotuj, jak zwiększa się szybkość wykonywania, gdy używamy współbieżności.
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
start := time.Now()
sitelist := []string{
"https://www.google.com//",
"https://www.youtube.com/",
"https://www.pinterest.com/",
"https://www.codeguru.com/",
"https://www.nasa.gov/",
}
for _, site := range sitelist {
GetSiteStatus(site)
}
fmt.Printf("\n\nTime elapsed since %v\n\n", time.
Since(start))
}
func GetSiteStatus(site string) {
if _, err := http.Get(site); err != nil {
fmt.Printf("%s is down\n", site)
} else {
fmt.Printf("%s is up\n", site)
}
}
Jak stworzyć Goroutine
Możemy po prostu stworzyć własną Goroutine, poprzedzając wywołanie funkcji lub metody słowem kluczowym go, jak widać w następującej składni:
Składnia:
func name(){
// statement
}
// using go keyword as
// the prefix of our function call
go name()
Przykład:
// Program to illustrate the
// concept of Goroutine
package main
import "fmt"
func display(str string) {
for c := 0; c < 5; c++ {
fmt.Println(str)
}
}
func main() {
// Calling the Goroutine
go display("Welcome")
// Calling the normal function
display("Helloeveryone")
}
W powyższym przykładzie definiujemy metodę display() i wywołujemy ją na dwa różne sposoby. Pierwsza to Goroutine, taka jak go display("Witamy"), a druga to normalna funkcja, taka jak display("Helloeveryone"). Jest jednak problem: pokazuje tylko wynik normalnej funkcji, a nie wynik Goroutine, ponieważ kiedy wywoływany jest nowy Goroutine, Goroutine natychmiast wywołuje zwroty. Kontrolka nie czeka, aż Goroutine zakończy wykonywanie; zamiast tego przechodzi do następnego wiersza po wywołaniu Goroutine i ignoruje wartość podaną przez Goroutine. Tak więc, aby poprawnie uruchomić Goroutine, wprowadziliśmy następujące zmiany w naszym programie:
Zaktualizowany przykład:
// program to illustrate concept of Goroutine
package main
import (
"fmt"
"time"
)
func display(str string) {
for w := 0; w < 5; w++ {
time.Sleep(1 * time.Second)
fmt.Println(str)
}
}
func main() {
// Calling Goroutine
go display("Hello")
// Calling the normal function
display("Helloeveryone")
}
W naszej aplikacji wprowadziliśmy funkcję Sleep(), która powoduje uśpienie głównego Goroutine na 1 sekundę pomiędzy 1 sekundą wykonania nowego Goroutine, wyświetleniem "Hello" na ekranie, a następnie zakończeniem po 1 sekundzie głównego Goroutine zmienia harmonogram i wykonuje swoje działania. Ta procedura jest kontynuowana aż do osiągnięcia wartości z<5, w którym to momencie główny Goroutine się kończy. W takim przypadku zarówno Goroutine, jak i normalna funkcja są w stanie działać wydajnie. Goroutines zapewniają następujące korzyści:
o Goroutines są tańsze niż wątki.
o Goroutines są przechowywane na stosie, a rozmiar stosu może się zwiększać i zmniejszać w zależności od potrzeb programu. Jednak rozmiar stosu w wątkach jest stały.
o Goroutines mogą wchodzić w interakcje przez kanał, a kanały te mają na celu zapobieganie problemom związanym z wyścigiem podczas korzystania z Goroutines w celu uzyskania dostępu do pamięci współdzielonej.
o Załóżmy, że program ma pojedynczy wątek z dołączonymi do niego kilkoma Goroutines. Jeśli którykolwiek z Goroutines zablokuje wątek z powodu ograniczeń zasobów, wszystkie pozostałe Goroutines zostaną przypisane do nowo wygenerowanego wątku systemu operacyjnego. Programiści nie są świadomi żadnej z tych informacji.
Anonimowe Goroutines
W Go możemy uruchomić Goroutine dla anonimowej funkcji, lub innymi słowy, możemy skonstruować anonimowy Goroutine po prostu używając słowa kluczowego go jako przedrostka tej funkcji, jak widać w następującej składni:
Składnia:
// the Anonymous function call
go func (parameterlist){
// statement..
}(arguments)
Przykład:
// Program to illustrate how
// to create anonymous Goroutine
package main
import (
"fmt"
"time"
)
// the main function
func main() {
fmt.Println("Welcome to the main function")
// Creating the Anonymous Goroutine
go func() {
fmt.Println("Welcome to ourworld")
}()
time.Sleep(1 * time.Second)
fmt.Println("GoodBye ")
}
INSTRUKCJA SELECT
Instrukcja select w Go jest podobna do instrukcji switch; jednakże instrukcja case w instrukcji select odnosi się do komunikacji, tj. operacji wysyłania lub odbierania na kanale.
Składnia:
select{
case SendOrReceive1: // Statement..
case SendOrReceive2: // Statement..
case SendOrReceive3: // Statement..
.
.
default: // Statement..
Należy wziąć pod uwagę:
o W pewnych okolicznościach instrukcja select czeka, aż komunikacja (operacja wysyłania lub odbierania) będzie gotowa przed kontynuowaniem.
Przykład:
// Program to illustrate
// the concept of select statement
package main
import("fmt"
"time")
// function 1
func portal1(channel1 chan string) {
time.Sleep(3*time.Second)
channel1 <- "Welcome to channel1"
}
// function 2
func portal2(channel2 chan string) {
time.Sleep(9*time.Second)
channel2 <- "Welcome to channel2"
}
// the main function
func main(){
// Creating the channels
R1:= make(chan string)
R2:= make(chan string)
// calling function 1
// and function 2 in the goroutine
go portal1(R1)
go portal2(R2)
select{
// case 1 for portal1
case op1:= <- R1:
fmt.Println(op1)
// case 2 for portal2
case op2:= <- R2:
fmt.Println(op2)
}
}
Objaśnienie: W poprzednim programie portal1 był uśpiony przez 3 sekundy, a portal2 był uśpiony przez 9 sekund przed uruchomieniem. Teraz instrukcja select czeka, aż skończy się ich czas uśpienia, a następnie wybiera przypadek 2 i wyświetla komunikat "Witamy na kanale 1". Jeśli portal 1 obudzi się przed portalem 2, wyjściem będzie "witamy w kanale 2".
o Jeśli instrukcja select nie zawiera instrukcji case, będzie czekać w sposób nieokreślony.
Składnia:
select{}
Przykład:
// Program to illustrate
// the concept of select statement
package main
// the main function
func main() {
// Select statement without any case
select{ }
}
o Domyślna instrukcja select służy do zapobiegania blokowaniu instrukcji select. Ta instrukcja jest wykonywana, gdy nie ma instrukcji case, a instrukcja jest gotowa do kontynuacji.
Przykład:
// Program to illustrate
// the concept of select statement
package main
import "fmt"
// the main function
func main() {
// the creating channel
mychannel:= make(chan int)
select{
case <- mychannel:
default:fmt.Println("Not-found")
}
}
o Gdy żadna instrukcja case nie jest gotowa, a instrukcja select nie zawiera żadnych instrukcji domyślnych, instrukcja select zostanie zablokowana, dopóki co najmniej jedna instrukcja case lub komunikacja nie będą mogły być kontynuowane.
Przykład:
// Program to illustrate
// the concept of select statement
package main
// the main function
func main() {
// creating the channel
mychannel:= make(chan int)
// channel is not ready and
// no default case
select{
case <- mychannel:
}
}
o Jeśli wiele przypadków jest gotowych do kontynuowania, można wybrać losowo w instrukcji select.
Przykład:
// Program to illustrate
// the concept of select statement
package main
import "fmt"
// function 1
func portal1(channel1 chan string){
for i := 0; i <= 4; i++{
channel1 <- "Welcome to channel1"
}
}
// function 2
func portal2(channel2 chan string){
channel2 <- "Welcome to channel2"
}
// the main function
func main() {
// Creating the channels
R1:= make(chan string)
R2:= make(chan string)
// calling the function 1 and function 2 in
goroutine
go portal1(R1)
go portal2(R2)
// the choice of selection of case is random
select{
case op1:= <- R1:
fmt.Println(op1)
case op2:= <- R2:
fmt.Println(op2)
}
}
WIELE GOROUTINE
Goroutine to funkcja lub metoda w naszym programie, która działa niezależnie i równolegle z innymi Goroutine. Innymi słowy, każda współbieżnie wykonywana akcja w języku programowania Go jest określana jako Goroutine. Możemy mieć kilka gorutyn w jednym programie w języku programowania Go. Możemy łatwo skonstruować goroutine, poprzedzając wywołanie funkcji lub metody słowem kluczowym go, jak ilustruje to następująca składnia:
func name(){
// statement(s)
}
// using go keyword as
// the prefix of your function call
go name()
Za pomocą przykładu zbadamy teraz, jak utworzyć i pracować nad kilkoma goroutines:
// Program to illustrate the Multiple Goroutines
package main
import (
"fmt"
"time"
)
// For goroutine 1
func Aname() {
arr1 := [4]string{"Ronik", "Sunita", "Arman",
"Tia"}
for tk1 := 0; tk1 <= 3; tk1++ {
time.Sleep(150 * time.Millisecond)
fmt.Printf("%s\n", arr1[tk1])
}
}
// For goroutine 2
func Aid() {
arr2 := [4]int{400, 201, 402, 203}
for tk2 := 0; tk2 <= 3; tk2++ {
time.Sleep(500 * time.Millisecond)
fmt.Printf("%d\n", arr2[tk2])
}
}
// the main function
func main() {
fmt.Println("!The Main Go-routine Start!")
// calling Goroutine 1
go Aname()
// calling Goroutine 2
go Aid()
time.Sleep(2900 * time.Millisecond)
fmt.Println("\n! The Main Go-routine End!")
}
1. Tworzenie: Z powyższego przykładu mamy dwie goroutine i główną goroutine, czyli Aname i Aid. Tutaj Aname drukuje nazwiska autorów, a Aid drukuje identyfikator autorów.
2. Praca: Mamy tutaj dwie goroutines, Aname i Aid, oraz jedną główną goroutine. Kiedy uruchamiamy ten program, startuje główna procedura goroutine i wypisuje "!Main Go-routine Start!" Ponieważ główny goroutine jest jak rodzic, a inne goroutines są jego dziećmi, główny goroutine działa jako pierwszy, a następnie inne goroutines, a jeśli główny goroutine się kończy, inne goroutines również się kończą. W rezultacie, po głównym goroutine, goroutines Aname i Aid zaczynają działać równolegle
KANAŁ GoLang
Kanał w Go to medium, za pośrednictwem którego goroutine komunikuje się z innym goroutine w sposób wolny od blokad. Innymi słowy, kanał jest mechanizmem, który pozwala jednemu gorutynowi przesyłać dane do drugiego. Kanał jest domyślnie dwukierunkowy, co oznacza, że gorutyny mogą przesyłać i odbierać dane tym samym kanałem, jak pokazano na poniższym rysunku.
Tworzenie kanału
Kanał jest tworzony w Go za pomocą słowa kluczowego chan i może przesyłać tylko dane tego samego rodzaju; z tego samego kanału nie można przesyłać wielu typów danych.
Składnia:
var Channelname chan Type
Możemy również użyć skróconej deklaracji do zbudowania kanału z metodą make().
Składnia:
channelname:= make(chan Type)
Przykład:
// Program to illustrate
// how to create channel
package main
import "fmt"
func main() {
// Creating channel
// Using the var keyword
var mychannel chan int
fmt.Println("The Value of the channel: ",
mychannel)
fmt.Printf("The Type of the channel: %T ",
mychannel)
// Creating channel using the make() function
mychannel1 := make(chan int)
fmt.Println("\nThe Value of the channel1: ",
mychannel1)
fmt.Printf("The Type of the channel1: %T ",
mychannel1)
}
Wysyłaj i odbieraj dane z kanału
W języku programowania Go kanały wykonują dwie podstawowe operacje: wysyłanie i odbieranie, zwane łącznie komunikacją. A to, czy dane są odbierane, czy wysyłane, jest wskazywane przez kierunek operatora <-. Domyślnie operacje wysyłania i odbierania w kanale są blokowane, dopóki druga strona nie będzie gotowa. Umożliwia gorutynom komunikowanie się ze sobą bez wyraźnych blokad lub zmiennych warunków.
Operacja wysyłania
Operacja wysyłania wysyła dane z jednej gorutyny do drugiej przez kanał. Wartości, takie jak int, float64 i bool, są bezpieczne i proste do przesłania przez kanał, ponieważ są kopiowane, co eliminuje możliwość przypadkowego równoczesnego dostępu do tej samej wartości. Łańcuchy są podobnie bezpieczne do przesyłania, ponieważ są niezmienne. Jednak przesyłanie wskaźników lub odniesień, takich jak wycinek, mapa itp., przez kanał nie jest bezpieczne, ponieważ wartość wskaźników lub odniesień może ulec zmianie podczas wysyłania lub odbierania gorutyny w tym samym czasie, co skutkuje nieprzewidywalnymi konsekwencjami. W rezultacie, używając wskaźników lub odwołań w kanale, musimy upewnić się, że mogą one uzyskać dostęp tylko przez jedną goroutine na raz.
Mój kanał <- element
Powyższe zdanie wskazuje, że dane (element) zostały przesłane do kanału (Mój kanał) za pomocą operatora <-.
Operacja odbioru
Operacja odbierania służy do odbierania danych wysłanych przez operatora wysyłania.
element := <-Mój kanał
Zgodnie z powyższym zdaniem element pobiera dane z kanału (Mychannel). Jeżeli wynik otrzymanego oświadczenia nie będzie wykorzystany, oświadczenie jest również ważne. Instrukcję odbioru można alternatywnie zapisać jako:
<-Mój kanał
Przykład:
// Program to illustrate send and
// receive operation
package main
import "fmt"
func myfunc(ch chan int) {
fmt.Println(234 + <-ch)
}
func main() {
fmt.Println("Main method start")
// Creating channel
ch := make(chan int)
go myfunc(ch)
ch <- 23
fmt.Println("Main method end")
}
Zamknięcie kanału
Możemy również użyć metody close() do zamknięcia kanału. Ta wbudowana funkcja ustawia flagę wskazującą, że żadne dodatkowe dane nie będą wysyłane do tego kanału.
close()
Możemy również użyć pętli for range, aby zamknąć kanał. Goroutine odbiornika może użyć następującej składni, aby określić, czy kanał jest otwarty, czy zamknięty:
Składnia:
ele, ok:= <- Mój kanał
Jeśli wartość ok jest równa true, oznacza to, że kanał jest otwarty i można wykonywać operacje odczytu. A jeśli wartość jest fałszywa, oznacza to, że kanał jest zamknięty; w związku z tym operacje odczytu zakończą się niepowodzeniem.
Przykład:
// program to illustrate
// how to close channel using
// for range loop and close function
package main
import "fmt"
// Function
func myfun(mychnl chan string) {
for k := 0; k < 4; k++ {
mychnl <- "Helloeveryone"
}
close(mychnl)
}
// the main function
func main() {
// Creating channel
ch := make(chan string)
// calling Goroutine
go myfun(ch)
// When value of ok is
// set to true means
// channel is open and
// it can send or receive data
// When value of ok is set to
// false means channel is closed
for {
rest, ok := <-c
if ok == false {
fmt.Println("Channel-Close ", ok)
break
}
fmt.Println("Channel-Open ", rest, ok)
}
}
Ważne notatki:
o Blokowanie wysyłania i odbierania: Kiedy dane są przesyłane do kanału, sterowanie jest blokowane w tej instrukcji wysyłania, dopóki inna goroutine nie odczyta tego kanału. Podobnie, gdy kanał pobiera dane z goroutine, polecenie odczytu jest blokowane do czasu wykonania innej instrukcji goroutine.
o Kanał z wartością zerową: Wartość zerowa kanału wynosi zero.
o Dla pętli kanału: Pętla for może przeglądać wartości wysyłane w kanale, aż do jej zamknięcia.
Składnia:
for item := range Chnl {
// statement(s)
}
Przykład:
// Program to illustrate how
// to use for loop in the channel
package main
import "fmt"
// the main function
func main() {
// Creating channel
// Using the make() function
mychnl := make(chan string)
// Anonymous goroutine
go func() {
mychnl <- "HFE"
mychnl <- "hfe"
mychnl <- "hello"
mychnl <- "Hellofromeveryone"
close(mychnl)
}()
// Using the for loop
for rest := range mychnl {
fmt.Println(rest)
}
}
o Długość kanału: Długość kanału można znaleźć w kanale za pomocą metody len(). W tym przypadku długość wskazuje liczbę wartości umieszczonych w kolejce w buforze kanału.
Przykład:
// Program to illustrate how to
// find the length of channel
package main
import "fmt"
// the main function
func main() {
// Creating channel
// Using the make() function
mychnl := make(chan string, 4)
mychnl <- "HFE"
mychnl <- "hfe"
mychnl <- "Hello"
mychnl <- "Hellofromeveryone"
// Finding length of the channel
// Using the len() function
fmt.Println("The Length of channel is: ",
len(mychnl))
}
o Przepustowość kanału: Funkcja cap() w kanale może być wykorzystana do określenia przepustowości kanału. Pojemność określa rozmiar bufora w tym przypadku.
Przykład:
// Program to illustrate
// how to find the capacity of the channel
package main
import "fmt"
// the main function
func main() {
// Creating channel
// Using the make() function
mychnl := make(chan string, 5)
mychnl <- "HFE"
mychnl <- "hfe"
mychnl <- "Geeks"
mychnl <- "Helloeveryone"
// Finding the capacity of channel
// Using the cap() function
fmt.Println("The Capacity of the channel is:
", cap(mychnl))
}
o Instrukcja Select i Case w kanale: Instrukcja select w Go jest podobna do instrukcji switch w tym, że nie przyjmuje żadnych parametrów wejściowych. Ta instrukcja pick jest używana w kanale do wykonania pojedynczej operacji z listy wielu operacji bloku sprawy.
KANAŁ JEDNOKIERUNKOWY
Jak wiemy, kanał jest mechanizmem komunikacji między jednocześnie wykonującymi się gorutynami, który umożliwia im wysyłanie i odbieranie danych od siebie nawzajem. Domyślnie kanał dwukierunkowy, ale możemy też zbudować kanał jednokierunkowy. Kanał jednokierunkowy może tylko odbierać dane lub taki, który może tylko wysyłać dane. Metodę make() można również wykorzystać do skonstruowania kanału jednokierunkowego, jak pokazano poniżej:
// Only to receive the data
c1:= make(<- chan bool)
// Only to send the data
c2:= make(chan<-bool)
Przykład:
// Program to illustrate concept
// of unidirectional channel
package main
import "fmt"
// the main function
func main() {
// Only for receiving
mychanl1 := make(<-chan string)
// Only for sending
mychanl2 := make(chan<- string)
// Display types of channels
fmt.Printf("%T", mychanl1)
fmt.Printf("\n%T", mychanl2)
}
Konwersja kanału dwukierunkowego na kanał jednokierunkowy
W Go możemy przekonwertować kanał dwukierunkowy na kanał jednokierunkowy lub innymi słowy kanał dwukierunkowy na kanał tylko do odbioru lub tylko do wysyłania, ale nie odwrotnie. Jest to pokazane w następującym programie:
Przykład:
// Program to illustrate how to
// convert bidirectional channel into
// the unidirectional channel
package main
import "fmt"
func sending(s chan<- string) {
s <- "Helloeveryone"
}
func main() {
// Creating bidirectional channel
mychanl := make(chan string)
// Here, sending() function convert
// bidirectional channel into send only channel
go sending(mychanl)
// Here, channel is sent
// only inside goroutine
// outside goroutine the
// channel is bidirectional
// So, it print Helloeveryone
fmt.Println(<-mychanl)
}
Użycie kanału jednokierunkowego: kanał jednokierunkowy jest używany do zapewnienia programowi bezpieczeństwa typu, co skutkuje mniejszą liczbą błędów. Możemy użyć kanału jednokierunkowego, gdy chcemy stworzyć kanał, który może tylko wysyłać lub odbierać dane. W tym rozdziale omówiliśmy programowanie współbieżne w Go, jak radzić sobie z problemami współbieżności w Go, jak utworzyć instrukcję Goroutine i select. Omówiliśmy również wiele Goroutines i kanał GoLang.
Pakiety w GoLang
Podczas tej sesji przeanalizujemy pakiety w języku programowania Go. Pisanie łatwego do utrzymania i wielokrotnego użytku kodu ma kluczowe znaczenie podczas tworzenia aplikacji. Dzięki ekosystemowi pakietów Go zapewnia modułowość i możliwość ponownego wykorzystania kodu. Go zachęca nas do tworzenia małych fragmentów oprogramowania jako pakietów, a następnie używania tych małych pakietów do komponowania naszych programów.
Obszar roboczy
Zanim przejdziemy do pakietów Go, porozmawiajmy o kodzie strukturalnym w Workspace. Programy w Go są utrzymywane w strukturze katalogów zwanej przestrzenią roboczą. Obszar roboczy to nic innego jak katalog główny dla naszych aplikacji Go. W katalogu głównym obszaru roboczego znajdują się trzy podkatalogi:
o src: Ten katalog zawiera pliki źródłowe pogrupowane w pakiety. W tym katalogu będziemy rozwijać nasze programy Go.
o pkg: obiekty pakietu Go są przechowywane w tym katalogu.
o bin: Ten katalog zawiera programy, które mogą być wykonywane.
Zanim zaczniemy pisać programy w Go, musimy najpierw zdefiniować położenie obszaru roboczego. GOPATH to zmienna środowiskowa określająca lokalizację obszarów roboczych Go.
Pakiety
W Go pliki źródłowe są pogrupowane w foldery systemowe zwane pakietami, co umożliwia ponowne wykorzystanie kodu w programach Go. Konwencja nazewnictwa pakietów Go wykorzystuje nazwę katalogu systemowego, w którym przechowujemy nasze pliki źródłowe Go. Nazwa pakietu będzie taka sama dla wszystkich plików źródłowych zawartych w tym katalogu w jednym folderze. Programy Go tworzymy w katalogu $GOPATH, gdzie organizujemy pliki kodu źródłowego w pakiety jako katalogi. Wszystkie identyfikatory w pakietach Go są eksportowane do innych pakietów, jeśli pierwsza litera nazwy identyfikatora jest wielka. Jeśli nazwę identyfikatora zaczniemy małą literą, funkcje i typy nie będą eksportowane do innych pakietów. Standardowa biblioteka Go zawiera mnóstwo pomocnych pakietów do tworzenia aplikacji w świecie rzeczywistym. Na przykład standardowa biblioteka zawiera pakiet "net/http", którego można używać do tworzenia aplikacji i usług internetowych. Standardowe pakiety bibliotek mogą znajdować się w podfolderze "pkg" katalogu GOROOT. Podczas instalacji Go do naszego systemu dodawana jest zmienna środowiskowa o nazwie GOROOT, która określa ścieżkę instalacji Go. Społeczność programistów Go jest zachwycona perspektywą tworzenia pakietów Go innych firm. Te pakiety Go innych firm mogą być używane do tworzenia aplikacji Go.
Pakiet main
Kiedy tworzymy kod wielokrotnego użytku, utworzysz pakiet jako bibliotekę współdzieloną. Jednak podczas tworzenia aplikacji wykonywalnych wykorzystamy pakiet "main" do przekształcenia pakietu w program wykonywalny. Pakiet "main" instruuje kompilator Go, aby skonstruował pakiet jako wykonywalną aplikację, a nie bibliotekę współdzieloną. Główna funkcja w pakiecie "main" będzie służyć jako punkt wejścia programu wykonywalnego. Podczas tworzenia bibliotek współdzielonych w pakiecie nie będzie pakietu głównego ani głównej funkcji. Oto przykładowy program wykonywalny, który używa pakietu main, z funkcją main służącą jako punkt wejścia.
package main
import (
"fmt"
)
func main(){
fmt.Println("Hello, Everyone")
}
Importowanie pakietów
Podczas importowania pakietu do innego pakietu używany jest "import". Zaimportowaliśmy pakiet "fmt" do przykładowego programu w Code, aby użyć metody Println. Pakiet "fmt" jest częścią standardowej biblioteki Go. Gdy importujemy pakiety, kompilator Go wyszukuje je w miejscach wskazanych przez zmienne środowiskowe GOROOT i GOPATH. Katalog GOROOT zawiera pakiety z biblioteki standardowej. Lokalizacja GOPATH zawiera pakiety, które napisaliśmy, oraz pakiety stron trzecich, które zaimportowaliśmy.
Instalowanie pakietów innych firm
Możemy pobierać i instalować pakiety Go innych firm za pomocą polecenia "Go get". Polecenie Go get pobierze pakiety z repozytorium źródłowego i umieści je w lokalizacji GOPATH. W terminalu wpisz następujące polecenie, aby zainstalować "mgo", pakiet sterowników Go innej firmy dla MongoDB, w naszym GOPATH, którego można użyć we wszystkich projektach w katalogu GOPATH:
go get gopkg.in/mgo.v2
Po zainstalowaniu mgo dodaj następującą instrukcję importu do naszych aplikacji, aby ponownie użyć kodu:
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
Sterownik MongoDB, mgo, udostępnia dwa pakiety, które zaimportowaliśmy w poprzedniej instrukcji importu.
Funkcja Init
Pisząc pakiety Go, możemy dołączyć funkcję o nazwie "init", która jest wywoływana na początku okresu wykonania. Funkcja init jest przydatna do dodawania logiki inicjalizacji do pakietu.
package db
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
func init {
// here initialization-code
}
W niektórych przypadkach możemy potrzebować zaimportować pakiet, aby wywołać jego funkcję init i nie musimy wywoływać żadnych innych metod pakietu. Jeśli zaimportujemy pakiet, ale nie użyjemy identyfikacji pakietu w programie, kompilator Go zgłosi skargę. W takim przypadku możemy użyć pustego identyfikatora (_) jako nazwy aliasu pakietu. Kompilator przeoczy pomyłkę polegającą na nieużyciu identyfikatora pakietu podczas wywoływania funkcji init.
package main
import (
_ "mywebapp/libs/mongodb/db"
"fmt"
"log"
)
func main() {
//implementation-here
}
Zaimportowaliśmy pakiet o nazwie db do powyższego przykładowego programu. Załóżmy, że chcemy użyć tego pakietu do wywołania funkcji init. Pusty identyfikator pozwoli uniknąć błędu kompilatora Go i wykonać funkcję init określoną w pakiecie. Aby uniknąć niejednoznaczności nazw pakietów, możemy używać nazw aliasów dla pakietów.
package main
import (
mongo "mywebapp/libs/mongodb/db"
mysql "mywebapp/libs/mysql/db"
)
func main() {
mongodata :=mongo.Get() //calling the method of
package "mywebapp/libs/mongodb/db"
sqldata:=mysql.Get() //calling the method of
package "mywebapp/libs/mysql/db"
fmt.Println(mongodata )
fmt.Println(sqldata )
}
Importujemy dwie oddzielne paczki z dwóch różnych lokalizacji, ale ich nazwy są identyczne. Możemy utworzyć nazwę aliasu dla pojedynczego pakietu i używać jej w dowolnym momencie, gdy potrzebujemy wywołać metodę w tym pakiecie.
Ważne uwagi
1. Ścieżki importu: W języku programowania Go każdy pakiet jest określony przez unikalny ciąg zwany ścieżką importu. Możemy importować pakiety do naszego programu przy użyciu trasy importu. Jako przykład:
import "fmt"
Jak stwierdzono w tym zdaniu, importujemy pakiet fmt do naszego programu. Ścieżki importu pakietów są unikalne w skali globalnej. Aby uniknąć konfliktów ze ścieżkami pakietów innych niż biblioteka standardowa, ścieżka pakietu powinna zaczynać się od nazwy domeny internetowej podmiotu, który jest właścicielem lub hostem pakietu. Jako przykład:
import "geeksforgeeks.com/example/strings"
2. Deklaracja pakietu: W języku programowania Go deklaracja pakietu jest zawsze dołączana na początku pliku źródłowego. Jego funkcją jest ustawienie domyślnego identyfikatora dla tego pakietu, gdy inny pakiet go importuje. Jako przykład:
pacjage main
3. Deklaracja przywozowa: Deklaracja przywozowa następuje bezpośrednio po deklaracji paczki. Plik źródłowy Go zawiera co najmniej jedną deklarację importu, z których każda podaje w nawiasach ścieżkę do jednego lub większej liczby pakietów. Jako przykład:
// Importing the single package
import "fmt"
// Importing the multiple packages
import(
"fmt"
"strings"
"bytes"
)
Kiedy importujemy pakiet do naszego programu, mamy dostęp do członków pakietu. Na przykład mamy pakiet o nazwie "sort" i możemy uzyskać dostęp do sortowania po zaimportowaniu go do naszego programu. Sortuj, Float64s() SearchStrings() tego pakietu i inne funkcje.
4. Pusty import: W programowaniu Go zdarzają się sytuacje, w których importujemy pewne pakiety, ale ich nie wykorzystujemy. Kiedy uruchomimy programy zawierające nieużywane pakiety, kompilator wygeneruje błąd. Używamy pustego identyfikatora przed nazwą pakietu, aby obejść ten problem. Jako przykład:
import _ "strings"
Nazywa się to pustym importem. Jest używany w kilku sytuacjach, gdy główny program może włączyć dodatkowe możliwości zapewniane przez puste importowanie dodatkowych pakietów w czasie kompilacji.
5. Pakiety zagnieżdżone: W Go możemy zbudować pakiet w innym pakiecie, po prostu ustanawiając podkatalog. Zagnieżdżony pakiet, podobnie jak pakiet główny, może zostać zaimportowany. Jako przykład:
import "math/cmplx"
Pakiet math jest w tym przypadku pakietem podstawowym, podczas gdy pakiet cmplx jest pakietem zagnieżdżonym.
6. Chociaż niektóre pakiety mogą mieć tę samą nazwę, droga do takich pakietów jest zawsze inna. Na przykład zarówno pakiet math, jak i crypto mają pakiet o losowej nazwie, ale ich ścieżki są różne, tj. math/rand i crypto/rand.
7. Dlaczego w programowaniu Go główny pakiet jest zwykle na początku programu? Ponieważ główny pakiet instruuje kompilację go, że linker musi włączyć, aby utworzyć plik wykonywalny.
Nadawanie nazw pakietom
Nazywając pakiet w Go, musimy zawsze pamiętać o następujących kryteriach:
o Konstruując opakowanie, musimy zachować krótką i zwięzłą nazwę. Łańcuchy, czas, flagi i tak dalej to przykłady standardowych pakietów bibliotek.
o Nazwa pakietu powinna być opisowa i jasna.
o Zawsze staraj się unikać używania nazw już używanych lub używanych dla lokalnych zmiennych względnych.
o Nazwa paczki jest zwykle zapisywana w liczbie pojedynczej. Aby zapobiec konfliktom słów kluczowych, kilka pakietów nazywa się w liczbie mnogiej, na przykład łańcuchy, bajty, bufory i tak dalej.
o Zawsze unikaj nazw pakietów, które mają już istniejące znaczenie.
Przykład:
// Program to illustrate
// the concept of packages
// Package declaration
package main
// Importing the multiple packages
import (
"bytes"
"fmt"
"sort"
)
func main() {
// Creating and initializing the slice
// Using the shorthand declaration
slice_1 := []byte{'*', 'H', 'e', 'l', 'l',
'o', 'f',
'o', 'r', 'W', 'o', 'r', 'k', 's', '^', '^'}
slice_2 := []string{"hel", "lo", "for", "wor",
"ks"}
// Displaying the slices
fmt.Println("Original-Slice:")
fmt.Printf("Slice 1 : %s", slice_1)
fmt.Println("\nSlice 2: ", slice_2)
// Trimming the specified leading
// and trailing Unicode points
// from given slice of bytes
// Using the Trim function
res := bytes.Trim(slice_1, "*^")
fmt.Printf("\nNew Slice : %s", res)
// Sorting the slice 2
// Using the Strings function
sort.Strings(slice_2)
fmt.Println("\nSorted slice:", slice_2)
}
Wyeksportowany kod
Mogliśmy zauważyć, że wszystkie deklaracje w wywołanym przez nas pliku greet.go były pisane wielkimi literami. Go, w przeciwieństwie do innych języków, nie ma idei publicznych, prywatnych ani chronionych modyfikatorów. Wielkie litery rządzą widocznością na zewnątrz. Typy, zmienne, funkcje i zaczynające się wielką literą są publicznie dostępne poza bieżącym pakietem. Symbol, który można zobaczyć poza jego pojemnikiem, jest określany jako wyeksportowany. Jeśli dodamy nową metodę resetowania do Octopusa, możemy ją wywołać z pakietu powitalnego, ale nie z naszego pliku main.go, który nie jest częścią pakietu powitalnego:
package greet
import "fmt"
var Shark = "Rammy"
type Octopus struct {
Name string
Color string
}
func (o Octopus) String() string {
return fmt.Sprintf("Octopus's name is %q and
the color %s.", o.Name, o.Color)
}
func (o *Octopus) reset() {
o.Name = ""
o.Color = ""
}
func Hello() {
fmt.Println("Hello, Everyone")
}
Jeśli spróbujemy wywołać reset z main. kontynuuj i złóż:
package main
import (
"fmt"
"github.com/gopherguides/greet"
)
func main() {
greet.Hello()
fmt.Println(greet.Shark)
oct := greet.Octopus{
Name: "Tessa",
Color: "White",
}
fmt.Println(oct.String())
oct.reset()
}
Otrzymamy błąd kompilacji. Aby wyeksportować funkcję resetowania Octopus, pisz wielką literą R w resetowaniu:
package greet
import "fmt"
var Shark = "Rammy"
type Octopus struct {
Name string
Color string
}
func (o Octopus) String() string {
return fmt.Sprintf("The octopus's name is %q
and is the color %s.", o.Name, o.Color)
}
func (o *Octopus) Reset() {
o.Name = ""
o.Color = ""
}
func Hello() {
fmt.Println("Hello, Everyone")
}
W konsekwencji możemy użyć opcji Resetuj z innego pakietu, nie widząc błędu:
package main
import (
"fmt"
"github.com/gopherguides/greet"
)
func main() {
greet.Hello()
fmt.Println(greet.Shark)
oct := greet.Octopus{
Name: "Tessa",
Color: "White",
}
fmt.Println(oct.String())
oct.Reset()
fmt.Println(oct.String())
}
Teraz, jeśli uruchomimy program:
$ go run main.go
DOKUMENTACJA
Go zapewnia możliwość tworzenia dokumentacji dla opracowywanych przez nas pakietów, porównywalnej do zwykłej dokumentacji paczki. Uruchom następujące polecenie w terminalu:
godoc golang-book/chapter11/math Average
Możemy udoskonalić tę dokumentację, dodając następującą uwagę przed funkcją:
// Finds the average of a series of numbers
func Average(xs []float64) float64 {
Jeśli uruchomimy go install w folderze math, a następnie godoc, powinniśmy zauważyć naszą uwagę pod definicją funkcji. Ta dokumentacja jest również dostępna w formie online, jeśli wykonamy następujące polecenie:
godoc -http=":6060"
i wprowadź następujący adres URL do naszej przeglądarki:
http://localhost:6060/pkg/
Powinniśmy przejrzeć wszystkie pakiety w naszym systemie.
Pakiety podstawowe
STRINGS
W pakiecie strings, Strings Go zawiera szeroką gamę funkcji do pracy z łańcuchami:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(
// true
strings.Contains("rest", "es"),
// 2
strings.Count("rest", "r"),
// true
strings.HasPrefix("rest", "re"),
// true
strings.HasSuffix("rest", "st"),
// 1
strings.Index("rest", "e"),
// "x-y"
strings.Join([]string{"x","y"}, "-"),
// == "xxxxx"
strings.Repeat("x", 5),
// "yyxx"
strings.Replace("xxxx", "x", "y", 2),
// []string{"x","y","z","a","b"}
strings.Split("x-y-z-a-b", "-"),
// "rest"
strings.ToLower("REST"),
// "REST"
strings.ToUpper("rest"),
)
}
Czasami musimy pracować z łańcuchami jako danymi binarnymi. Aby przekonwertować ciąg na wycinek bajtów, wykonaj następujące czynności:
arr := []byte("rest")
str := string([]byte{'r','e','s','t'})
WEJŚCIE/WYJŚCIE (we/wy)
Pakiet io zawiera kilka funkcji, z których większość to interfejsy używane przez inne pakiety. Reader i Writer to dwa główne interfejsy. Czytelnicy pomagają w czytaniu przy użyciu metody Read. Pisarze pomagają pisarzom przy użyciu metody Write. Wiele funkcji Go przyjmuje jako argumenty Czytelników lub Pisarzy. Na przykład pakiet io zawiera funkcję Kopiuj, która przesyła dane z programu Reader do Writer:
func Copy(dst Writer, src Reader) (written int64, err error)
Struktury Buffer z pakietu bytes można użyć do odczytu lub zapisu do [] bajtu lub łańcucha znaków:
var buf bytes.Buffer
buf.Write([]byte("test"))
Bufor nie musi być inicjowany i może być używany z interfejsami Reader i Writer. Buf może użyć do przekonwertowania go na []bajt, wywołując bug.Bytes(). Możemy również użyć ciągów znaków, jeśli musimy odczytać z łańcucha. Metoda NewReader jest szybsza niż użycie bufora.
PLIKI I FOLDERY
Aby otworzyć plik, użyj funkcji Otwórz pakietu systemu operacyjnego. Przykład odczytania zawartości pliku i wyświetlenia jej na terminalu:
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("rest.txt")
if err != nil {
// handle error here
return
}
defer file.Close()
// get file size
stat, err := file.Stat()
if err != nil {
return
}
// read file
bs := make([]byte, stat.Size())
_, err = file.Read(bs)
if err != nil {
return
}
str := string(bs)
fmt.Println(str)
}
Używamy odroczonego pliku. Close() powinno zostać wywołane natychmiast po otwarciu pliku, aby upewnić się, że zostanie on zamknięty natychmiast po zakończeniu funkcji. Ponieważ czytanie plików jest tak powszechne, istnieje szybszy sposób, aby to osiągnąć:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
bs, err := ioutil.ReadFile("rest.txt")
if err != nil {
return
}
str := string(bs)
fmt.Println(str)
}
Oto jak moglibyśmy przejść do tworzenia pliku:
package main
import (
"os"
)
func main() {
file, err := os.Create("rest.txt")
if err != nil {
// handle error here
return
}
defer file.Close()
file.WriteString("rest")
}
Aby pobrać zawartość katalogu, używamy tej samej metody os.Open, ale tym razem przekazujemy ścieżkę do katalogu, a nie nazwę pliku. Następnie wywoływana jest metoda Readdir:
package main
import (
"fmt"
"os"
)
func main() {
dir, err := os.Open(".")
if err != nil {
return
}
defer dir.Close()
fileInfos, err := dir.Readdir(-1)
if err != nil {
return
}
for _, fi := range fileInfos {
fmt.Println(fi.Name())
}
}
Często chcemy rekurencyjnie chodzić po folderze (przeczytać zawartość folderu, wszystkie podfoldery, wszystkie podfoldery,
). Aby w tym pomóc, pakiet path/filepath ma funkcję Walk:
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
filepath.Walk(".", func(path string, info
os.FileInfo, err error) error {
fmt.Println(path)
return nil
})
}
Funkcja wywołuje każdy plik i folder w folderze głównym, który przekazujemy do Walk.
BŁĘDY
Go zawiera wbudowany typ dla wcześniej widzianych błędów (typ błędu). Korzystając z funkcji New w pakiecie błędów, możemy zbudować własne błędy:
package main
import "errors"
func main() {
err := errors.New("error-message")
}
POJEMNIKI I SORTOWANIE
Pakiet kontenerów Go zawiera wiele różnych kolekcji oprócz list i map. Jako przykład rozważmy pakiet kontenera/listy.
Lista
Pakiet list implementuje podwójnie połączoną listę. Połączona lista to forma struktury danych, która wygląda następująco:
Każdy węzeł na liście ma wartość (w tym przykładzie 1, 2 lub 3) i łącze do następnego węzła. Ponieważ jest to lista podwójnie połączona, każdy węzeł ma wskaźnik do węzła poprzedzającego. Ten program może wygenerować następującą listę:
package main
import ("fmt" ; "container/list")
func main() {
var y list.List
y.PushBack(1)
y.PushBack(2)
y.PushBack(3)
for c := y.Front(); c != nil; c=c.Next() {
fmt.Println(c.Value.(int))
}
}
Lista z wartością zero jest listą pustą (*List można również wygenerować za pomocą list.New). PushBack służy do dołączania wartości do listy. Zapętlamy listę, zaczynając od pierwszego elementu i podążając za wszystkimi połączeniami, aż osiągniemy zero.
SORTOWANIE
Sortowanie dowolnych danych jest obsługiwane przez pakiet sort. Istnieje wiele wbudowanych funkcji sortowania (dla wycinków typu int i float). Oto przykład, w jaki sposób możemy posortować nasze dane:
package main
import ("fmt" ; "sort")
type Person struct {
Name string
Age int
}
type ByName []Person
func (this ByName) Len() int {
return len(this)
}
func (this ByName) Less(x, y int) bool {
return this[x].Name < this[y].Name
}
func (this ByName) Swap(x, y int) {
this[x], this[y] = this[y], this[x]
}
func main() {
kids := []Person{
{"Thill",7},
{"Rach",11},
}
sort.Sort(ByName(kids))
fmt.Println(kids)
}
Funkcja sortowania wykonuje sortowanie. Jest połączony i sortowany. Ten rodzaj. Interfejs wymaga trzech metod: Len, Less i Swap. Tworzymy nowy typ (ByName), który odnosi się do wycinka tego, co chcemy posortować, aby zaprojektować własne sortowanie. Następnie definiuje się trzy techniki. Dlatego sortowanie naszej listy osób jest tak proste, jak rzutowanie listy na nasz nowy typ. Możemy również uporządkować według wieku, wykonując następujące czynności:
type ByAge []Person
func (this ByAge) Len() int {
return len(this)
}
func (this ByAge) Less(x, y int) bool {
return this[x].Age < this[y].Age
}
func (this ByAge) Swap(x, y int) {
this[x], this[y] = this[y], this[x]
}
HASZE I KRYPTOGRAFIA
Funkcja skrótu obniża zbiór danych do mniejszego stałego rozmiaru. Hashe są często używane w programowaniu do różnych celów, od wyszukiwania danych po proste identyfikowanie zmian. W Go funkcje skrótu są klasyfikowane jako kryptograficzne i niekryptograficzne. Niekryptograficzne funkcje skrótu obejmują adler32, crc32, crc64 i fnv, które można znaleźć w pakiecie hash. Oto przykład wykorzystujący crc32:
package main
import (
"fmt"
"hash/crc32"
)
func main() {
x := crc32.NewIEEE()
x.Write([]byte("rest"))
y := h.Sum32()
fmt.Println(y)
}
Ponieważ obiekt hash crc32 implementuje interfejs Writer, możemy zapisywać do niego bajty w taki sam sposób, jak każdy inny Writer. Po wpisaniu wszystkiego, czego potrzebujemy, wywołamy Sum32(), aby uzyskać uint32. Porównanie dwóch plików jest popularnym zastosowaniem crc32. Jeśli wartość Sum32 dla obu plików jest taka sama, jest bardzo prawdopodobne (ale nie pewne), że pliki są takie same. Jeśli wartości się różnią, pliki nie są takie same:
package main
import (
"fmt"
"hash/crc32"
"io/ioutil"
)
func getHash(filename string) (uint32, error) {
bs, err := ioutil.ReadFile(filename)
if err != nil {
return 0, err
}
x := crc32.NewIEEE()
x.Write(bs)
return x.Sum32(), nil
}
func main() {
x1, err := getHash("rest1.txt")
if err != nil {
return
}
x2, err := getHash("rest2.txt")
if err != nil {
return
}
fmt.Println(x1, x2, x1 == x2)
}
Kryptograficzne funkcje skrótu są porównywalne z niekryptograficznymi funkcjami skrótu, ale mają dodatkową właściwość polegającą na tym, że są trudne do odwrócenia. Ustalenie, kto stworzył kryptograficzny skrót zbioru danych, jest skomplikowane. Te skróty są często używane w aplikacjach zabezpieczających. SHA-1 to znana kryptograficzna funkcja skrótu. Oto jak jest używany:
package main
import (
"fmt"
"crypto/sha1"
)
func main() {
x:= sha1.New()
x.Write([]byte("rest"))
bs := x.Sum([]byte{})
fmt.Println(bs)
}
Ponieważ zarówno crc32, jak i sha1 implementują interfejs hash.Hash, ten przykład jest identyczny z crc32. Podstawowym rozróżnieniem jest to, że podczas gdy crc32 generuje 32-bitowy skrót, sha1 generuje 160-bitowy skrót. Ponieważ nie ma natywnego typu reprezentującego 160-bitową liczbę całkowitą, zamiast tego używamy wycinka 20-bajtowego.
SERWERY
Tworzenie serwerów sieciowych w Go jest stosunkowo proste. Zaczniemy od przyjrzenia się, jak utworzyć serwer TCP:
package main
import (
"encoding/gob"
"fmt"
"net"
)
func server() {
// listen on a port
l, err := net.Listen("tcp", ":9999")
if err != nil {
fmt.Println(err)
return
}
for {
// accept a connection
x, err := ln.Accept()
if err != nil {
fmt.Println(err)
continue
}
// handle the connection
go handleServerConnection(x)
}
}
func handleServerConnection(c net.Conn) {
// receive message
var msg string
err := gob.NewDecoder(c).Decode(&msg)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Receive", msg)
}
x.Close()
}
func client() {
// connect to the server
x, err := net.Dial("tcp", "127.0.0.1:9999")
if err != nil {
fmt.Println(err)
return
}
// send message
msg := "Hello Everyone"
fmt.Println("Sending", msg)
err = gob.NewEncoder(x).Encode(msg)
if err != nil {
fmt.Println(err)
}
x.Close()
}
func main() {
go server()
go client()
var input string
fmt.Scanln(&input)
}
W tym przykładzie wykorzystano pakiet encoding/gob, który ułatwia kodowanie wartości Go, aby inne programy Go (lub w tym przypadku ten sam program Go) mogły je odczytać. Dodatkowe kodowania można znaleźć w pakietach poniżej kodowania (takich jak encoding/json) oraz w pakietach innych firm.
http
Serwery HTTP są jeszcze prostsze w konfiguracji i obsłudze:
package main
import ("net/http" ; "io")
func helloo(res http.ResponseWriter, req *http.
Request) {
res.Header().Set(
"Content-Type",
"text/html",
)
io.WriteString(
res,
'< DOCTYPE html >
< html >
< head >
< title >Hello Everyone< /title >
< /head >
< body >
Hello Everyone!
< /body >
< /html >',
)
}
func main() {
http.HandleFunc("/helloo", helloo)
http.ListenAndServe(":9000", nil)
}
HandleFunc obsługuje trasę URL (/helloo) poprzez wywołanie danej funkcji. Możemy również użyć FileServer do obsługi plików statycznych:
http.Handle(
"/assets/",
http.StripPrefix(
"/assets/",
http.FileServer(http.Dir("assets")),
),
)
RPC
Pakiety net/rpc i net/rpc/jsonrpc ułatwiają udostępnianie metod do użycia w sieci (a nie w programie, który je wykonuje).
package main
import (
"fmt"
"net"
"net/rpc"
)
type Server struct {}
func (this *Server) Negate(i int64, reply *int64)
error {
*reply = -i
return nil
}
func server() {
rpc.Register(new(Server))
ln, err := net.Listen("tcp", ":9999")
if err != nil {
fmt.Println(err)
return
}
for {
x, err := ln.Accept()
if err != nil {
continue
}
go rpc.ServeConn(x)
}
}
func client() {
x, err := rpc.Dial("tcp", "127.0.0.1:9999")
if err != nil {
fmt.Println(err)
return
}
var result int64
err = x.Call("Server.Negate", int64(999), &result)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Server.Negate(999) =", result)
}
}
func main() {
go server()
go client()
var input string
fmt.Scanln(&input)
}
Ten program jest identyczny z przykładem TCP, z tą różnicą, że teraz utworzyliśmy obiekt do przechowywania wszystkich metod, które chcemy ujawnić, i wywołaliśmy metodę Negate z klienta.
ANALIZACJA ARGUMENTÓW WIERSZA POLECEŃ
Kiedy uruchamiamy polecenie z terminala, możemy podać mu argumenty. Widzieliśmy to za pomocą polecenia go:
go run mytestfile.go
Argumenty są uruchamiane i mytestfile.go. Możemy również przekazać flagi poleceń:
go run -v mytestfile.go
Możemy użyć pakietu flag do analizy argumentów i flag wysyłanych do naszego programu. Oto program, który generuje liczbę od 0 do 6. Możemy dostosować wartość maksymalną, wysyłając flagę do programu (-max=100):
package main
import ("fmt";"flag";"math/rand")
func main() {
// Define the flags
maxp := flag.Int("max", 6, "max value")
// Parse
flag.Parse()
// Generate a number between 0 and max
fmt.Println(rand.Intn(*maxp))
}
flag.Args() zwraca ciąg znaków [], jeśli istnieją dodatkowe argumenty inne niż flaga
PRYMITYWY SYNCHRONIZACJI
Pakiety sync i sync/atomic w Go umożliwiają bardziej typowe funkcje wielowątkowe.
Mutex
Mutex (wzajemna blokada na wyłączność) służy do ochrony współdzielonych zasobów przed nieatomowymi operacjami poprzez blokowanie bloku kodu do pojedynczego wątku na raz. Poniżej przedstawiono muteks:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
x := new(sync.Mutex)
for c := 0; c < 10; c++ {
go func(i int) {
x.Lock()
fmt.Println(c, "start")
time.Sleep(time.Second)
fmt.Println(c, "end")
x.Unlock()
}(i)
}
var input string
fmt.Scanln(&input)
}
Jeśli muteks (x) jest zablokowany, wszelkie dalsze próby jego zablokowania zakończą się niepowodzeniem, dopóki nie zostanie odblokowany. Należy zachować szczególną ostrożność podczas korzystania z muteksów lub prymitywów synchronizacji oferowanych przez pakiet sync/atomic. Tradycyjne programowanie wielowątkowe stanowi wyzwanie; błędy są proste do popełnienia. Problemy te są trudne do zidentyfikowania, ponieważ mogą zależeć od bardzo specyficznego, stosunkowo rzadkiego i trudnego do powielenia zestawu okoliczności. Jedną z głównych zalet Go jest to, że jego możliwości współbieżności są znacznie łatwiejsze do zrozumienia i zastosowania niż wątki i blokady.
Ocena
Go to język komputerowy stworzony w 2007 roku przez Roba Pike′a, Roberta Griesemera i Kena Thompsona z Google. Jest to język o typie statycznym, którego składnia jest porównywalna z C. Obsługuje wyrzucanie elementów bezużytecznych, bezpieczeństwo typów, pisanie dynamiczne i wiele zaawansowanych typów wbudowanych, w tym tablice o zmiennej długości i mapy klucz-wartość. Posiada również obszerną bibliotekę standardów i umożliwia programowanie współbieżne. Go to język programowania wprowadzony w listopadzie 2009 roku i wykorzystywany w niektórych systemach produkcyjnych Google. Pakiety są używane do projektowania programów w celu efektywnego zarządzania zależnościami. Implementacje programistyczne Go używają typowego modelu kompilacji i łączenia do tworzenia wykonywalnych plików binarnych.
KORZYŚCI I WADY PROGRAMOWANIA W Go
Język programowania Go odnotował gwałtowny wzrost popularności w ostatnich latach. Wydaje się, że każdy startup wykorzystuje go w swoich systemach zaplecza. Deweloperzy są do niego przywiązani z różnych powodów.
Go jest szybkie
Go to błyskawiczny język programowania. Jest kompilowany do kodu maszynowego; automatycznie przewyższy interpretowane lub wirtualne języki wykonawcze. Aplikacje Go również budują się szybko, a ostateczny plik binarny jest niewielki. Nasz interfejs API buduje się w kilka sekund i generuje plik wykonywalny o wielkości 11,5 MB.
Proste do zrozumienia
Gramatyka Go jest krótka w porównaniu z innymi językami, co ułatwia naukę. Większość z nich pamiętamy, więc nie musimy tracić dużo czasu na odkopywanie. Jest również dość czysty i łatwy do odczytania. Programiści spoza Go, szczególnie ci przyzwyczajeni do składni w stylu C, zazwyczaj potrafią czytać program Go i rozumieć, co się dzieje.
Typowanie statyczne
Go to wysoce typowany, statycznie typowany język programowania. Typy pierwotne obejmują int, byte i string. Struktury to inny rodzaj struktur. Jak każdy silnie typowany język, system typów pozwala kompilatorowi przechwycić całe klasy problemów. Go zawiera wbudowane typy list i map, które są proste w użyciu.
Rodzaje interfejsów
Interfejsy istnieją w Go, a każda struktura może spełniać interfejs, po prostu implementując swoje funkcje. Pozwala to oddzielić zależności kodu. Zależności mogą następnie kpić w testach. Możemy opracować bardziej modułowe, testowalne programowanie, wykorzystując interfejsy. Go zawiera również pierwszorzędne funkcje, które pozwalają nam tworzyć kod bardziej funkcjonalnie.
Biblioteka standardowa
Go zawiera przyzwoitą standardową bibliotekę. Ma przydatne wbudowane procedury do radzenia sobie z prymitywnymi rodzajami. Istnieją pakiety, które ułatwiają konfigurację serwera WWW, zarządzanie wejściami/wyjściami, interakcję z szyfrowaniem i manipulowanie nieprzetworzonymi danymi. Serializacja i deserializacja JSON biblioteki standardowej są proste. Możemy podać nazwy pól JSON bezpośrednio obok pól struktury za pomocą "tagów".
Pomoc w testowaniu
Standardowa biblioteka obejmuje obsługę testów. Nie ma potrzeby dodatkowej zależności. Jeśli mamy kod o nazwie example.go, umieść nasze testy w pliku o nazwie thing test.go, a następnie wykonaj "go test", testy te zostaną szybko uruchomione przez Go.
Narzędzia do analizy statycznej
Narzędzia analizy statycznej dla Go są obfite i wydajne. W szczególności Gofmt formatuje nasz kod zgodnie ze stylem zalecanym przez Go. Może to pomóc znormalizować wiele sprzecznych punktów widzenia na projekt i uwolnić czas naszego zespołu, aby mógł skupić się na tym, co robi kod. Uruchamiamy gofmt, golint i sprawdzamy każdą kompilację, a jeśli zostaną wykryte jakiekolwiek ostrzeżenia, kompilacja kończy się niepowodzeniem.
Zbieranie śmieci
Zarządzanie pamięcią Go zostało zaprojektowane tak, aby było prostsze niż zarządzanie pamięcią w C i C++. Obiekty, które są przydzielane dynamicznie, są wyrzucane do kosza. Go sprawia, że używanie wskaźników jest znacznie bezpieczniejsze, ponieważ nie umożliwia arytmetyki wskaźników. Zapewnia również możliwość używania typów wartości.
Łatwiejszy model współbieżności
Podczas gdy programowanie współbieżne nigdy nie jest łatwe, Go czyni je łatwiejszym niż inne języki programowania. Ustanowienie lekkiego wątku znanego jako "goroutine" i komunikowanie się z nim za pośrednictwem "kanału" jest niezwykle proste. Możliwe jest również tworzenie bardziej skomplikowanych wzorów.
JAKA JEST JEGO NAZWA? Czy to Go CZY GoLang?
Możemy usłyszeć język określany zarówno jako Go, jak i GoLang, co może być mylące. To powiedziawszy, GoLang to po prostu inna nazwa Go, zachowująca oficjalną nazwę. Słowo GoLang pochodzi od nazwy domeny oficjalnej strony Go, golang.org. Co jest bardzo przydatne, ponieważ "GoLang" jest znacznie łatwiej wyszukiwać w Google niż "Go". W rezultacie ułatwia życie osobom poszukującym wiedzy na temat języka programowania.
DLACZEGO WARTO STUDIOWAĆ Go
Prosta krzywa uczenia się
Go jest jednym z najbardziej podstawowych dostępnych języków programowania. Łatwo się go nauczyć, zwłaszcza jeśli znamy już inny język programowania. Wielu programistów Go, którzy są pewni swoich talentów dydaktycznych, twierdzi, że mogą nauczyć kompletnego nowicjusza, jak zbudować aplikację w zaledwie kilka godzin. Według ankiety StackOverflow Developer Survey 2020, jednym z głównych powodów, dla których Go awansował z 10. na 5. miejsce wśród najpopularniejszych języków programowania, jest jego prostota.
Dobra dokumentacja i aktywna społeczność
Go oferuje obszerną i łatwą do zrozumienia dokumentację. Dokumentacja jest dostępna na oficjalnej stronie internetowej. Oprócz dokumentacji, Go ma za sobą silną i aktywną społeczność, więc zawsze możemy uzyskać pomoc, jeśli utkniemy. Ponieważ hashtag #golang jest powszechnie używany na Twitterze, możemy tweetować nasze zapytanie z dołączonym hashtagiem, jeśli utkniemy. Dzięki Go możemy wiele zrobić Go to wszechstronny język programowania, którego można używać do różnych zadań, takich jak tworzenie stron internetowych, analiza danych, przetwarzanie w chmurze i nie tylko. Jeśli chcemy pracować w chmurze obliczeniowej, powinniśmy nauczyć się Go, ponieważ obsługują go systemy takie jak Amazon Web Services, Kubernetes i Google Cloud Platform (GCP).
Płace są atrakcyjne
Z medianą wynagrodzenia wynoszącą 74 000 USD, pracownicy Go są trzecimi najlepiej opłacanymi pracownikami za Perlem i Scalą, zgodnie z ankietą dla programistów StackOverflow 2020. Kwota ta prawdopodobnie wzrośnie jeszcze bardziej, ponieważ popularność Go rośnie z roku na rok i jest na nie duży popyt. Jeśli więc chcemy zarabiać więcej, powinniśmy nauczyć się Go.