Учебные заметки GoLang (2) «Языковая битва Go»

Go

Глава 1-3

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

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

goroutine

Горутина — это функция, которая может выполняться параллельно с другими горутинами, а также параллельно с основной программой (записью программы) воплощать в жизнь.

ряд

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

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

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

система типов

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

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

Функция init() будет вызываться перед функцией main().

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

Импортированным путям предшествует символ подчеркивания, например.

_ "github.com/goinaction/code/chapter2/sample/matchers"

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

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

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

В языке Go все переменные инициализируются своим нулевым значением. Для числовых типов нулевое значение равно 0, для строковых типов Нулевое значение — это пустая строка, для логических типов нулевое значение равно false, для указателей нулевое значение равно nil. Для ссылочных типов Базовая структура данных, на которую ссылаются, инициализируется соответствующим нулевым значением. Но переменная ссылочного типа, объявленная как имеющая нулевое значение, вернет возвращает nil в качестве значения.

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

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

Упрощенный оператор объявления переменных (:=). Этот оператор используется для объявления переменной и присвоения ей начального значения. Компилятор использует тип возвращаемого значения функции для определения типа каждой переменной. Упрощенный оператор объявления переменных — это просто сокращенная запись, которая делает код более читаемым. Переменные, объявленные с помощью этого оператора, ничем не отличаются от других переменных, объявленных с помощью ключевого слова var.

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

Группа ожидания пакета синхронизации отслеживает все запущенные горутины. В реальной разработке настоятельно рекомендуется использовать WaitGroup для Отслеживает, выполнена ли работа горутины. WaitGroup — это семафор-счетчик, мы можем использовать его для подсчета всех Завершили ли горутины свою работу.

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

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

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

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

Ключевое слово defer планирует последующие вызовы функций, которые будут выполнены, когда функция вернется. После использования файла необходимо активно закрыть Закройте файл. Использование ключевого слова defer для планирования вызова метода Close гарантирует, что функция будет вызвана. четная буква Это также гарантирует, что функция, вызываемая ключевым словом defer, будет выполнена, если она неожиданно завершится из-за сбоя. Ключевое слово defer сокращает хит Количество строк кода между открытием и закрытием файлов, что помогает улучшить читаемость кода и уменьшить количество ошибок.

Поведение интерфейса в конечном счете определяется методами, объявленными в типе интерфейса.

При именовании интерфейсов вам также необходимо следовать соглашениям об именовании языка Go. Если тип интерфейса содержит только один метод, то этот Имя типа заканчивается на er. Это то, что делает наш пример, поэтому имя интерфейса — Matcher. подобно Если тип интерфейса объявляет внутри несколько методов, его имя должно быть связано с его поведением.

type Matcher interface {
    Search(feed *Feed, searchTerm string) ([]*Result, error)
}

Если определяемый пользователем тип должен реализовать интерфейс, определяемый пользователем тип должен реализовывать тип, объявленный в типе интерфейса. Все методы.

type defaultMatcher struct{}

Приведенный выше код объявляет тип структуры с именем defaultMatcher с пустой структурой. Пустая структура не выделяет память при создании экземпляра. Эта структура отлично подходит для создания типов без какого-либо состояния.

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

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

Удаленный импорт

При компиляции программы с путем импорта команда go build использует параметр GOPATH для поиска пакета на диске. По факту, Этот путь импорта представляет собой URL-адрес, указывающий на репозиторий на GitHub. Если путь содержит URL-адрес, вы можете использовать цепочку инструментов Go из DVCS извлекает пакет и сохраняет исходный код пакета в каталоге, соответствующем URL-адресу в пути, на который указывает GOPATH. процесс приобретения Это делается с помощью команды go get. go get получит пакет по любому указанному URL-адресу или любой другой пакет, от которого зависит импортированный пакет. Он упаковывает. Из-за рекурсивной природы go get эта команда сканирует исходное дерево пакета на наличие всех зависимостей, которые она может найти.

