Язык программирования Go был запущен в 2007 году инженерами Google Робертом Гриземером, Робом Пайком и Кеном Томпсоном. Первый стабильный релиз был выпущен с открытым исходным кодом в марте 2012 года.

Вы можете получить доступ ко всем исходным кодам на Github и даже внести свой вклад в разработку.

Новый бренд Go: https://blog.golang.org/go-brand

Основные особенности Go:

  • Открытый источник
  • Статически написано
  • Высокая производительность
  • Быстрая компиляция (проект из миллиардов строк может быть скомпилирован за секунды)
  • Поддержка сборщика мусора
  • Внутренний менеджер пакетов
  • Параллелизм (на языковом уровне)
  • Подробная документация, где все задокументировано
  • и больше" …

Файл Go - это в основном;

  • функции (методы)
  • переменные
  • разновидность
  • Комментарии
  • состоит из постоянных переменных.

Предисловие

Этот пост был создан, чтобы разогреть вас перед Go и помочь вам быстро приступить к работе. Обязательно прочтите документацию на« golang.org , чтобы понять Go после разминки.

Вместо того, чтобы копировать примеры, чтобы сделать обучение эффективным, попробуйте писать, чтобы выработать привычку. Измените коды, понаблюдайте за выводом и попытайтесь понять изменение.

Обязательно просмотрите ссылки, указанные в (или в конце) главы. Эти ресурсы помогут вам найти дополнительную информацию и примеры по теме.

Вы можете запустить образцы кода на Площадке.

Сначала откажитесь от своих привычек!

Вместо того, чтобы запоминать, научитесь делать работу на ходу, поймите философию языка.

Настраивать

Чтобы скомпилировать коды в среде, в которой вы будете работать, вам сначала необходимо установить компилятор Go. Загрузите и установите компилятор для своей операционной системы со страницы Загрузки.

При желании вы можете следовать инструкциям на странице Настройка.

После завершения установки введите следующую команду в терминале (CL: командная строка), чтобы проверить ее:

go version

Эта команда распечатает установленную версию Go на экране.

go helpЭту команду можно использовать для просмотра всех команд, поддерживаемых инструментом Go.

ЗДЕСЬ

Вы можете писать коды Go в любой IDE (интегрированной среде разработки). Вы можете выбрать любой из предложенных ниже вариантов.

Вы можете свободно установить некоторые плагины для IDE в соответствии с вашими предпочтениями.

Рабочий каталог

После установки компилятора установщик Go создает несколько каталогов в соответствии со своими потребностями. Эти каталоги важны для разработки, компиляции и выполнения программ. Давайте познакомимся с двумя важными каталогами, которые мы должны знать в первую очередь:

$GOROOT: Каталог, в котором установлен Go

$GOPATH: каталог разработанных проектов

$GOROOT Нет необходимости изменять его, так как он определяется автоматически во время установки.

$GOPATHВы можете следовать инструкциям (в соответствии с операционной системой) на странице вики или установочном документе, чтобы определить / изменить каталог $GOPATHВы можете использовать каталог по умолчанию, не внося изменений изначально. Можно определить более одной $GOPPATHvariable. $GOPATH Обратите внимание, что все, что нужно для разработки приложения, должно находиться в каталоге (рабочем каталоге).

$GOPATH Он ~/go определен по умолчанию для систем MAC.

go envВы можете перечислить все переменные среды, набрав команду на терминале.

Программа First Go

Изучая язык программирования, как бы вы хотели начать с уже ставшего традицией примера «привет, мир»?

Создайте новый проект Go в рабочем каталоге. main.goСоздайте файл в каталоге проекта. Внутри этого файла напишите следующие коды и сохраните:

package main
 
import "fmt"
 
func main() {
    fmt.Println("merhaba dünya")
}

Программы Go состоят из пакетов. Следовательно, у каждого файла Go должно быть имя пакета. Вверху файла после слова пишется packagepackage. Для исполняемых (небиблиотечных) программ mainpackage является отправной точкой.

Мы можем называть повторно используемые пакеты, созданные для общей цели, библиотекой. Например; Вы можете создать пакет, который вычисляет среднее значение предоставленных ему чисел, и загрузить этот пакет в Github или аналогичные источники. Используя этот пакет в каждом нужном вам проекте, вы избегаете повторения одних и тех же кодов снова и снова.

Если он не содержит бизнес-правила, вы можете публиковать свои пакеты как с открытым исходным кодом и сделать их доступными для всех.

В следующей строке с importword был импортирован fmtpackage. fmtВ этой программе теперь можно использовать все переменные, функции и методы, которые экспортируются из импортированного пакета.

Если имена переменных, функций или методов начинаются с заглавной буквы, эти операторы общедоступны для других пакетов. Например; Ortalama ,, OrtalamaHesapla

Однако, если имена выражений начинаются со строчной буквы, они не могут быть доступны другим пакетам (защищенным). К нему могут получить доступ только другие файлы в том же пакете. Например; ortalama ,, ortalamaHesapla

В Go это основная mainфункция входа. Эта функция не принимает параметров и не возвращает никакого значения. Наконец, мы выводим на экран желаемое сообщение с функцией (методом) из fmtpackage в теле функции Println.

Функции и методы похожи друг на друга, но отличаются друг от друга стилем выражения и использованием. Мы рассмотрим оба аспекта по отдельности в следующих разделах.

Посмотрим на результат, запустив эту программу. Есть разные способы запуска программ Go. Во-первых; Мы будем использовать 2 разные команды для компиляции написанного кода и выполнения скомпилированной программы. Чтобы скомпилировать программу, откройте терминал и перейдите в каталог, где находится проект. Находясь в рабочем каталоге, введите следующую команду:

go build ./main.go

Эта команда создает исполняемый двоичный файл. Запустите скомпилированный двоичный файл, чтобы запустить программу:

./main

Вместо того, чтобы компилировать программу и каждый раз запускать скомпилированный файл в среде разработки (локальной), вы можете предпочесть более простой способ. Вместо вышеуказанных операций мы run можем использовать команду, абстрагирующую этап компиляции. Команда ниже; абстрактно скомпилирует программу и запустит скомпилированную программу:

go run ./main.go

Потому что Go - это язык компиляции; Когда в коды Go вносятся какие-либо изменения, программа должна быть остановлена ​​и снова запущена (скомпилирована), чтобы изменение отразилось в работающей (выполняющейся) программе. Это не исключительный случай для Go, это требование для всех компилируемых языков.

fmt Для получения дополнительных сведений о пакете, в котором выполняются операции ввода-вывода и форматирования, обязательно ознакомьтесь с документацией по пакету.

Комментарии

Иногда вам может понадобиться добавить комментарии или комментарии где-нибудь в программе, чтобы запомнить их позже, или написать простые примеры, чтобы проиллюстрировать использование функции / метода.

Комментарии поддерживаются Go, а также на других языках. Во время компиляции все строки комментариев игнорируются. Вы можете писать все, что хотите, между строками комментариев.

// Строка, начинающаяся с символов, считается строкой комментария:

// you can write the description you want here

/**/ Все, что находится между символами и, считается блочным (многострочным) комментарием:

/ * 
here 
you 
can enter the description you want 
* /

Как правило, блочные комментарии предпочтительнее выражать что-либо подробно. Для нескольких строк комментария вместо комментария блока вы можете повторить комментарий строки:

// here 
// you 
can // write the description you want

Используя комментарии, вы можете подготовить руководство пользователя (документацию) для своих кодов. Например, вы можете задокументировать пакет, который вы разработали, чтобы упростить его использование другим разработчикам.