именованный импорт

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

import (
    "fmt"
    myfmt "mylib/fmt"
)

пустой идентификатор

Символ подчеркивания (_) в Go называется идентификатором пробела и имеет множество применений. Этот идентификатор используется для сброса Значения, которые вы хотите продолжать использовать, такие как предоставление импортированным пакетам пустого имени или игнорирование значений, возвращаемых функциями, которые вас не интересуют.

инициализация функции

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

Запустите код с помощью команды go run.

Команда go vet поможет разработчикам обнаружить распространенные ошибки в их коде, такие как:

  1. Когда вызывается функция класса Printf, тип соответствует неверному аргументу.
  2. Ошибка в подписи метода при определении часто используемых методов.
  3. Неправильная маркировка структуры.
  4. Литерал структуры без указания имен полей.

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

Перейти к форматированию кода с помощью команды fmt.

go doc Вы можете просмотреть документацию по связанным пакетам, таким как go doc http.

Просмотр документов Разработчики могут запустить свой собственный сервер документации, просто введя следующую команду в сеансе терминала: годок-http =: 6060 Эта команда указывает godoc запустить веб-сервер на порту 6060. Если браузер уже открыт, перейдите кhttp://localhost:6060Вы можете увидеть страницу с документацией для всех стандартных библиотек Go и исходным кодом Go в вашем GOPATH.

  1. Пакет — это основная единица организации кода в Go.
  2. Переменная среды GOPATH определяет, где на диске сохраняется, компилируется и устанавливается исходный код Go.
  3. Для каждого проекта можно установить разные GOPATH, чтобы изолировать исходный код и зависимости.
  4. Инструмент go — лучший инструмент для работы в командной строке.
  5. Разработчики могут использовать go get для получения пакетов других людей и установки их в каталог, указанный их GOPATH.
  6. Создать пакеты для других так же просто, как поместить исходный код в общедоступный репозиторий и следовать некоторым простым правилам.
  7. Язык Go был разработан с учетом совместного использования кода в качестве основной функции и движущей силы языка.
  8. Для управления зависимостями рекомендуется использовать инструмент управления зависимостями.
  9. Существует множество инструментов управления зависимостями, разработанных сообществом, таких как godep, vendor и gb.

Глава 4 Массивы, срезы и карты

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

Внутренняя реализация массивов

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

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

Объявление и инициализация массива

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

var array [5]int // 声明一个包含 5 个元素的整型数组

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

array:= [5]int{1,2,3,4,5}


// 声明一个整型数组
// 用具体值初始化每个元素
// 容量由初始化值的数量决定
array := [...]int{10, 20, 30, 40, 50}

// 声明一个有 5 个元素的数组
// 用具体值初始化索引为 1 和 2 的元素
// 其余元素保持零值
array := [5]int{1: 10, 2: 20}

Многомерные массивы

// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}

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

Внутренняя реализация и основные функции слайсов

Обоснование. Срез — это структура данных, упрощающая использование и управление коллекциями данных. Нарезка — это концепция динамических массивов. Создан для автоматического увеличения и уменьшения по мере необходимости. Динамический рост слайсов достигается за счет встроенной функции append. Это письмо Цифры могут быстро и эффективно увеличиваться в размерах. Вы также можете уменьшить размер фрагмента, снова нарезав его. из-за нарезанного Базовая память также выделяется в смежных блоках, поэтому срезы также получают преимущества индексации, итерации и оптимизации для сборки мусора.

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

Создание и инициализация среза

Способ 1: создание и нарезка литералов

// 创建一个字符串切片
// 其长度和容量都是 5 个元素
slice := make([]string, 5)

// 创建一个整型切片
// 其长度为 3 个元素,容量为 5 个元素
slice:=make([]int,3,5)

// 创建字符串切片
// 其长度和容量都是 5 个元素
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}

Помните, что если вы указываете значение в операторе [], вы создаете массив, а не срез. только если значение не указано когда срез создан