Для создания документации необходимо придерживаться нескольких правил:

  • Обязательно прочтите инструкцию Effective Go для правильного использования.
  • Что нужно знать для создания документации, объясняется в сообщении блога Documenting Go Code, я рекомендую вам ознакомиться.
  • Чтобы познакомиться с командным инструментом, преобразующим комментарии в документы документации, вы можете ознакомиться с документацией к пакету godoc.

Пакетная документация в Go создается с комментариями прямо над кодами. Эта функция обеспечивает невероятное удобство для тех, кто хочет писать (документировать) документы в своем коде.

Документация очень важна в мире программного обеспечения. Для получения лучших выражений обязательно ознакомьтесь с комментариями к коду для пакетов Go на Github.

Переменные

Поскольку Go написан статически, он хочет знать или предсказывать типы переменных во время компиляции. Следовательно, при определении переменной должен быть указан ее тип или она должна быть запущена с явным значением, чтобы Go мог предсказать.

Как следует из названия, переменные можно изменить в любое время. Единственное правило - новое значение должно быть того типа, который принимает переменная.

Оператор var используется для определения переменных в Go. Имя и тип переменной указываются сразу после.

var name  string
var email string
var age   int

Вы можете определять переменные путем группировки, а не определять их по отдельности. Go оставляет выбор за вами, вы свободны.

var (
    name  string
    email string
    age   int
)

Вы можете сразу объявлять переменные одного типа. Во время компиляции Go конвертирует его в понятный формат.

var name, email string
var age int

or;

var (
    name, email string
    age         int
)

При определении переменной ее можно инициализировать первым значением. Поскольку это не постоянное значение, инициализированное значение может быть позже заменено другим значением того же типа.

var (
    name  string = "John Doe"
    email string = "[email protected]"
    age   int    = 34
)// variables, with any data of the same type 
// can be updated anytime 
age = 27// whatever happens, a variable 
will never accept data of a different type // 
// age = "twelve"

Если переменная имеет значение инициализатора, объявление типа может быть опущено при определении переменной. Go может объявить тип переменной путем предполагаемого ввода во время компиляции.

var (
    name  = "John Doe"
    email = "[email protected]"
    age   = 34
)

or;

var name, email, age = "John Doe", "[email protected]", 34

Если переменная имеет начальное значение :=, varkeyword можно опустить с помощью оператора присваивания. Эта форма объявления может использоваться только в телах функций, :=operator не допускается глобально.

import "main"// Short / fast variable declaration cannot be used in this field, 
// variable can only be declared with the "var" statement.int main () { 
    // Both "var" statement and 
    // short declaration can be used in function bodies . 
    name, email, age: = "John Doe", "[email protected]", 34    // ...
}

Go декодирует короткое объявление во время компиляции и преобразует его в понятный формат.

Если переменная была ранее определена в Go, объявление varsecond (даже если оно того же типа) с оператором в той же области не допускается. Однако при объявлении нескольких переменных с помощью оператора объявления ярлыка, если объявляется новая переменная, Go может допускать ранее определенную переменную. Давайте рассмотрим следующие примеры.

Пример ниже неверен. Компилятор требует исправления этой строки, поскольку обе переменные переопределяются:

name, age := "John Doe", 34
name, age := "Jane Doe", 30

В приведенном ниже примере компилятор допускает это, потому что определенная переменная затем используется с другим объявлением новой переменной. Go принимает второе объявление определенной переменной как обновление значения, а не как определение переменной.

name, email := "John Doe", "[email protected]"
name, age := "Jane Doe", 30

Go анализирует указанный выше блок кода во время компиляции, конвертируя его в свой собственный формат. Его преобразованная версия будет:

var name string = "John Doe"
var email string = "[email protected]"
name = "Jane Doe"
var age int = 30

Вы поймете преимущества этой формы отчетности, когда изучите тему «управления ошибками» в следующих разделах.

Сфера

В языке Go переменные создаются в той области видимости, в которой они находятся, и уничтожаются в конце области видимости.

Короче говоря, мы можем определить область действия как тело, заключенное в фигурные скобки. Каждая новая скобка создает новую область действия.

  • Новая переменная с тем же именем может быть создана с разными областями действия или даже с тем же именем, но с другим типом.
  • Когда переменная выходит за рамки, она не определена.
  • Подобласти могут обращаться к переменным, которые выше, чем они сами. Однако обратное невозможно.

Давайте продолжим разбираться.

package main
 
import "fmt"
 
func main() {
    msg := "x"
 
    {
        fmt.Println("1:", msg)
 
        msg := "y"
 
        fmt.Println("2:", msg)
    }
 
    fmt.Println("3:", msg)
}

Как вы думаете, что делает эта программа? Когда программа будет запущена, на экране будет напечатан следующий вывод:

1: x
2: y
3: x

Выше мы фактически определили две независимые переменные. Их расположение и значения в памяти разные. Давайте объясним, почему результаты такие:

1: xsub-scopes могут обращаться к переменным с более высокой областью видимости, чем они сами. Следовательно, это значение, для которого была создана подобласть, использовало значение переменной верхнего уровня.

2: ysub-scopes могут регенерировать или обновлять переменные, которые выше, чем они сами. Go позволил определить новую переменную с тем же именем при изменении области видимости. Мы даже можем изменить тип переменной. Попробуйте msg := “y" вместо этого, если хотите msg := 5.

3: x: суперобласти не могут получить доступ к переменным, созданным во вспомогательных областях. Он по-прежнему имеет ценность в пределах своей компетенции.

Если мы немного изменим код, у нас может быть возможность изучить, как суб-области влияют на значения на верхнем уровне, чем они сами:

package mainimport "fmt"func main() {
    msg:= "x"
 
    {
        fmt.Println("1:", msg)        msg = "y"
        fmt.Println("2:", msg)
    }
 
    fmt.Println("3:", msg)
}

Единственное изменение, которое мы внесли в этот пример, - это то, что мы изменили msg := "y"value в под-области видимости на значение msg = "y"update вместо создания переменной. Как вы думаете, каков будет результат?

1: x 
2: y 
3: y

Как вы можете видеть из результатов, у нас есть право обновлять, поскольку мы получили доступ к верхней переменной области во вложенной области. Поскольку мы не определяли новую переменную, мы смогли обновить существующую переменную.

Помните правило! Переменные можно обновлять только значениями одного и того же типа. В этом примере msg = "y" вместо msg = 5 не разрешено изменять. Это было бы неточно, поскольку мы не можем назначать значения одного и того же типа.

Сфера; Это также справедливо для тел global, function, function, if-else и loop.

for i: = 1; i <5; i ++ { 
    fmt.Println (i) 
} 
 
// The variable 
"i" cannot be accessed in this field because the "i" variable is defined in the scope of "for"

Чтобы расширить переменную до большего охвата вместо области цикла:

// We are 
defining the variable "i" higher than the scope // for " 
var i int 
 
for i = 1; i <5; i ++ { 
    fmt.Println (i) 
} 
 
// variable "i" can now be accessed here 
// even its value has changed under "for" 
fmt.Println ("last value:", i)

Обязательно попробуйте этот пример.

Типы данных

Go хочет знать тип и ценность всего. Go может определить его тип, изучив значение, присвоенное переменной. Или он может присвоить значение по умолчанию (значение по умолчанию зависит от типа переменной) переменной, которая указана, но не имеет значения.

Для получения дополнительной информации о типах данных обязательно ознакомьтесь с документацией Спецификация типов. Все объяснено до мельчайших деталей.

Go поддерживает множество типов переменных. Некоторые типы данных даже имеют разную емкость. Давайте быстро взглянем на типы данных:

Числа

Есть несколько различных типов го, которые представляют собой числа. Обычно мы принимаем числа двух разных типов: целые числа и числа с плавающей запятой.

Целые числа (целые числа)

В зависимости от количества битов целочисленного типа данных объем памяти и емкость переменной могут различаться. Go поддерживает следующие целочисленные типы данных:

int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr

var i uint8
fmt.Printf("%d\n", i)
 
i = 34
fmt.Printf("%d\n", i)

В этом примере определяется 8-битная unsignedчисловая переменная. Числовое выражение в информатике signed и unsigned может быть. Если это переменная unsignedtype, она может состоять только из положительных (включая ноль) чисел.

Если переменной целочисленного типа не присвоено никакого значения, ее значение по умолчанию 0value (ноль) присваивается во время компиляции.

Существует два типа псевдонимов для числового типа данных; uint8с byte, int32 это rune то же самое, что и.

Разработчики Go очень заботятся об использовании памяти и производительности. Следовательно, используется соответствующий тип данных. Определение значения int8data type int64 не рекомендуется, если оно соответствует вашим потребностям.

Обычно в программах Go используется тип intdata.

Числа с плавающей запятой

Это тип переменной, которая содержит десятичные числа. Он может иметь float32 либо float64тип, либо в зависимости от точности числа. Для обоих типов по умолчанию присваивается 0value (ноль).

var f float32
fmt.Printf("%f\n", f)
 
f = 3.12
fmt.Printf("%f\n", f)

Нить

Это тип переменной, в которой вы можете хранить строковые значения. Он "" имеет значение (пустая строка), когда значение не установлено.

var s string
fmt.Printf("%#v\n", s)
 
s = "go"
fmt.Printf("%#v\n", s)

Логический

Он содержит только trueили его falsevalue. Переменная, которой false не присвоено значение, имеет значение по умолчанию.

var b bool
fmt.Printf("%t\n", b)
 
b = true
fmt.Printf("%t\n", b)

Преобразование типов

Go очень чувствителен к типу переменных. Например; Если математическая операция должна выполняться с двумя числовыми выражениями, предполагается, что типы переменных будут одинаковыми.

Это T(v) можно резюмировать формулой преобразования типа So; преобразует свое vvalue в свой Ttype.

package main
 
import "fmt"
 
func main() {
    var i int = 42
    var f float64 = float64(i)
    fmt.Printf("%T(%v)\n", i, i)
    fmt.Printf("%T(%v)\n", f, f)
}

В этом примере; Можно сказать, что данные преобразуются по типу до того, как переменная с типом копируется в int i переменную типа .float64f

Для получения дополнительной информации о преобразовании типов и других типах функций преобразования обязательно ознакомьтесь с конвенциями.

Постоянные переменные

Иногда нам нужны выражения, которые определены в программе один раз и значение которых мы не хотим изменять позже.

Например, если вы хотите обновить программу, номер текущей версии будет постоянным. Когда мы добавляем новую функцию в программу, мы увеличиваем это значение на единицу и оставляем его постоянным. Почему это должно измениться где-нибудь в приложении?

Константы похожи на переменные, но с некоторыми отличиями. Что нужно знать о константах:

  • varconstиспользуется вместо этого.
  • string, booleanИли numeric ему может быть присвоено значение типа.
  • ярлык :=operator не поддерживается.
  • Неопределенные данные не могут быть присвоены как значения.
  • Возвращает тип контекста, если тип не объявлен.
  • его ценность никогда не может быть изменена.
  • Компилятор не работает для констант, которые определены, но не используются.
package main 
 
import "fmt" 
 
const ( 
    Locale string = "     tr_TR " 
    PI = 3.14 
PILong = float64 (22) / float64 (7) 
    // 
    // cannot be assigned to a constant variable for // because the following expression produces a constantly changing value 
    // Now = time. Now () 
) 
 
func main () ( 
    fmt.Printf ("% T (% v) \ n", Locale, Locale) 
    fmt.Printf ("% T (% v) \ n", PI, PI) 
    fmt.Printf ("% T (% v) \ n", PILong, PILong) 
)

Операторы

В языке программирования Go существует ряд операторов, используемых для разных целей. Кратко рассмотрим наиболее востребованные операторы:

Арифметические операторы

Эти операторы позволяют нам выполнять математические операции с числовыми данными.

Https://golang.org/ref/spec#Arithmetic_operators

Операторы присваивания

Операторы, используемые для присвоения значения переменной.

Https://golang.org/ref/spec#Assignments

Операторы сравнения

bool Возвращает (логический) результат путем сравнения двух данных друг с другом. Если сравнение истинно, true, false возвращает свое значение, если оно ложно.

Https://golang.org/ref/spec#Comparison_operators

Логические операторы

Он проверяет несколько логических данных, объединяя их в цепочку. Вывод может отличаться в зависимости от используемого оператора.

Https://golang.org/ref/spec#Logical_operators

Операторы адреса / указателя

Это операторы, используемые для получения адреса переменной в памяти или для изучения значения в адресе памяти. Остальная часть статьи будет подробно рассмотрена в разделе указателей.

Https://golang.org/ref/spec#Address_operators

Go включает намного больше операторов. Для начала достаточно знать операторов из этого списка. Однако вы можете проверить страницу операторов, чтобы узнать больше.

Массивы

Это комбинированный тип данных, в котором хранятся данные определенной длины (емкости). При создании массива емкость массива указывается заранее.

[n]T - это массив, содержащий значение единицы Ttype n.

var a [5] int

Вышеупомянутый оператор int определяет массив, содержащий 5 типов данных. Массивы имеют нулевой начальный индекс. Массив с 2 элементами будет иметь индексы 0 и 1. В пределах их емкости любому индексу массива может быть присвоено значение или значение его индекса может быть обновлено.

Например;

package main 
 
import "fmt" 
 
func main () { 
    var m [2] int 
 
    m [0] = 25 
 
    // indices with insufficient array capacity 
    // cannot be assigned data 
    // m [2] = 5 
 
    fmt.Printf ("% # v ", m) 
}

В приведенном выше примере мы определили массив из 2 элементов. Мы присваиваем первому элементу массива (индекс 0) значение. Однако мы не смогли присвоить значение его второму элементу (номер индекса 1). Элементы массива, которым не присвоено значение, заполняются значением по умолчанию, соответствующим типу данных.

При желании вы можете заранее указать значения, которые будут иметь элементы массива при определении массива. Чтобы определить начальные значения массива, вы можете указать значения инициализации в фигурных скобках сразу после выражения массива.

В приведенном ниже примере инициализируются некоторые элементы массива. Обратите внимание, что неинициализированные значения заполняются значениями по умолчанию.

package main
 
import "fmt"
 
func main() {
    m := [3]int{25, 5}
   
    fmt.Printf("%#v", m)
}

Для доступа к элементам массива достаточно указать в квадратных скобках индекс элемента, к которому будет осуществляться доступ:

package main 
 
import "fmt" 
 
func main () { 
    m: = [2] string {"foo", "bar"} 
 
    fmt.Println (m [0]) 
 
    // 
    // the following statement is an error because the array does not have an index # 2 throws 
    // fmt.Println (m [2]) 
}

Предположим, у вас есть диапазон данных и вы хотите назначить его новому массиву без указания емкости. Затем Go может оценить вместимость для вас. В этом случае ...вы можете использовать оператор (многоточие) вместо ввода длины.

package main
 
import "fmt"
 
func main() {
    m := [...]string{"foo", "bar"}
 
    fmt.Printf("%#v", m)
}

Мы всегда работали с одномерными массивами, но иногда нам нужны многомерные матрицы. Go поддерживает многомерные массивы. Давайте рассмотрим пример ниже:

package main
 
import "fmt"
 