// 创建有 3 个元素的整型数组
array := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
slice := []int{10, 20, 30}

Для среза slice[i:j], базовая емкость массива которого равна k

Длина: j - i

Вместимость: к - я

срез роста

При добавлении вам нужен срез для работы и значение для добавления.

Примечание. Функция append интеллектуально обрабатывает рост базового массива. Когда емкость среза меньше 1000 элементов, всегда умножит емкость. Как только количество элементов превысит 1000, коэффициент роста емкости будет установлен равным 1,25, то есть каждый раз он будет увеличиваться на 25%. емкость. Этот алгоритм роста может меняться по мере развития языка.

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

// 创建两个切片,并分别用两个整数进行初始化
s1 := []int{1, 2}
s2 := []int{3, 4}
// 将两个切片追加在一起,并显示结果
fmt.Printf("%v\n", append(s1, s2...))
Output:
[1 2 3 4]

Для слайсов функция len возвращает длину слайса, а функция cap возвращает вместимость слайса.

Передача срезов между функциями

На машинах с 64-битной архитектурой слайсу требуется 24 байта памяти: 8 байтов для поля указателя, длины и емкости Каждое поле требует 8 байтов. Поскольку данные, связанные со срезом, содержатся в базовом массиве и не принадлежат самому срезу, срез При копировании в любую функцию это не влияет на размер базового массива. При копировании копируется только сам срез, дно не задействовано Массив слоев, передавая 24 байта данных между функциями очень быстро и легко. Здесь также высока эффективность нарезки. нет необходимости проходить Игла и обработка сложного синтаксиса, просто скопируйте фрагмент, измените данные так, как вы хотите, и верните новую копию фрагмента.

Внутренняя реализация и основные функции отображения

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

Внутренняя реализация

Создать и инициализировать

//创建一个映射,键的类型是 string,值的类型是 int
dict:=make(map[string]int)

// 创建一个映射,键和值的类型都是 string
// 使用两个键值对初始化映射
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}

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

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

// 获取键 Blue 对应的值
value, exists := colors["Blue"]
// 这个键存在吗?
if exists {
    fmt.Println(value)
}

Когда карта индексируется по ключу, всегда возвращается значение, даже если ключ не существует. В этом случае возвращается нулевое значение типа, соответствующего значению.

Передача карт между функциями

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

краткое содержание главы

  1. Массивы являются строительными блоками для построения срезов и карт.
  2. В Go срезы часто используются для работы с коллекциями данных, а карты используются для работы с данными со структурой пар ключ-значение.
  3. Встроенная функция make может создавать срезы и карты, указывая исходную длину и емкость. Вы также можете использовать фрагменты напрямую и отображать литералы, или использовать литералы в качестве начальных значений для переменных.
  4. Объем срезов ограничен, но их можно расширить с помощью встроенной функции добавления.
  5. Нет никакой емкости или какого-либо ограничения на рост карты.
  6. Встроенная функция len может использоваться для получения длины среза или карты.
  7. Встроенная функциональная крышка может использоваться только для нарезки.
  8. Комбинируя, вы можете создавать многомерные массивы и многомерные срезы. Также возможно использовать срезы или другие карты в качестве значений карты. Но слайсы нельзя использовать в качестве ключей карт.
  9. Передача среза или карты в функцию не требует больших затрат и не копирует базовую структуру данных.

Глава 5. Система типов языка Go

метод

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

В языке Go есть два типа приемников: приемники значений и приемники указателей.

 // notify 使用值接收者实现了一个方法
func (u user) notify() {
    fmt.Printf("Sending User Email To %s<%s>\n",
    u.name,u.email)
}

Если метод объявлен с получателем значения, копия значения используется для выполнения вызова.

// changeEmail 使用指针接收者实现了一个方法
func (u *user) changeEmail(email string) {
    u.email = email
}

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

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

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

интерфейс

Встроенный тип

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

type user3 struct {
	name  string
	email string
}

type admin struct {
	user3
	level string
}