func main() {
    var a [2][3]string
 
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            a[i][j] = fmt.Sprintf("%d-%d", i+1, j+1)
        }
    }
 
    fmt.Println(a)
}

Вы можете инициализировать приведенный выше пример многомерным массивом, который у вас уже есть, например одномерными массивами:

package main
 
import "fmt"
 
func main() {
    a := [3][2]int{
        {0, 1},
        {2, 3},
        {4, 5},
    }    fmt.Printf("%#v", a)
}

Мы используем квадратные скобки для определения элемента в многомерных массивах, как в одномерных массивах. Например; Чтобы перейти к первому элементу строки 2:

a[2][0]

Достаточно использовать выражение.

Для получения дополнительной информации о серии вы можете ознакомиться с примерами приложений или документацией Go.

Ломтики

Срезы обертывают массивы, чтобы сделать их более полезными для массивов. Подобно массивам, но емкость срезов может быть неопределенной.

[]Tявляется T срезом своего типа.

package main
 
import "fmt"
 
func main() {
    n := []int{1, 2, 3, 4}
 
    fmt.Printf("%#v", n)
}

Новую переменную среза можно создать, разрезая массивы в Go. Чтобы создать новый срез, указав границы массива:

msg[low:high]

выражение используется. Это выражение выбирает полуоткрытый срез, который содержит первый элемент (низкий), но исключает последний элемент (высокий). Выражение немного сложное, давайте рассмотрим пример, чтобы его можно было понять.

package main
 
import "fmt"
 
func main() {
    chars := [6]string{"a", "b", "c", "d", "e", "f"} 
 
    var slice []string = chars[1:4]
 
    fmt.Printf("%#v", slice)
}

В этом примере будут выбраны значения, которые попадают между индексами 1–4 массива (включая индекс №1, а не индекс №4). Обратите внимание, что начальный индекс массивов равен 0 (нулю).

Создание срезов из массивов по ссылке

Этот визуальный элемент представляет собой визуализацию предыдущей операции, которую мы проделали. Массивы копируются по ссылке при разделении на фрагменты. То есть в качестве значения передается ссылка, а не значение массива.

Чтобы продолжить, запустите приведенный ниже код и посмотрите на результат.

package main
 
import "fmt"
 
func main() {
    chars := [6]string{"a", "b", "c", "d", "e", "f"} 
 
    var slice []string = chars[1:4]
 
    chars[2] = "x"
 
    fmt.Printf("%#v", slice)
}

Мы makeиспользуем слово, чтобы создать новый пустой фрагмент. Go make ожидает длину слова.

package main
 
import "fmt"
 
func main() {
    s := make([]int, 2)
 
    fmt.Printf("%#v:", s)
}

В этом примере мы создали новый фрагмент с длиной (len) 2. Поскольку мы еще не присвоили значение моему фрагменту, Go заполнил его начальным значением.

package main
 
import "fmt"
 
func main() {
    s := make([]int, 2)
 
    s[0] = 10
    s[1] = 20
 
    fmt.Printf("%#v:", s)
}

Как и в случае с массивами, вы можете обращаться к срезам через их индексы или присваивать значения.

Мы упоминали, что срезы обеспечивают удобство с точки зрения ограничения длины. Так что же делать, если изначально определенной длины недостаточно?

s[2] = 30

Добавляя приведенное выше утверждение к нашему примеру, Go рассердится на нас за превышение длины среза. Так что мы можем сделать?

s = append(s, 30)

Мы append можем использовать это слово для увеличения длины среза, добавления новых элементов в конец среза. Go расширит срез для нас и добавит новый элемент в конец среза.

s = append(s, 30, 40, 50)

При желании вы можете добавить в срез большое количество данных в одной строке.

Обратите внимание, что начальные значения заполняются при создании пустого среза. Кроме того, он append просто добавляет новые значения в конец среза. Таким образом, он не обновляет значение ни в одном индексе.

Вот пример:

package main
 
import "fmt"
 
func main() {
    s := make([]int, 2)
 
    s = append(s, 10)
 
    fmt.Printf("%#v:", s)
}

Вы len можете использовать это слово, чтобы узнать длину отрезка.

l: = len (s)

Чтобы узнать больше, вы можете присоединиться к Экскурсии или прочитать замечательную статью с объяснением срезов, в которой резюмируется эта тема.

Карты

скоро будет обновлено

Условные выражения

Программы ведут себя по-разному в зависимости от того, верна ситуация или нет. Мы используем условные операторы (управляющие структуры) для запроса текущих условий и направления выполнения программы.

Простая структура управления, которая проверяет, равно ли значение переменной «а» 5.

Если еще

Это позволяет нам контролировать ситуацию с условием (-ями) «что, если».

Например, мы хотим управлять значением переменной числового типа в соответствии с ее нечетным или четным состоянием. Если число будет двойным, мы напечатаем сообщение на экране.

package main
 
import "fmt"
 
func main() {
    i := 4
 
    if i%2 == 0 {
        fmt.Println("çift")
    }
}
 
// output: çift

В примере проверка переменной mod оператором i. Если оставшийся результат раздела равен нулю (0), будет создано true его значение и if условие в его блоке будет выполнено. if кусок кода в теле блока будет выполнен, потому что он соответствует условию. Если бы число было нечетным, на экране не было бы ничего напечатано, потому что условие не было выполнено. Попробуйте изменить значение.

Как ни крути, но в языке Go if и в дальнейшем для тела условия следует использовать необычные скобки.

Что, если бы нам в обоих случаях приходилось что-то печатать на экране?

package main
 
import "fmt"
 
func main() {
    i := 3
 
    if i%2 == 0 {
        fmt.Println("çift")
    } else {
        fmt.Println("tek")
    }
}
 
// output: tek

В этом примере условие false не будет ifsatisfied, потому что условие даст результат. Он выполняет тело программы if, потому что не удовлетворяет его условию else. Если бы ifcondition было выполнено, elsetrunk не работал бы в это время.

Иногда мы можем захотеть протестировать программу с большим количеством условий. Таким образом, нам могут потребоваться другие элементы управления, помимо if и else. Итак, давайте else ifmeet.

package main 
 
import "fmt" 
 
func main () { 
    i: = 7 
 
    if i <5 { 
        fmt.Println ("the number is less than five") 
    } else if i == 6 { 
        fmt.Println ("the number equals six") 
    } else if i == 7 { 
        fmt.Println ("number equals seven") 
    } else { 
        fmt.Println ("number meets no requirement") 
    } 
} 
 
// output: number equals seven

Поскольку ifcondition не выполняется в примере, оно проверяется с помощью следующего условия. Если это условие также не истинно, следующее, следующее ... Если оно не удовлетворяет никакому условию, его elsebody сработает. Все выполняется последовательно. Однако в нашем примере есть блок, в котором выполняется условие: i==7state.

Условные операторы могут содержать один if и elseblock, в то время как они else if могут иметь несколько блоков. Если честно, он состоит из всего if и его else блоков. Фактически, он else if существует только для визуального удобства.

if i == 5 {
    ...
} else if i == 7 {
    ...
} else {
    ...
}

равно:

if i == 5 {
    ...
} else {
    if i == 7 {
        ...
    } else {
        ...
    }
}

Старайтесь не писать вложенные блоки кода, так как это снижает удобочитаемость. Просто знайте, что это работает так, вы else if можете спокойно пользоваться блоком управления.

Для получения дополнительной информации ознакомьтесь с документацией управляющие структуры.

Выключатель

if/elseIts switchblock, который является мощной альтернативой блоку управления, предлагает более мощный интерфейс наряду с аналогичными элементами управления. Опять же, условия проверяются последовательно сверху вниз. Когда условие (утверждение, условие) выполняется успешно, выполняется тело условия.

package main
 
import "fmt"
 
func main() {
    num := 2
 
    switch num {
    case 1:
        fmt.Println("num: 1")
    case 2:
        fmt.Println("num: 2")
    }
}

В приведенном выше примере выражение switch содержит значение, которое должно быть условно применено. Затем casestatements проверяются последовательно с условиями. Выполняется тело статуса выигрыша.

Вы думаете о elseit, верно? Не волнуйтесь, есть defaultblock, который вы можете запустить, если не выполняются никакие условия. Он else работает так же.

package main
 
import "fmt"
 
func main() {
    num := 200
 
    switch num {
    case 1:
        fmt.Println("num: 1")
    case 2:
        fmt.Println("num: 2")
    default:
        fmt.Println("num: diğer")
    }
}

Если switchситуация default в операторах и если ни одно из условий не соблюдается, несмотря на все поставленные под сомнение условия, defaultcontrol завершается запуском тела. Если выполняется хотя бы одно условие, defaulttrunk не будет работать.

package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    switch hour := time.Now().Hour(); {
    case hour < 12:
        fmt.Println("günaydın")
    case hour < 17:
        fmt.Println("tünaydın")
    default:
        fmt.Println("iyi akşamlar")
    }
}

В этом примере определена переменная, относящаяся к switchscope. Вы можете получить доступ к определенной переменной в области видимости и создать расширенные элементы управления.

package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    switch time.Now().Hour() {
    case 6, 7, 8, 9, 10, 11:
        fmt.Println("günaydın")
    case 12, 13, 14, 15, 16:
        fmt.Println("tünaydın")
    default:
        fmt.Println("iyi akşamlar")
    }
}

Давайте продолжим с другим вариантом использования. Вы можете указать условия в списке контрольных случаев. Если условие равенства выполняется для любого значения в списке условий, выполняется тело условия.

Дополнительную информацию можно найти в документации по переключателям или в примерах.

Петли

Цикл используется для многократного выполнения блока кода. Go может выполнять все типы циклов с помощью одного forключевого слова.

Для петли

Это тип цикла с определенным началом, концом и нарастанием / уменьшением. Циклу заранее известны условия, в которых он будет работать.

package main
 
import "fmt"
 
func main() {
    sum := 0    for i := 1; i < 10; i++ {
        sum += i
    }    fmt.Println(sum)    // variable "i" is 
    not defined for this field because it is not covered by the loop 
}

Приведенная выше программа выводит на экран сумму чисел в определенном диапазоне. Цикл работает в следующих ситуациях:

  1. i := 1 Инициализация со статусом (инициализация)
  2. i < 10condition (условие) вычисляется. Если условие выполнено, выполняется тело цикла, в противном случае цикл завершается.
  3. i++ состояние запущено (сообщение)
  4. Вернуться к шагу 2

Пока цикл

Цикл можно получить, for слегка изменив whileцикл, указанный в предыдущем разделе.

package main
 
import "fmt"
 
func main() {
    sum, i := 0, 1    for i < 10 {
        sum += i
        i++
    }    fmt.Println(sum)
}

Фактически, whileцикл состоит только из условия. Он работает снова и снова, пока выполняется условие. Цикл работает в следующих ситуациях:

  1. i < 10condition (условие) вычисляется. Если условие выполнено, выполняется тело цикла, в противном случае цикл завершается.
  2. Вернуться к шагу 1

Для каждого Döngüsü

Повторяется (повторяется) string, array, slice, mapили channeldata принадлежащие типам данных переменных для обработки идеального цикла. Например;

package main
 
import "fmt"
 
func main () {
    list := []string{"cat", "dog", "rabbit"}    for key, value := range list {
        fmt.Println(key, value)
    }
}

Цикл просматривает каждый элемент в списке от начала до конца. После обработки последнего элемента он уничтожается. Список range вводится в цикл с его ключом. Цикл работает с каждым элементом keyи valuemap.

Если key вам не нужно его значение, вы null identifier можете игнорировать его, используя (пустой идентификатор). Символ _ (подчеркивание) используется для пустого идентификатора.

for _, value := range list {
    fmt.Println(value)
}

keyЕсли вам просто нужно value его значение, просто отбросьте это значение.

for key := range list {
    fmt.Println(key)
}

Бесконечный цикл

Иногда может потребоваться выполнение цикла в течение всего времени работы программы. Это цикл, который не работает ни при каких обстоятельствах.

package main
 
import "fmt"
 
func main() {
    for {
        fmt.Println(".")
    }
}

Пока эта программа работает, она будет печатать точку на экране.

Разрыв / Продолжить

break и continuekeywords, которые есть почти во всех языках программирования, поддерживаются Go.

break: разорвать петлю

continue: пропускает текущий цикл и продолжает цикл.

package main
 
import "fmt"
 
func main() {
    sum := 0    for i: = 1; ; i ++ { 
        // skip 
        if the value i divides into 2 and 3 exactly if i% 2 == 0 && i% 3 == 0 { 
            continue 
        } 
    
        //             break the loop 
        if sum is greater than 15 if sum> 15 { 
break 
        }        sum += i
    }    fmt.Println(sum)
}

Функции

Функция (функция) в информатике аналогична функциям в математике. Его определенная f(x)функция может использоваться повторно, когда это необходимо.

Прототип функции

Представьте себе черный ящик на изображении выше как функцию. Функции; Он принимает ноль или более входных параметров и генерирует ноль или более выходных параметров.

Функции в языке Go func определяются ключевым словом. Каждая функция имеет уникальное имя. Раньше main мы часто встречали именованную функцию без параметров и не возвращали результатов.

func main() {
  // ...
}

Напишем небольшую программу, чтобы понять функции:

package main
 
import "fmt"
 
func main() {
    n := []int{5,10,15,20}
    t := 0
 
    for _, v := range n {
        t += v
    }
 
    fmt.Println(t)
}

В этом примере n мы написали блок кода, который собирает серию числовых данных, присвоенных его переменной, и выводит их на экран. Давайте преобразуем блок кода, который выполняет добавление, в новую функцию, отсоединив его от основного блока.

func toplam(n []int]) {
    t := 0
 
    for _, v := range n {
        t += v
    }
 
    fmt.Println(t)
}

В приведенном выше примере функции toplam named требуется один ввод (параметр), и она не возвращает никаких результатов. Мы можем понять этот вывод из соглашения о прототипе функции. Давай продолжим.

func name(inputs) outputs {
    // body
}

Приведенное выше утверждение является простейшей формулой функций, другими словами прототипом. Если toplam нас попросят объяснить функцию, которую мы создали по этой формуле, n []intвы можете сказать, что она получает один параметр своего типа сразу после имени функции. Опять же, согласно формуле, было бы уместно сказать, что она не возвращает значение, потому что в поле вывода ничего не определено.

mainВозвращаясь к функции для вызова функции, давайте обновим тело функции:

func main() {
    toplam([]int{5,10,15,20})
}

Программа выглядит чистой, но ее нельзя использовать повторно. Не было бы лучше, если бы мы вывели вычисленное значение суммы обратно на экран, вместо того, чтобы печатать его внутри функции? Таким образом, выходное значение можно использовать для разных целей. Давайте познакомимся с функциями, которые возвращают результаты, внеся некоторые изменения:

func toplam(n []int]) int {
    t := 0
 
    for _, v := range n {
        t += v
    }
 
    return t
}

Вы заметили изменение? Go хочет заранее знать тип возвращаемого значения, если результаты должны быть возвращены функциями. intГарантированно возвращает один результат типа обратно из функции. В последней строке тела вместо вывода результата на экран return значение возвращается с ключевым словом.