В приведенном выше коде мы объявляем тип структуры с именем user и другой тип структуры с именем admin. В методе, который объявляет тип администратора, мы встраиваем тип пользователя внутри типа администратора. Чтобы внедрить тип, просто объявите имя типа. Как только мы встроим тип пользователя в admin, мы можем сказать, что пользователь является внутренним типом внешнего типа admin.

Раскрытые или нераскрытые идентификаторы

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

резюме

  1. Пользовательские типы могут быть объявлены с помощью ключевого слова struct или путем указания уже существующего типа.
  2. Методы предоставляют способ добавления поведения к пользовательским типам.
  3. При разработке типа необходимо подтвердить, является ли природа типа примитивной или непримитивной.
  4. Интерфейс — это тип, который объявляет набор поведений и поддерживает полиморфизм.
  5. Встроенные типы предоставляют возможность расширять типы без использования наследования.
  6. Идентификаторы либо предоставляются из пакета, либо не предоставляются в пакете.

Глава 6 Параллелизм

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

Модель синхронизации параллелизма в Go исходит из процесса, называемого Communicating Sequential Processes (CSP). Парадигма (парадигма). CSP — это модель передачи сообщений, в которой сообщения передаются путем передачи данных между горутинами вместо Заблокируйте данные для обеспечения синхронного доступа. Ключевой тип данных для синхронизации и передачи данных между горутинами называется каналом. (канал).

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

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

заблокировать общие ресурсы

Один из способов исправить код и устранить состояние гонки — использовать механизм блокировки, предоставляемый языком Go, для блокировки общих ресурсов от И гарантировать состояние синхронизации горутины. Язык Go предоставляет традиционный механизм синхронизации горутин, заключающийся в блокировке общих ресурсов. Если вам нужен последовательный доступ к Целочисленные переменные или фрагмент кода, функции в пакетах atomic и sync обеспечивают хорошее решение.

атомарная функция

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

Например, атомарные функции AddInt64, LoadInt64 и StoreInt64 в пакете atmoic.

Мьютекс

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

mutex.Lock()//加锁
临界区的代码
mutex。Unlock()//解锁

ряд

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

// 无缓冲的整型通道
unbuffered := make(chan int)
// 有缓冲的字符串通道
buffered := make(chan string, 10)

Отправка значения или указателя на канал требует использования оператора

// 通过通道发送一个字符串
buffered <- "Gopher"

// 从通道接收一个字符串
value := <-buffered

Обратите внимание на

небуферизованный канал

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

буферизованный канал

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

резюме

  1. Параллелизм означает, что горутины работают независимо друг от друга.
  2. Используйте ключевое слово go, чтобы создать горутину для запуска функции.
  3. Oroutines выполняются на логических процессорах, которые имеют независимые системные потоки и очереди выполнения.
  4. Состояние гонки — это когда две или более горутины пытаются получить доступ к одному и тому же ресурсу.
  5. Атомарные функции и мьютексы позволяют предотвратить состояние гонки.
  6. Каналы обеспечивают простой способ обмена данными между двумя горутинами.
  7. Небуферизованные каналы гарантируют одновременный обмен данными, а буферизованные - нет.

Глава 7 Параллельные режимы

runner

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

резюме

  1. Каналы можно использовать для управления жизненным циклом программы.
  2. Оператор select с ветвью по умолчанию может использоваться для попытки отправки или получения данных в канал без блокировки.
  3. Буферизованные каналы можно использовать для управления набором повторно используемых ресурсов.
  4. Среда выполнения языка отвечает за координацию и синхронизацию каналов.
  5. Используйте небуферизованный канал для создания пула работающих горутин.
  6. Небуферизованный канал можно использовать в любое время, чтобы позволить двум горутинам обмениваться данными, гарантируя, что операция канала завершена. Другая сторона получила данные.

Глава 8 Стандартная библиотека

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

журнал

Простой настраиваемый регистратор

package main