Теперь main, чтобы вернуться и изменить применение функции:

func main () { 
    result: = sum ([] int {5,10,15,20}) 
 
    fmt.Println (result) 
}

Теперь toplam новое значение, полученное из функции, можно использовать для разных целей. Либо распечатайте результат на экране, либо сохраните его в файл.

Давайте немного усложним ситуацию. Как бы вы хотели написать программу, которая принимает много параметров и возвращает много результатов?

package main
 
import "fmt"
 
func main() {
    o1, o2:= islem(5, 6)
 
    fmt.Printf("o1: %v, o2: %v", o1, o2)
}func islem(a int, b int) (int, float64) {
    x := a * b
    y := float64(a) * 0.25
 
    return x, y
}

Подобно параметризованным функциям, которые мы определили ранее, имя и тип каждого принимаемого параметра объявляются в заголовке функции. Если необходимо вернуть более одного результата, типы данных для вывода указываются в скобках.

Если данных, которые должны быть возвращены из функции, больше одного, типы данных, которые должны быть возвращены, должны быть указаны в круглых скобках в заголовке функции. При возврате одного результата круглые скобки не требуются.

func islem (a, b int) (int, float64) {
    // ...
}

В Go вы можете сгруппировать последовательные параметры того же типа, что и в приведенном выше примере.

Представьте себе такую ​​ситуацию: у нас есть функция, которая возвращает множество результатов, но нам не нужно использовать их все в приложении. Так что некоторые результаты нам не нужны. В этом случае нам нужно игнорировать неиспользуемые выходы функции с пустым идентификатором:

package main
 
import "fmt"
 
func main() {
    _, iki, _ := fn()
 
    fmt.Println(iki)
}
 
func fn() (int, int, int) {
    return 1, 2, 3
}

Помните, что если переменная определена в Go, ее необходимо использовать. По этой причине мы должны игнорировать избыточные значения, которые мы получаем от функций с пустым идентификатором.

Наконец, давайте быстро рассмотрим функции, известные как вариативные функции, которые принимают неопределенные (ноль, один или несколько) параметров. fmt.Printlnфункция, которую мы очень часто используем, на самом деле является функцией с переменным числом аргументов. В исходных кодах Go функция is определяется следующим образом:

func Println(a ...interface{}) (n int, err error)

В этой функции параметр a named interface{} принимает неопределенное количество входов типа (любого типа). Неопределенность количества параметров выражается выражением (3 балла).

toplamДавайте изменим функцию, которую мы использовали в примере, чтобы получить неопределенное количество параметров:

func toplam(n ...int) int {
    t := 0
 
    for _, v := range n {
      t += v
    }
 
    return t
}

Мы обновили n []int объявление параметра a ...int в соответствии с функцией, которую мы создали ранее. Вот и все. Чтобы вызвать эту функцию:

func main () { 
    result: = sum (1, 2, 10, 15) 
 
    fmt.Println (result) 
}

Управление ошибками

Go оставляет обработку ошибок разработчику. В отличие от других языков Go хочет, чтобы каждая ошибка обрабатывалась индивидуально. В Go есть два разных механизма обработки ошибок:

  • функции error вернуть результат обратного типа
  • panic Исключение времени выполнения генерируется с инструкцией (не рекомендуется)

Поскольку Go может возвращать большое количество результатов, ошибки, возникающие в программах, error сообщаются с результатом, полученным из его интерфейса.

type error interface {
    Error() string
}

Go try/catch не имеет механизма обработки ошибок. Вместо этого проверяется errorresult, возвращаемый функциями. Фактически, эта функция практичнее и чище, чем решения на других языках.

Например; При работе с файловыми системами функция os.Open возвращает тип возврата errorresult в тех случаях, когда не может открыть файл. Ниже представлен прототип этой функции:

func Open(name string) (file *File, err error)

Когда мы используем эту функцию, нам нужно проверить, не вызывает ли процесс ошибок. В приведенном ниже примере показано, как проверить наличие ошибки.

f, err := os.Open("file.txt")if err != nil {
    log.Fatal(err)
}// do something with variable "f"

Попробуем разобраться в предмете на собственном примере. Напишем простую функцию, выполняющую деление. Если значение раздела равно нулю, мы сгенерируем ошибку и отловим эту ошибку в программе.

package mainimport (
   "errors"
   "fmt"
   "log"
)func bol (number, bolen float64) (float64, error) { 
    if bolen == 0 { 
        return 0, errors.New ("the divisor cannot be zero") 
    }    result: = number / bolen    return sonuc, nil
}func main() {
    sonuc, err := bol(5, 0)    if err != nil {
        log.Fatal(err)
    }    fmt.Printf("sonuc: %v", sonuc)
}

Пример включает рекомендуемое использование функций для возврата и обработки ошибок. Для создания собственных ошибок достаточно использовать одну из функций в пакете ошибок.

err := errors.New("hata mesajı")

Что мы будем учитывать, возвращая в результате ошибки в функциях:

  • errorДругие параметры значения, кроме случая ошибки, могут быть заполнены значениями по умолчанию типа
  • Если ошибки нет, error возвращаемое значение nil должно соответствовать
  • В функциях, возвращающих несколько результатов, errorпараметр его типа обычно стоит на последнем месте (наилучшая практика).

Для получения дополнительной информации вы можете ознакомиться с описанием документации пакета, сообщения в блоге и Effective Go.

Структуры

В языке Go нет классов, это все равно не объектно-ориентированный язык программирования. В нем есть только преимущества подхода ООП.

Классы можно эмулировать с помощью структур. Конструкционные элементы могут приниматься как свойства.

type Rect struct {
    width  float64
    height float64
}

В приведенном выше примере мы создали именованную структуру, которая содержит widthи heightvariables Rect. Структурные элементы могут иметь все типы данных, которые мы изучили до сих пор. Он может даже принять в качестве типа другое здание.

package mainimport "fmt"type Rect struct {
    width  float64
    height float64
}func main() {
    r := Rect{}    fmt.Printf("%+v\n", r)
}

Опишем Rectпример полученной структуры (экземпляра). Поскольку мы еще не загрузили никаких значений в элементы структуры, значения по умолчанию присваиваются автоматически, как вы помните из раздела переменных.

package mainimport "fmt"type Rect struct {
    width  float64
    height float64
}func main() {
    r := Rect{}
    r.width = 5.0
    r.height = 4.0    fmt.Printf("%+v\n", r)
    fmt.Printf("width: %.2f, height: %.2f", r.width, r.height)
}

Оператор . (точка) используется для доступа к элементам здания. Чтобы присвоить значение элементу или получить его значение, мы можем получить доступ к элементам с помощью оператора точки через переменную экземпляра.

r := Rect{5.0, 4.0}

Создавая структуру, мы также можем определить начальные значения. В приведенном выше примере переменным будут присвоены значения в соответствии с порядком в определении структуры. В этом случае он будет иметь widthvalue 5.0и heightvalue 4.0.

r := Rect{
    width:  5.0,
    height: 4.0,
}

Структура - наиболее предпочтительное написание для инициализации. Обычно при выборке структуры явно указываются значения переменных.

Методы

Это специальные функции, определенные для структур в Go. Эти функции принадлежат структурам и могут использоваться только с примерами структур.

RectДавайте напишем метод (функцию), который вычисляет и возвращает значение площади для структуры, которую мы создали в предыдущем разделе.

type Rect struct {
    width  float64
    height float64
}func (r Rect) Area() float64 {
    return r.width * r.height
}

Все правила, применяемые к функциям, действительны в определении метода. В отличие от функций, используемая структура указывается непосредственно перед именем функции. В данном случае это означает, что Areaфункция Rect принадлежит его структуре.