import (
	"io"
	"io/ioutil"
	"log"
	"os"
)

var (
	Trace   *log.Logger
	Info    *log.Logger
	Warning *log.Logger
	Error   *log.Logger
)

func init() {

	file, err := os.OpenFile("errors.txt",
		os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalln("Failed to open error log file:", err)
	}

	Trace = log.New(ioutil.Discard, "TRACE:", log.Ldate|log.Ltime|log.Lshortfile)

	Info = log.New(os.Stdout, "INFO:", log.Ldate|log.Ltime|log.Lshortfile)

	Warning = log.New(os.Stdout, "WARNING:", log.Ldate|log.Ltime|log.Lshortfile)

	Error = log.New(io.MultiWriter(file, os.Stderr), "ERROR:",     log.Ldate|log.Ltime|log.Lshortfile)

}

func main() {

	Trace.Println("I have something standard to say")
	Info.Println("Special Information")
	Warning.Println("There is something you need to know about")
	Error.Println("Something has failed")

}

кодировать декодировать

Декодировать JSON

Используйте функцию NewDecoder пакета json и метод Decode для декодирования.

Разобрать данные json из сети

// 将 JSON 响应解码到结构类型
var gr gResponse
err = json.NewDecoder(resp.Body).Decode(&gr)
if err != nil {
    log.Println("ERROR:", err)
    return
}
fmt.Println(gr)

Иногда документ JSON, который необходимо обработать, существует в виде строки. В этом случае строку необходимо преобразовать Это байтовый срез ([]byte), десериализованный с помощью функции Unmarshal пакета json.

// 将 JSON 字符串反序列化到变量
var c Contact
err := json.Unmarshal([]byte(JSON), &c)
if err != nil {
    log.Println("ERROR:", err)
    return
}

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

// 将 JSON 字符串反序列化到 map 变量
var c map[string]interface{}
err := json.Unmarshal([]byte(JSON), &c)
if err != nil {
    log.Println("ERROR:", err)
    return
}
fmt.Println("Name:", c["name"])
fmt.Println("Title:", c["title"])
fmt.Println("Contact")
fmt.Println("H:", c["contact"].(map[string]interface{})["home"])
fmt.Println("C:", c["contact"].(map[string]interface{})["cell"])

кодировать JSON

Используйте функцию MarshalIndent пакета json для кодирования. Эта функция может легко преобразовать значение типа карты языка Go или значение типа структуры в документ JSON в удобочитаемом формате.

data, err := json.MarshalIndent(c, "", "    ")
if err != nil {
	fmt.Println("ERROR:", err)
	return
}
fmt.Println(string(data))

Глава 9 Тестирование и производительность

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

модульный тест

В Go есть два типа модульных тестов:

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

Примечание 1. Инструменты тестирования Go рассматривают только файлы, оканчивающиеся на _test.go, как тестовые файлы.

Примечание 2. Тестовая функция должна быть общедоступной и начинаться со слова Test. Не только имя функции должно начинаться с Test, но и сигнатура функции должна получать указатель на тип testing.T и не возвращать значения.

Например:

func TestDownload(t *testing.T) 

const checkMark = "\u2713" //输出对号
const ballotX = "\u2717"   //输出错号

Стандартная библиотека включает пакет под названием httptest, который позволяет разработчикам эмулировать Сетевые HTTP-вызовы.

func mockServer() *httptest.Server {
    f := func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(200)
        w.Header().Set("Content-Type", "application/xml")
        fmt.Fprintln(w, feed)
    }
    return httptest.NewServer(http.HandlerFunc(f))
}

Бенчмаркинг — это способ проверить производительность вашего кода. Хотите проверить производительность различных решений одной и той же проблемы и посмотреть Сравнительный анализ полезен, когда речь заходит о том, какое решение работает лучше. Тесты также можно использовать для определения процессора фрагмента кода. Или проблемы с эффективностью памяти, а эффективность этого кода может серьезно сказаться на производительности всего приложения.