r := Rect{
    width:  5.0,
    height: 4.0,
}fmt.Println("area:", r.Area())

Мы используем оператор точки для вызова функции. Вызов функции осуществляется через переменную экземпляра.

В нашем примере мы определили функцию, которая не принимает параметров. В Go также могут быть определены функции с параметрами и возвращающими несколько значений.

Указатели

Указатели содержат адрес значения в памяти.

Адрес & переменной в памяти берется с помощью оператора (и). Значение адреса памяти * отображается с помощью оператора (звездочка).

package mainimport "fmt"func main() {
    a := 5
    c := &a    fmt.Println(c)
}

В приведенном выше примере c переменная ahe была назначена ссылке на переменную. Когда вы запускаете программу, печатается 0x40e020 результат, аналогичный отображаемому на экране. Фактически это значение aaddress переменной в памяти.

*Давайте воспользуемся его оператором, чтобы вывести на экран значение переменной, содержащей ссылку:

fmt.Println(*c)

При использовании указателя следует соблюдать осторожность. Обычно, когда вы присваиваете значение одной переменной другой переменной, значение копируется. Однако, когда присвоение выполняется по ссылке, вместо значения создается ссылочная копия. Таким образом, если исходная или ссылочная переменная претерпевает изменение, обе переменные изменят свои значения.

package mainimport "fmt"func main() {
    a := 5
    b := a
    c := &a    // a = 3
    *c = 3    fmt.Println(a, b, *c)
}

Когда вы запустите указанную выше программу a, вы увидите, что значение ее переменных c изменяется, но b значение ее переменной не изменяется.

Функции и методы могут принимать ссылки в качестве параметров. Когда параметр передается функциям, создается копия переменной. Однако, если параметр является ссылкой, адрес переменной в памяти отправляется вместо создания новой копии. Если переменная претерпевает какие-либо изменения внутри функции, переменная, переданная в функцию, или структура (переменная), из которой вызывается функция, также изменяется.

package mainimport "fmt"type Rect struct {
    width  float64
    height float64
}func (r Rect) setWidth(w float64) {
    r.width = w
}func (r *Rect) setHeight(h float64) {
    r.height = h
}func main() {
    r := Rect{
        width:  5.0,
        height: 4.0,
    }    r.setWidth(2.0)
    r.setHeight(3.0)    fmt.Printf("%+v", r)
}

Поскольку в приведенном выше примере setWidth применяется как значение, создается копия структуры, примененной к функции. Даже если значение widthits изменяется в функции, это не вызывает изменения в структуре, которая выполняет этот вызов.

Однако, поскольку setHeightit применяется как ссылка, refean передается вместо новой копии структуры. Когда значение heightits изменяется в теле функции, на него влияет структура, выполнившая вызов.

Вы можете запустить программу и наблюдать результат.

Интерфейсы

Интерфейсы, другими словами, интерфейсы широко используются в мире ООП. Go реализует интерфейсы со структурой и функциями и предлагает фиктивную поддержку ООП.

В отличие от объектно-ориентированных языков программирования, в Go интерфейс не реализован явно. Чтобы интерфейс был реализован, все функции в интерфейсе должны быть определены в структуре. Когда все функции созданы, Go принимает реализацию интерфейса.

Приведем пример, чтобы понять предмет. Представьте, что вам нужна программа, которая вычисляет площадь для фигур. Формула расчета площади отличается для каждой формы. Ранее мы diktörtgen выполнили расчет домена, но он daire не подходит для этого. Давайте создадим программу, которая поддерживает прямоугольные, круглые и другие формы будущего, применив интерфейс.

type Shaper interface {
    Area() float64
}

Наш Shaperinterface выше включает одну функцию. Рекомендуется er заканчивать именами интерфейсов, значимыми или нет для языка Go. Интерфейсы могут содержать ноль, одну или несколько функций.

RectДавайте применим этот интерфейс к структуре, которую мы создали ранее.

type Rect struct {
    width  float64
    height float64
}func (r Rect) Area() float64 {
    return r.width * r.height
}

Интерфейс был успешно реализован, так как его Rect структура теперь Shaper удовлетворяет требованиям интерфейса. Давайте проверим, если хотите:

func main () {
    var r Shaper = Rect{
        width:  5.0,
        height: 4.0,
    }
 
    fmt.Printf("type of r is %T\n", r)
    fmt.Printf("value of r is %v\n", r)
    fmt.Printf("value of r area is %.2f\n\n", r.Area())
}

Когда мы Shaper захотели создать переменную нового типа в примере, компилятор разрешил этот запрос. Если Rect его структура не соответствует правилам интерфейса, компилятор отклонит наш запрос и выдаст ошибку.

Функции могут принимать тип интерфейса как тип параметра. Благодаря этой функции мы можем писать более гибкие (расширяемые) программы.

Давайте создадим новую круговую структуру и применим интерфейс:

type Circle struct {
     radius float64
}func (c Circle) Area() float64 {
    return 3.14 * c.radius * c.radius
}

И, наконец, Calculator давайте напишем нашу функцию, выполняющую вычисления. Если бы не было интерфейсов, было бы невозможно управлять двумя разными типами структур фигур (прямоугольными и круговыми) в одной и той же функции.

func Calculator(s Shaper) float64 {
    return s.Area()
}

Как вы заметили, функция Shaper принимает в качестве параметра переменную типа. Таким образом, Shaper, каждая переменная, реализующая ее интерфейс, может Calculator быть отправлена ​​в качестве параметра своей функции.

package mainimport "fmt"type Shaper interface {
    Area() float64
}func Calculator(s Shaper) float64 {
    return s.Area()
}type Rect struct {
    width  float64
    height float64
}type Circle struct {
    radius float64
}func (r Rect) Area() float64 {
    return r.width * r.height
}func (c Circle) Area() float64 {
    return 3.14 * c.radius * c.radius
}func main() {
    r := Rect{width: 5.0, height: 4.0}
    c := Circle{radius: 3.0}    fmt.Printf("rect area is %.2f\n\n", Calculator(r))
    fmt.Printf("circle area is %.2f\n\n", Calculator(c))
}

Игровая площадка Го

Go Playground - это веб-сервис, работающий на серверах golang.org. Сервис получает программу Go, ветеринары…

Play.golang.org

В ядре Go есть много предопределенных интерфейсов, даже интерфейсы используются очень часто. Время от времени мы реализуем основные интерфейсы в разрабатываемых нами программах.

Для большей гибкости мы определяем функции или функции как тип интерфейса вместо определения типа структуры как параметра. Итак, какой бы ни была структура, функция принимает интерфейс, который она распознает.

В итоге:

  • При именовании интерфейса er рекомендуется заканчивать его суффиксом.
  • Интерфейсы могут содержать ноль, одну или несколько функций. Функции - это функции, определенные для структур.
  • Функции интерфейса могут быть с параметрами или без них.
  • Интерфейсные функции могут возвращать ноль, одно или несколько значений.
  • Структуры могут реализовывать один или несколько интерфейсов. Вместо того, чтобы определять большой интерфейс, лучше разбить интерфейсы для достижения общей цели. (ReadWriter вместо двух отдельных Reader и Writer интерфейсов)

Отличные приложения постоянно развиваются и меняются. При правильном использовании интерфейсов будущие потребности могут быть легко удовлетворены с меньшими усилиями. Всегда заботьтесь о гибкости.

Предлагаю изучить тему Внедрение зависимостей.

Пакеты

В начале статьи мы упоминали, что приложения Go разрабатываются модульно с помощью пакетов.

Вспомните лего. Пакеты - это другая часть Лего. Собрав детали воедино, вы легко сможете построить дом своей мечты или даже очень большой город. Детали независимы друг от друга и могут использоваться повторно.

Он находится в пакетах в Go. Он содержит независимые способности каждого, и вы можете использовать их снова и снова, когда напишете их. Вы даже можете использовать его как открытый исходный код. Пакеты можно импортировать из разных источников (локальный или удаленный сервер):

  • «Fmt»
  • «Математика / ранд»
  • «Github.com/guptarohit/asciigraph»

Как правило, имя пакета совпадает с последним элементом пути импорта. Однако иногда это может отличаться. Исключения указаны в руководстве пользователя пакета. Пространства имен вышеперечисленных пакетов при импорте:

  • fmt
  • ранд
  • аскииграф

будет.

Вы можете искать нужные пакеты на сайтах сервисов кода, таких как Github, Gitlab, Bitbucket.

Скачать пакет

Go поставляется с менеджером пакетов. Вы go get можете легко загрузить нужные вам пакеты с помощью команды. importВы можете импортировать и использовать загруженный пакет в своей программе с оператором.

Откройте терминал, войдя в рабочий каталог и введите следующую команду:

go get github.com/guptarohit/asciigraph

После завершения загрузки пакет будет готов к использованию. Давайте посмотрим на использование пакета на примере из описаний пакетов:

package mainimport (
    "fmt"
    "github.com/guptarohit/asciigraph"
)func main() {
    data := []float64{3, 4, 9, 6, 2, 4, 5, 8, 5, 10, 2, 7, 2, 5, 6}
    graph := asciigraph.Plot(data)    fmt.Println(graph)
}

Все очень просто. go getЗагрузите его в среду разработки с соответствующим пакетом и import начните использовать его, включив в проект.

Иногда имена пакетов конфликтуют друг с другом, или вы можете использовать имя пакета с псевдонимом. В этом случае достаточно import, чтобы добавить псевдоним перед названием пакета. Давайте рассмотрим пример ниже:

package mainimport (
    "fmt"
    rnd "math/rand"
)func main() {
    n := rnd.Int()    fmt.Println(n)
}

Мы сообщили rand, что rnd мы будем использовать его в качестве имени пакета, даже если это так. Теперь нам нужно rand.Int(), чтобы rnd.Int() использовать его вместо вызова функций внутри пакета.

Наконец, давайте . будем использовать оператор (точка) при импорте пакетов. Добавляя оператор точки непосредственно перед именем пакета, можно использовать явные идентификаторы пакета, как если бы они принадлежали текущему пакету.

package mainimport (
    "fmt"
    . "math/rand"
)func main() {
    n := Int()    fmt.Println(n)
}

Теперь rand идентификаторы внутри пакета можно вызывать без имени пакета. Можно использовать только Int() как.

Оператор точки не очень предпочтителен, поскольку он скрывает, в каком пакете находится идентификатор.

Создание пакета

Создавать пакеты в Go очень просто. Приведем простой пример. fundingСоздайте папку с именем в рабочей области и fund.goсоздайте файл внутри. Напишите и сохраните примеры кодов ниже.

package fundingtype Fund struct {
    balance int
}func NewFund(initial int) *Fund {
    return &Fund{
        balance: initial,
    }
}func (f *Fund) Balance() int {
    return f.balance
}func (f *Fund) Withdraw(amount int) {
    f.balance -= amount
}

Вот и все. Go main будет понимать эти коды как собственные пакеты во время компиляции, потому что они находятся вне его пакета. Вы можете получить доступ ко всем идентификаторам, которые были импортированы и экспортированы, где бы вы ни хотели их использовать. Импортировать:

import "MYPROJECT/funding"

В приведенном выше примере MYPROJECT вы должны написать имя вашего собственного проекта, которое вы назвали при создании проекта.

При желании вы можете загрузить этот простой пакет, установив его в сервисах кода (Github), версию (git, svn) и когда он вам понадобится go get.

Для получения дополнительной информации обязательно ознакомьтесь с документацией Модули Go и Как писать код Go.

Тестирование

Завершено, приложение прошло тщательное тестирование и готово к распространению, так как все в порядке. Мы хотели добавить новую функцию после развертывания. Мы завершили разработку и провели повторное тестирование. Этот цикл необходимо повторять после каждого проявления.

Разве не сложно было бы контролировать все с помощью человеческой силы? После каждой разработки приложение следует (полностью) тестировать с нуля, чтобы проверить, не повлияла ли разработка на то или иное место. Количество тестируемых функций в разрабатываемом приложении будет постоянно увеличиваться.

Если программное обеспечение предназначено для решения проблем, почему бы нам не автоматизировать его? Go уже предлагает встроенный набор тестов.

Давайте быстро рассмотрим тестовый пакет, написав тестовые примеры для пакета, который мы создали в предыдущем разделе.

Если файл будет тестироваться в Go, рекомендуется назвать funding.go тестовый файл funding_test.go. Он *_test.go обнаруживает файлы инструментов, которые запускают процессы тестирования, и запускает методы тестирования в этом файле.

package fundingimport "testing"func TestNewFund(t *testing.T) {
    f := NewFund(5)    if f.Balance() != 5 {
        t.Error("Balance değeri hatalı")
    }
}

В приведенном выше примере была протестирована его NewFundфункция. Test Достаточно добавить префикс перед названием тестируемого элемента. Поэтому мы определили новую тестовую функцию NewFund для функции TestNewFund named. Это проверка точности значения, изначально присвоенного конструкции.

go testtool используется для запуска теста. Вы можете запустить файл или все тесты в приложении / пакете. Все тесты запускаются, когда вы запускаете следующую команду в рабочем каталоге.

go test ./...

Если вы хотите, чтобы ./... запускал тест для одного файла, просто введите файл Go, который вы хотите запустить.

go test ./funding

Вы можете протестировать тесты в нескольких сценариях:

package fundingimport "testing"func TestNewFund(t *testing.T) {
    testPairs := []struct {
        set int
        get int
    }{
        {0, 0},
        {5, 5},
    }    for _, p := range testPairs {
        f := NewFund(p.set)        if f.Balance() != p.get {
            t.Errorf("Sonuç: %d, Beklenen: %d", f.Balance(), p.get)
        }
    }
}

В приведенном выше примере мы testPairsсоздали новую структуру, которая содержит названные тестовые примеры. Мы сохранили setvalue, которое мы загрузили в начале, и значение, которое мы хотим получить, с его getname. Мы применили их все с помощью цикла и проверили, будет ли результат одинаковым.

Мы можем протестировать каждый модуль, подготовив тестовые примеры для всех функций в пакете.

package fundingimport "testing"testPairs: = [] struct { 
    i int // initial value 
    w int // shot amount 
    b int // remainder 
} { 
    {0, 0, 0}, 
    {0, 5, -5}, 
    {10, 10, 0} , 
    {10, 0, 10}, 
    {10, 5, 5}, 
}func TestFund(b *testing.B) {
    for _, p := range testPairs {
        f := NewFund(p.i)        f.Withdraw(p.w)        if fund.Balance() != 0 {
            t.Errorf("Sonuç: %d, Beklenen: %d", f.Balance(), p.b)
        }
    }
}

Выше мы написали общий тест, который проверяет сценарий за один раз. Итак, мы протестировали весь поток в одной тестовой функции. Как правило, тесты пишутся специально для модуля, но иногда сценарий можно протестировать полностью.

Вы можете посетить документацию по пакету для получения дополнительной информации.

Закрытие

Вы можете перейти по ссылкам ниже, чтобы быть в курсе событий и узнавать больше о Go:

Оставайся с любовью.