From 02a7051563fb17610404db5a310d066bfd6abda2 Mon Sep 17 00:00:00 2001 From: badkaktus Date: Mon, 14 Oct 2019 23:18:33 +0300 Subject: [PATCH 1/2] fix links --- examples.txt | 148 +++--- examples/arrays/arrays.hash | 4 +- examples/atomic-counters/atomic-counters.hash | 4 +- examples/base64-encoding/base64-encoding.hash | 4 +- .../channel-buffering/channel-buffering.hash | 4 +- .../channel-directions.hash | 4 +- .../channel-synchronization.hash | 4 +- examples/channels/channels.hash | 4 +- .../closing-channels/closing-channels.hash | 4 +- examples/closures/closures.hash | 4 +- .../collection-functions.hash | 4 +- .../command-line-arguments.hash | 4 +- .../command-line-flags.hash | 4 +- .../command-line-subcommands.hash | 4 +- examples/constants/constants.hash | 4 +- examples/directories/directories.hash | 4 +- .../environment-variables.hash | 4 +- examples/errors/errors.hash | 4 +- .../execing-processes/execing-processes.hash | 4 +- examples/exit/exit.hash | 4 +- examples/file-paths/file-paths.hash | 4 +- examples/for/for.hash | 4 +- examples/functions/functions.hash | 4 +- examples/goroutines/goroutines.hash | 4 +- examples/http-clients/http-clients.hash | 4 +- examples/http-servers/http-servers.hash | 4 +- examples/interfaces/interfaces.hash | 4 +- examples/line-filters/line-filters.hash | 4 +- examples/maps/maps.hash | 4 +- examples/methods/methods.hash | 4 +- .../multiple-return-values.hash | 4 +- examples/mutexes/mutexes.hash | 4 +- .../non-blocking-channel-operations.hash | 4 +- examples/number-parsing/number-parsing.hash | 4 +- examples/pointers/pointers.hash | 4 +- examples/random-numbers/random-numbers.hash | 4 +- .../range-over-channels.hash | 4 +- examples/range/range.hash | 4 +- examples/rate-limiting/rate-limiting.hash | 4 +- examples/reading-files/reading-files.hash | 4 +- examples/recursion/recursion.hash | 4 +- .../regular-expressions.hash | 4 +- examples/sha1-hashes/sha1-hashes.hash | 4 +- examples/signals/signals.hash | 4 +- examples/slices/slices.hash | 4 +- .../sorting-by-functions.hash | 4 +- examples/sorting/sorting.hash | 4 +- .../spawning-processes.hash | 4 +- .../stateful-goroutines.hash | 4 +- .../string-formatting/string-formatting.hash | 4 +- .../string-functions/string-functions.hash | 4 +- examples/structs/structs.hash | 4 +- .../temporary-files-and-directories.hash | 4 +- examples/testing/testing.hash | 4 +- examples/tickers/tickers.hash | 4 +- .../time-formatting-parsing.hash | 4 +- examples/time/time.hash | 4 +- examples/timeouts/timeouts.hash | 4 +- examples/timers/timers.hash | 4 +- examples/url-parsing/url-parsing.hash | 4 +- examples/values/values.hash | 4 +- examples/variables/variables.hash | 4 +- .../variadic-functions.hash | 4 +- examples/worker-pools/worker-pools.hash | 4 +- examples/writing-files/writing-files.hash | 4 +- public/404.html | 17 - public/arrays | 41 -- public/atomic-counters | 41 -- public/base64 | 41 -- public/channel-buffering | 41 -- public/channel-directions | 41 -- public/channel-synchronization | 41 -- public/channels | 41 -- public/clipboard.png | Bin 488 -> 0 bytes public/closing-channels | 41 -- public/closures | 41 -- public/collection-functions | 41 -- public/command-line-arguments | 41 -- public/command-line-flags | 41 -- public/command-line-subcommands | 41 -- public/constants | 41 -- public/defer | 220 --------- public/directories | 41 -- public/environment-variables | 41 -- public/epoch | 183 -------- public/errors | 41 -- public/execing-processes | 41 -- public/exit | 33 -- public/favicon.ico | Bin 71518 -> 0 bytes public/file-paths | 41 -- public/for | 41 -- public/functions | 41 -- public/goroutines | 41 -- public/hello-world | 142 ------ public/http | 41 -- public/if-else | 191 -------- public/index.html | 182 -------- public/interfaces | 41 -- public/json | 424 ------------------ public/line-filters | 41 -- public/maps | 41 -- public/methods | 41 -- public/multiple-return-values | 41 -- public/mutexes | 41 -- public/non-blocking-channel-operations | 41 -- public/number-parsing | 41 -- public/panic | 183 -------- public/play.png | Bin 739 -> 0 bytes public/pointers | 41 -- public/random-numbers | 41 -- public/range | 41 -- public/range-over-channels | 41 -- public/rate-limiting | 41 -- public/reading-files | 41 -- public/recursion | 41 -- public/regular-expressions | 41 -- public/select | 192 -------- public/sha1 | 41 -- public/signals | 41 -- public/site.css | 212 --------- public/site.js | 17 - public/slices | 41 -- public/sorting | 41 -- public/sorting-by-functions | 41 -- public/spawning-processes | 41 -- public/stateful-goroutines | 41 -- public/string-formatting | 41 -- public/string-functions | 41 -- public/structs | 41 -- public/switch | 209 --------- public/temporary-files-and-directories | 41 -- public/testing | 41 -- public/tickers | 41 -- public/time | 41 -- public/time-formatting-parsing | 41 -- public/timeouts | 41 -- public/timers | 41 -- public/url | 41 -- public/values | 41 -- public/variables | 41 -- public/variadic-functions | 41 -- public/waitgroups | 226 ---------- public/worker-pools | 41 -- public/writing-files | 41 -- public/xml | 288 ------------ tools/generate.go | 20 +- 146 files changed, 215 insertions(+), 5470 deletions(-) delete mode 100644 public/404.html delete mode 100644 public/arrays delete mode 100644 public/atomic-counters delete mode 100644 public/base64 delete mode 100644 public/channel-buffering delete mode 100644 public/channel-directions delete mode 100644 public/channel-synchronization delete mode 100644 public/channels delete mode 100644 public/clipboard.png delete mode 100644 public/closing-channels delete mode 100644 public/closures delete mode 100644 public/collection-functions delete mode 100644 public/command-line-arguments delete mode 100644 public/command-line-flags delete mode 100644 public/command-line-subcommands delete mode 100644 public/constants delete mode 100644 public/defer delete mode 100644 public/directories delete mode 100644 public/environment-variables delete mode 100644 public/epoch delete mode 100644 public/errors delete mode 100644 public/execing-processes delete mode 100644 public/exit delete mode 100644 public/favicon.ico delete mode 100644 public/file-paths delete mode 100644 public/for delete mode 100644 public/functions delete mode 100644 public/goroutines delete mode 100644 public/hello-world delete mode 100644 public/http delete mode 100644 public/if-else delete mode 100644 public/index.html delete mode 100644 public/interfaces delete mode 100644 public/json delete mode 100644 public/line-filters delete mode 100644 public/maps delete mode 100644 public/methods delete mode 100644 public/multiple-return-values delete mode 100644 public/mutexes delete mode 100644 public/non-blocking-channel-operations delete mode 100644 public/number-parsing delete mode 100644 public/panic delete mode 100644 public/play.png delete mode 100644 public/pointers delete mode 100644 public/random-numbers delete mode 100644 public/range delete mode 100644 public/range-over-channels delete mode 100644 public/rate-limiting delete mode 100644 public/reading-files delete mode 100644 public/recursion delete mode 100644 public/regular-expressions delete mode 100644 public/select delete mode 100644 public/sha1 delete mode 100644 public/signals delete mode 100644 public/site.css delete mode 100644 public/site.js delete mode 100644 public/slices delete mode 100644 public/sorting delete mode 100644 public/sorting-by-functions delete mode 100644 public/spawning-processes delete mode 100644 public/stateful-goroutines delete mode 100644 public/string-formatting delete mode 100644 public/string-functions delete mode 100644 public/structs delete mode 100644 public/switch delete mode 100644 public/temporary-files-and-directories delete mode 100644 public/testing delete mode 100644 public/tickers delete mode 100644 public/time delete mode 100644 public/time-formatting-parsing delete mode 100644 public/timeouts delete mode 100644 public/timers delete mode 100644 public/url delete mode 100644 public/values delete mode 100644 public/variables delete mode 100644 public/variadic-functions delete mode 100644 public/waitgroups delete mode 100644 public/worker-pools delete mode 100644 public/writing-files delete mode 100644 public/xml diff --git a/examples.txt b/examples.txt index 1ad6eca..58af207 100644 --- a/examples.txt +++ b/examples.txt @@ -1,74 +1,74 @@ -Hello World -Типы данных (Values) -Переменные (Variables) -Константы (Constants) -Цикл For -If/Else -Switch -Массивы (Arrays) -Срезы (Slices) -Карты (Maps) -Ряд (Range) -Функции (Functions) -Функции с множественным возвратом (Multiple Return Values) -Функции с переменным числом аргументов (Variadic Functions) -Замыкания (Closures) -Рекурсия (Recursion) -Указатели (Pointers) -Структуры (Structs) -Методы (Methods) -Интерфейсы (Interfaces) -Ошибки (Errors) -Горутины (Goroutines) -Каналы (Channels) -Буферизированный канал (Channel Buffering) -Синхронизация канала (Channel Synchronization) -Направления канала (Channel Directions) -Select -Тайм-ауты (Timeouts) -Неблокируемые операции в каналах (Non-Blocking Channel Operations) -Закрытие каналов (Closing Channels) -Перебор значений из каналов (Range over Channels) -Таймеры (Timers) -Тикеры (повторения) (Tickers) -Пулы воркеров (Worker Pools) -WaitGroups -Ограничение скорости (Rate Limiting) -Атомарные счетчики (Atomic Counters) -Мьютексы (Mutexes) -Управление состоянием горутин (Stateful Goroutines) -Сортировка (Sorting) -Сортировка через функции (Sorting by Functions) -Panic -Defer -Функции коллекции (Collection Functions) -Строковые функции (String Functions) -Форматирование строк (String Formatting) -Регулярные выражения (Regular Expressions) -JSON -XML -Время (Time) -Epoch -Форматирование времени (Time Formatting / Parsing) -Случайные числа (Random Numbers) -Парсинг чисел (Number Parsing) -Парсинг URL (URL Parsing) -Хеш SHA1 (SHA1 Hashes) -Кодирование Base64 (Base64 Encoding) -Чтение файлов (Reading Files) -Запись файлов (Writing Files) -Строковые фильтры (Line Filters) -Пути к файлам (File Paths) -Директории (Directories) -Временные файлы и директории (Temporary Files and Directories) -Тестирование (Testing) -Аргументы командной строки (Command-Line Arguments) -Флаги командной строки (Command-Line Flags) -Подкоманды командной строки (Command-Line Subcommands) -Переменные среды (Environment Variables) -HTTP клиенты (HTTP Clients) -HTTP серверы (HTTP Servers) -Порождающие процессы (Spawning Processes) -Исполняющие процессы (Exec'ing Processes) -Сигналы (Signals) -Выход (Exit) +Hello World|Hello World +Типы данных (Values)|Values +Переменные (Variables)|Variables +Константы (Constants)|Constants +Цикл For|For +If/Else|If/Else +Switch|Switch +Массивы (Arrays)|Arrays +Срезы (Slices)|Slices +Карты (Maps)|Maps +Ряд (Range)|Range +Функции (Functions)|Functions +Функции с множественным возвратом (Multiple Return Values)|Multiple Return Values +Функции с переменным числом аргументов (Variadic Functions)|Variadic Functions +Замыкания (Closures)|Closures +Рекурсия (Recursion)|Recursion +Указатели (Pointers)|Pointers +Структуры (Structs)|Structs +Методы (Methods)|Methods +Интерфейсы (Interfaces)|Interfaces +Ошибки (Errors)|Errors +Горутины (Goroutines)|Goroutines +Каналы (Channels)|Channels +Буферизированный канал (Channel Buffering)|Channel Buffering +Синхронизация канала (Channel Synchronization)|Channel Synchronization +Направления канала (Channel Directions)|Channel Directions +Select|Select +Тайм-ауты (Timeouts)|Timeouts +Неблокируемые операции в каналах (Non-Blocking Channel Operations)|Non-Blocking Channel Operations +Закрытие каналов (Closing Channels)|Closing Channels +Перебор значений из каналов (Range over Channels)|Range over Channels +Таймеры (Timers)|Timers +Тикеры (повторения) (Tickers)|Tickers +Пулы воркеров (Worker Pools)|Worker Pools +WaitGroups|WaitGroups +Ограничение скорости (Rate Limiting)|Rate Limiting +Атомарные счетчики (Atomic Counters)|Atomic Counters +Мьютексы (Mutexes)|Mutexes +Управление состоянием горутин (Stateful Goroutines)|Stateful Goroutines +Сортировка (Sorting)|Sorting +Сортировка через функции (Sorting by Functions)|Sorting by Functions +Panic|Panic +Defer|Defer +Функции коллекции (Collection Functions)|Collection Functions +Строковые функции (String Functions)|String Functions +Форматирование строк (String Formatting)|String Formatting +Регулярные выражения (Regular Expressions)|Regular Expressions +JSON|JSON +XML|XML +Время (Time)|Time +Epoch|Epoch +Форматирование времени (Time Formatting / Parsing)|Time Formatting / Parsing +Случайные числа (Random Numbers)|Random Numbers +Парсинг чисел (Number Parsing)|Number Parsing +Парсинг URL (URL Parsing)|URL Parsing +Хеш SHA1 (SHA1 Hashes)|SHA1 Hashes +Кодирование Base64 (Base64 Encoding)|Base64 Encoding +Чтение файлов (Reading Files)|Reading Files +Запись файлов (Writing Files)|Writing Files +Строковые фильтры (Line Filters)|Line Filters +Пути к файлам (File Paths)|File Paths +Директории (Directories)|Directories +Временные файлы и директории (Temporary Files and Directories)|Temporary Files and Directories +Тестирование (Testing)|Testing +Аргументы командной строки (Command-Line Arguments)|Command-Line Arguments +Флаги командной строки (Command-Line Flags)|Command-Line Flags +Подкоманды командной строки (Command-Line Subcommands)|Command-Line Subcommands +Переменные среды (Environment Variables)|Environment Variables +HTTP клиенты (HTTP Clients)|HTTP Clients +HTTP серверы (HTTP Servers)|HTTP Servers +Порождающие процессы (Spawning Processes)|Spawning Processes +Исполняющие процессы (Exec'ing Processes)|Exec'ing Processes +Сигналы (Signals)|Signals +Выход (Exit)|Exit diff --git a/examples/arrays/arrays.hash b/examples/arrays/arrays.hash index 8ab57f4..ad69e96 100644 --- a/examples/arrays/arrays.hash +++ b/examples/arrays/arrays.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +cbd7ae7158cdb62fbd0f5a21c1f89a9a43369900 +CiZ6oDF6A_l diff --git a/examples/atomic-counters/atomic-counters.hash b/examples/atomic-counters/atomic-counters.hash index 8ab57f4..d8d3864 100644 --- a/examples/atomic-counters/atomic-counters.hash +++ b/examples/atomic-counters/atomic-counters.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e1b3a73458ef10d4cfe093766d05503ed7706544 +aEOYD0chCYy diff --git a/examples/base64-encoding/base64-encoding.hash b/examples/base64-encoding/base64-encoding.hash index 717ff3f..b5f4766 100644 --- a/examples/base64-encoding/base64-encoding.hash +++ b/examples/base64-encoding/base64-encoding.hash @@ -1,2 +1,2 @@ -e0148b9b4acb01e849b8f678cba03f549d250c44 -V3oV1bvh94k +0a1abdfdd647b24082d46fd54645bc597fb86b83 +3E068RAuW3p diff --git a/examples/channel-buffering/channel-buffering.hash b/examples/channel-buffering/channel-buffering.hash index 8ab57f4..b8c3cbb 100644 --- a/examples/channel-buffering/channel-buffering.hash +++ b/examples/channel-buffering/channel-buffering.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +4d4cf7b115f26c12d7e188a2d25c66e64f34edfe +HNVSsVpnHXN diff --git a/examples/channel-directions/channel-directions.hash b/examples/channel-directions/channel-directions.hash index 8ab57f4..700e311 100644 --- a/examples/channel-directions/channel-directions.hash +++ b/examples/channel-directions/channel-directions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +a0904bf943d61e4d220f29ef3a0e6f1368657e78 +uEeOmen99CF diff --git a/examples/channel-synchronization/channel-synchronization.hash b/examples/channel-synchronization/channel-synchronization.hash index 8ab57f4..16fea5e 100644 --- a/examples/channel-synchronization/channel-synchronization.hash +++ b/examples/channel-synchronization/channel-synchronization.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +29e4099160217bd2817aef8546927056b9ea4b12 +3NHqwE7Bwjz diff --git a/examples/channels/channels.hash b/examples/channels/channels.hash index 8ab57f4..eac8a35 100644 --- a/examples/channels/channels.hash +++ b/examples/channels/channels.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +92a2a89118f08e7ac1fcf82567c14a31e6a2fabe +jHsjIHrpHXV diff --git a/examples/closing-channels/closing-channels.hash b/examples/closing-channels/closing-channels.hash index 8ab57f4..16da6f6 100644 --- a/examples/closing-channels/closing-channels.hash +++ b/examples/closing-channels/closing-channels.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +67493a491669c559ceac851a959828a00ceb89eb +V8RCD4w9KY- diff --git a/examples/closures/closures.hash b/examples/closures/closures.hash index 8ab57f4..104a80b 100644 --- a/examples/closures/closures.hash +++ b/examples/closures/closures.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +5a274ea5c01af8573ce5c6382f41189446a8be09 +J2PladF_bU9 diff --git a/examples/collection-functions/collection-functions.hash b/examples/collection-functions/collection-functions.hash index 8ab57f4..49e6fd6 100644 --- a/examples/collection-functions/collection-functions.hash +++ b/examples/collection-functions/collection-functions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +5e8a32a022ffb4f746bbdf101face52ca008aeba +urAoHQtRHro diff --git a/examples/command-line-arguments/command-line-arguments.hash b/examples/command-line-arguments/command-line-arguments.hash index 8ab57f4..b81990d 100644 --- a/examples/command-line-arguments/command-line-arguments.hash +++ b/examples/command-line-arguments/command-line-arguments.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +375f50de2467743174f0d60d0635a3198e031094 +wSDrVn9TIK5 diff --git a/examples/command-line-flags/command-line-flags.hash b/examples/command-line-flags/command-line-flags.hash index 8ab57f4..2262d76 100644 --- a/examples/command-line-flags/command-line-flags.hash +++ b/examples/command-line-flags/command-line-flags.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e316c57acf4cc993f182f2d341a608a1eac4a551 +_r_-ZzDzQUH diff --git a/examples/command-line-subcommands/command-line-subcommands.hash b/examples/command-line-subcommands/command-line-subcommands.hash index 8ab57f4..f695b3c 100644 --- a/examples/command-line-subcommands/command-line-subcommands.hash +++ b/examples/command-line-subcommands/command-line-subcommands.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +7320b5803ad9875733c4ca9644600ae8a55009d8 +sr1FH0P_2Te diff --git a/examples/constants/constants.hash b/examples/constants/constants.hash index 8ab57f4..9cb2151 100644 --- a/examples/constants/constants.hash +++ b/examples/constants/constants.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +31b56e63896203b29fd3a08a1f5036ca62d6d0c2 +e1Vlh7LNMFJ diff --git a/examples/directories/directories.hash b/examples/directories/directories.hash index 8ab57f4..fa8c641 100644 --- a/examples/directories/directories.hash +++ b/examples/directories/directories.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +7df99bb0443cbe61600e6466782a66e76cf7d927 +6lC_YCFEXVl diff --git a/examples/environment-variables/environment-variables.hash b/examples/environment-variables/environment-variables.hash index 8ab57f4..3177ea5 100644 --- a/examples/environment-variables/environment-variables.hash +++ b/examples/environment-variables/environment-variables.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +61c3cd2ec3ab8fcd4528452e88fe25c0eafbb2de +--fC2aTdXEz diff --git a/examples/errors/errors.hash b/examples/errors/errors.hash index 8ab57f4..7c79ad8 100644 --- a/examples/errors/errors.hash +++ b/examples/errors/errors.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +91979262128065a70899eb9ee32da1549864b609 +9-iENtmoI5k diff --git a/examples/execing-processes/execing-processes.hash b/examples/execing-processes/execing-processes.hash index 8ab57f4..d0dcce3 100644 --- a/examples/execing-processes/execing-processes.hash +++ b/examples/execing-processes/execing-processes.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +878cb29aa644aef60217a2d97a586080cd783daa +dojmebwCvC4 diff --git a/examples/exit/exit.hash b/examples/exit/exit.hash index 8ab57f4..af49b62 100644 --- a/examples/exit/exit.hash +++ b/examples/exit/exit.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +450a55230493ea17b3b7aeef666f55f796c050a8 +BgQ_ag62q4k diff --git a/examples/file-paths/file-paths.hash b/examples/file-paths/file-paths.hash index 8ab57f4..fd63161 100644 --- a/examples/file-paths/file-paths.hash +++ b/examples/file-paths/file-paths.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +7bbdffb4411e01e9962593d1de16a5654fb780d4 +6VDVplbM_Sk diff --git a/examples/for/for.hash b/examples/for/for.hash index 8ab57f4..ff069d6 100644 --- a/examples/for/for.hash +++ b/examples/for/for.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +c478d7d6259b800c42307c0d520fb669109cb2f7 +Fv7uI0y_EWr diff --git a/examples/functions/functions.hash b/examples/functions/functions.hash index 8ab57f4..742cfe2 100644 --- a/examples/functions/functions.hash +++ b/examples/functions/functions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +fe343c61ebf68660290e3717592e7904c47abad5 +4sH5Tv_SBoU diff --git a/examples/goroutines/goroutines.hash b/examples/goroutines/goroutines.hash index 8ab57f4..ab46c61 100644 --- a/examples/goroutines/goroutines.hash +++ b/examples/goroutines/goroutines.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +9de125c9da86967491563075071ccd110b95b8ef +79i2V9dLU15 diff --git a/examples/http-clients/http-clients.hash b/examples/http-clients/http-clients.hash index e550dd5..8f7dd6a 100644 --- a/examples/http-clients/http-clients.hash +++ b/examples/http-clients/http-clients.hash @@ -1,2 +1,2 @@ -ec8fd69aa19e54a7ea05d2a911f09d3a98f0396c -VxYIifr_UuH +4efc6eb143a0e04132f16fcf929f7eed232b897d +8Z80D4rlbaE diff --git a/examples/http-servers/http-servers.hash b/examples/http-servers/http-servers.hash index a491ac1..553440b 100644 --- a/examples/http-servers/http-servers.hash +++ b/examples/http-servers/http-servers.hash @@ -1,2 +1,2 @@ -a4e8d30b7a6f3a6abd96b916d81ce5930bad94f9 -lNuS9ysZmxH +0282a23b343fbbbf9e3cb32d1efd934c9d707d26 +xndCIK5Wo-Y diff --git a/examples/interfaces/interfaces.hash b/examples/interfaces/interfaces.hash index 8ab57f4..e0bd9e8 100644 --- a/examples/interfaces/interfaces.hash +++ b/examples/interfaces/interfaces.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e09278982d7d148dd22c45730d0820659a7ecae8 +bS2bkTzP8cG diff --git a/examples/line-filters/line-filters.hash b/examples/line-filters/line-filters.hash index 8ab57f4..298af0b 100644 --- a/examples/line-filters/line-filters.hash +++ b/examples/line-filters/line-filters.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +92a88a19fb7453935093e2ae893fcef18432f596 +dLiHA3PDCFp diff --git a/examples/maps/maps.hash b/examples/maps/maps.hash index 8ab57f4..3f261eb 100644 --- a/examples/maps/maps.hash +++ b/examples/maps/maps.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +df6205e7069d3914f2a40940696755f4b6343a9b +HjBZNUEcF_e diff --git a/examples/methods/methods.hash b/examples/methods/methods.hash index 8ab57f4..37ab1b3 100644 --- a/examples/methods/methods.hash +++ b/examples/methods/methods.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +b3128d2e4d2238e56d99bfc7138389257076871f +qfALObNYETK diff --git a/examples/multiple-return-values/multiple-return-values.hash b/examples/multiple-return-values/multiple-return-values.hash index 8ab57f4..9a8cf5c 100644 --- a/examples/multiple-return-values/multiple-return-values.hash +++ b/examples/multiple-return-values/multiple-return-values.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +9cfe1eb1a10a8977bee1581389953af18afc9bc0 +6Khmls9Dsin diff --git a/examples/mutexes/mutexes.hash b/examples/mutexes/mutexes.hash index 8ab57f4..501066e 100644 --- a/examples/mutexes/mutexes.hash +++ b/examples/mutexes/mutexes.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +8c7db363d911ef04d1340ff195da03a5373b79ab +USO1aTX_xMe diff --git a/examples/non-blocking-channel-operations/non-blocking-channel-operations.hash b/examples/non-blocking-channel-operations/non-blocking-channel-operations.hash index 8ab57f4..70fa503 100644 --- a/examples/non-blocking-channel-operations/non-blocking-channel-operations.hash +++ b/examples/non-blocking-channel-operations/non-blocking-channel-operations.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +3b01f109970c31ffb1c67cfea86a8eaa2959f7e0 +FokCtF5TvgL diff --git a/examples/number-parsing/number-parsing.hash b/examples/number-parsing/number-parsing.hash index 8ab57f4..40ced04 100644 --- a/examples/number-parsing/number-parsing.hash +++ b/examples/number-parsing/number-parsing.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +9b4a9b30f02201adf86ab6c6abc60e23088026be +4PKUrIjNyTE diff --git a/examples/pointers/pointers.hash b/examples/pointers/pointers.hash index 8ab57f4..69d7ef2 100644 --- a/examples/pointers/pointers.hash +++ b/examples/pointers/pointers.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +909a2f7a79ef942a544292b283a964ae530fd612 +VHnMkOQfQea diff --git a/examples/random-numbers/random-numbers.hash b/examples/random-numbers/random-numbers.hash index 8ab57f4..acd1836 100644 --- a/examples/random-numbers/random-numbers.hash +++ b/examples/random-numbers/random-numbers.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +03975452ff4c127a4a78897643ce3eca0b90b239 +CKeOTktHnJe diff --git a/examples/range-over-channels/range-over-channels.hash b/examples/range-over-channels/range-over-channels.hash index 8ab57f4..0200e30 100644 --- a/examples/range-over-channels/range-over-channels.hash +++ b/examples/range-over-channels/range-over-channels.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +a2f106b835828ac784feffb869604e059d788680 +zbl7ytLnFCK diff --git a/examples/range/range.hash b/examples/range/range.hash index 8ab57f4..a1df701 100644 --- a/examples/range/range.hash +++ b/examples/range/range.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +f8c6ffeaa1f52aeff136779442bbd160313a6b32 +4GBukIe-7ie diff --git a/examples/rate-limiting/rate-limiting.hash b/examples/rate-limiting/rate-limiting.hash index 8ab57f4..19e0c2c 100644 --- a/examples/rate-limiting/rate-limiting.hash +++ b/examples/rate-limiting/rate-limiting.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +a93813bfc920c685c55bf09a3425f63fcc4a542b +rC0qLhImKAo diff --git a/examples/reading-files/reading-files.hash b/examples/reading-files/reading-files.hash index 8ab57f4..24886b8 100644 --- a/examples/reading-files/reading-files.hash +++ b/examples/reading-files/reading-files.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +176b57caf5a053e3707da299ca9fbb78314d283f +m6mvXlZtHTX diff --git a/examples/recursion/recursion.hash b/examples/recursion/recursion.hash index 8ab57f4..26a2e36 100644 --- a/examples/recursion/recursion.hash +++ b/examples/recursion/recursion.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +b75f7597af0526d0fefb481ef7987b5e186c0c04 +oPbHEHLaRrN diff --git a/examples/regular-expressions/regular-expressions.hash b/examples/regular-expressions/regular-expressions.hash index 8ab57f4..fbd8efc 100644 --- a/examples/regular-expressions/regular-expressions.hash +++ b/examples/regular-expressions/regular-expressions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +984c5939e46284833637df8aa8dd38f51b571425 +GB_bgVcRKg2 diff --git a/examples/sha1-hashes/sha1-hashes.hash b/examples/sha1-hashes/sha1-hashes.hash index 5af2939..b69d352 100644 --- a/examples/sha1-hashes/sha1-hashes.hash +++ b/examples/sha1-hashes/sha1-hashes.hash @@ -1,2 +1,2 @@ -4cda643ba233014fe6b30966c37d4d0fcd4edbe8 -oqcrTfY4Ykd +f64d96d9e998d1c8821689af70580b3929a464cf +zhhfA6LqgFI diff --git a/examples/signals/signals.hash b/examples/signals/signals.hash index 8ab57f4..02bac3b 100644 --- a/examples/signals/signals.hash +++ b/examples/signals/signals.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +8e3867a11504ce30880c75e3d5ed74907a8ef1b5 +Xs9zJ53YIAa diff --git a/examples/slices/slices.hash b/examples/slices/slices.hash index 8ab57f4..a4ad5e8 100644 --- a/examples/slices/slices.hash +++ b/examples/slices/slices.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +97236c6deebee661d0bd1e696b12e4ea671d06ff +32lRsL-MYrP diff --git a/examples/sorting-by-functions/sorting-by-functions.hash b/examples/sorting-by-functions/sorting-by-functions.hash index 8ab57f4..374e267 100644 --- a/examples/sorting-by-functions/sorting-by-functions.hash +++ b/examples/sorting-by-functions/sorting-by-functions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +0252f365e73e310a8f4dc4431f598ffcea3efc72 +VQrgvKKcvRg diff --git a/examples/sorting/sorting.hash b/examples/sorting/sorting.hash index 8ab57f4..c28118f 100644 --- a/examples/sorting/sorting.hash +++ b/examples/sorting/sorting.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +a059f86c91ed4084fb37f321a7def4ef88b62e67 +X9bT-mDzj4o diff --git a/examples/spawning-processes/spawning-processes.hash b/examples/spawning-processes/spawning-processes.hash index 8ab57f4..2ccab24 100644 --- a/examples/spawning-processes/spawning-processes.hash +++ b/examples/spawning-processes/spawning-processes.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +4984e90d62323e378c35e5c52d0c5646fd150d82 +2QNUQPuiFlR diff --git a/examples/stateful-goroutines/stateful-goroutines.hash b/examples/stateful-goroutines/stateful-goroutines.hash index 8ab57f4..bb70ee5 100644 --- a/examples/stateful-goroutines/stateful-goroutines.hash +++ b/examples/stateful-goroutines/stateful-goroutines.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e7e07404454809cbacb719ad94e70726d22dacc1 +n_gVZus4DBP diff --git a/examples/string-formatting/string-formatting.hash b/examples/string-formatting/string-formatting.hash index 8ab57f4..a8fe8ea 100644 --- a/examples/string-formatting/string-formatting.hash +++ b/examples/string-formatting/string-formatting.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +8ffedfce40621f09c42f07459127279d66425d08 +TKe8eifne_2 diff --git a/examples/string-functions/string-functions.hash b/examples/string-functions/string-functions.hash index 8ab57f4..e720ebb 100644 --- a/examples/string-functions/string-functions.hash +++ b/examples/string-functions/string-functions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +818faf1a5caccb1628010427eff861edd8379de8 +UeDwSoYepQt diff --git a/examples/structs/structs.hash b/examples/structs/structs.hash index 8ab57f4..f0189fa 100644 --- a/examples/structs/structs.hash +++ b/examples/structs/structs.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +995a3c5dec1de68fe79d5d3172531fb5d2b99870 +sJZCI3Gm3Ht diff --git a/examples/temporary-files-and-directories/temporary-files-and-directories.hash b/examples/temporary-files-and-directories/temporary-files-and-directories.hash index 8ab57f4..e68654d 100644 --- a/examples/temporary-files-and-directories/temporary-files-and-directories.hash +++ b/examples/temporary-files-and-directories/temporary-files-and-directories.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +99866fef55916b593bf73df9591ca9d7d2c86d7e +PMJP7pf-n5h diff --git a/examples/testing/testing.hash b/examples/testing/testing.hash index 8ab57f4..3f809e1 100644 --- a/examples/testing/testing.hash +++ b/examples/testing/testing.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +1a41d8c725f8bfe62838744d6327404ec1ddc319 +gZXCCqO7ezT diff --git a/examples/tickers/tickers.hash b/examples/tickers/tickers.hash index 8ab57f4..b4fefad 100644 --- a/examples/tickers/tickers.hash +++ b/examples/tickers/tickers.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +64772226ab38092e29f23802c8138a723e23cc83 +2bpsxisGGLj diff --git a/examples/time-formatting-parsing/time-formatting-parsing.hash b/examples/time-formatting-parsing/time-formatting-parsing.hash index 8ab57f4..892e30e 100644 --- a/examples/time-formatting-parsing/time-formatting-parsing.hash +++ b/examples/time-formatting-parsing/time-formatting-parsing.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +7a8299db21f9554a2b43ecece2d8abf7a370189c +G61ruGfMQZA diff --git a/examples/time/time.hash b/examples/time/time.hash index 8ab57f4..15db181 100644 --- a/examples/time/time.hash +++ b/examples/time/time.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e532cf20c51b0106aba8c041ec44480f7690da5e +ZE4n1Jt55m0 diff --git a/examples/timeouts/timeouts.hash b/examples/timeouts/timeouts.hash index 8ab57f4..91d44dc 100644 --- a/examples/timeouts/timeouts.hash +++ b/examples/timeouts/timeouts.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +441dc07d57c03df070488f85dbe24e5ef6591bf7 +SCMyPsGlXtX diff --git a/examples/timers/timers.hash b/examples/timers/timers.hash index 8ab57f4..87c1ff7 100644 --- a/examples/timers/timers.hash +++ b/examples/timers/timers.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +d1689f059a29e7e0d3f9ccd52632220d487d6ca0 +7RnBhz_kuki diff --git a/examples/url-parsing/url-parsing.hash b/examples/url-parsing/url-parsing.hash index 77021f1..28c5bcd 100644 --- a/examples/url-parsing/url-parsing.hash +++ b/examples/url-parsing/url-parsing.hash @@ -1,2 +1,2 @@ -babc12f5066652f4cb0151231c06f1037298ff28 -M218D9Tldlr +f0b0a50b3471f972b26e6fefb481730661aac6e1 +Zt1KHMGZESo diff --git a/examples/values/values.hash b/examples/values/values.hash index 8ab57f4..3716621 100644 --- a/examples/values/values.hash +++ b/examples/values/values.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +1c4cf252844f42861e8fbc59a604833d0dbd24c0 +SYLIv-rApFj diff --git a/examples/variables/variables.hash b/examples/variables/variables.hash index 8ab57f4..76bfeee 100644 --- a/examples/variables/variables.hash +++ b/examples/variables/variables.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e5f981f078207ac4f67b26be87a73c2989006685 +BUbDhWP8PV_k diff --git a/examples/variadic-functions/variadic-functions.hash b/examples/variadic-functions/variadic-functions.hash index 8ab57f4..46c87a0 100644 --- a/examples/variadic-functions/variadic-functions.hash +++ b/examples/variadic-functions/variadic-functions.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +e32d27f8b78c3e3f24c5dd98f864ffdb9567d628 +dz6tVXvffuH diff --git a/examples/worker-pools/worker-pools.hash b/examples/worker-pools/worker-pools.hash index 8ab57f4..fc92632 100644 --- a/examples/worker-pools/worker-pools.hash +++ b/examples/worker-pools/worker-pools.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +a719d863a0b07434beade5c6582eff76df8bd2ef +79qTVPHnwGQ diff --git a/examples/writing-files/writing-files.hash b/examples/writing-files/writing-files.hash index 8ab57f4..89cec11 100644 --- a/examples/writing-files/writing-files.hash +++ b/examples/writing-files/writing-files.hash @@ -1,2 +1,2 @@ -da39a3ee5e6b4b0d3255bfef95601890afd80709 -UCPdVNrl0-P +f6c74f9903720805417ffe5765cef04e3f58d966 +LscGbwmQZns diff --git a/public/404.html b/public/404.html deleted file mode 100644 index e2a089e..0000000 --- a/public/404.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Go by Example: Not Found - - - -
-

Go by Example

-

Sorry, we couldn't find that! Check out the home page?

- -
- - diff --git a/public/arrays b/public/arrays deleted file mode 100644 index d19bf1c..0000000 --- a/public/arrays +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Массивы (Arrays) - - - - -
-

Go в примерах: Массивы (Arrays)

- - -

- Следующий пример: Срезы (Slices). -

- - -
- - - - diff --git a/public/atomic-counters b/public/atomic-counters deleted file mode 100644 index e073b4b..0000000 --- a/public/atomic-counters +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Атомарные счетчики (Atomic Counters) - - - - -
-

Go в примерах: Атомарные счетчики (Atomic Counters)

- - -

- Следующий пример: Мьютексы (Mutexes). -

- - -
- - - - diff --git a/public/base64 b/public/base64 deleted file mode 100644 index eadbd1c..0000000 --- a/public/base64 +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Кодирование Base64 (Base64 Encoding) - - - - -
-

Go в примерах: Кодирование Base64 (Base64 Encoding)

- - -

- Следующий пример: Чтение файлов (Reading Files). -

- - -
- - - - diff --git a/public/channel-buffering b/public/channel-buffering deleted file mode 100644 index 36fd138..0000000 --- a/public/channel-buffering +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Буферизированный канал (Channel Buffering) - - - - -
-

Go в примерах: Буферизированный канал (Channel Buffering)

- - -

- Следующий пример: Синхронизация канала (Channel Synchronization). -

- - -
- - - - diff --git a/public/channel-directions b/public/channel-directions deleted file mode 100644 index f50b677..0000000 --- a/public/channel-directions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Направления канала (Channel Directions) - - - - -
-

Go в примерах: Направления канала (Channel Directions)

- - -

- Следующий пример: Select. -

- - -
- - - - diff --git a/public/channel-synchronization b/public/channel-synchronization deleted file mode 100644 index b421afc..0000000 --- a/public/channel-synchronization +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Синхронизация канала (Channel Synchronization) - - - - -
-

Go в примерах: Синхронизация канала (Channel Synchronization)

- - -

- Следующий пример: Направления канала (Channel Directions). -

- - -
- - - - diff --git a/public/channels b/public/channels deleted file mode 100644 index 9711b17..0000000 --- a/public/channels +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Каналы (Channels) - - - - -
-

Go в примерах: Каналы (Channels)

- - -

- Следующий пример: Буферизированный канал (Channel Buffering). -

- - -
- - - - diff --git a/public/clipboard.png b/public/clipboard.png deleted file mode 100644 index 0e262fec70a6efb70c8c03c67e4cfea0b230d5ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 488 zcmVP)vs0+u6@oUjF!il?f%*EGIz@kHuY0Jz-x!^TP`0I+j#4M3yOun`C$0GLY;0}N!> z@?HR!^uMdY?T0(;4FS(8K`+4e{$(p$r=i9GO#pFzR`vm!Q+6ka*jT(SNo?u|Lt!d6 zSGM3_C`@*F72plf0fhAVfD0h{U)v;(fF70L6Q}@Ds{#v|#T@yq_0~Ezo&p%OgcqtH ze?6R7A=SQhZwYS^XuznG2EkC6sp+&;0f49d3Xi}@mm2i7x*%siPzKUY8ptjfQgpvc zU|4PGLW39J38<u`lTp#J+Cizm8Ecyw8bkh1}(e_fNd33!{0 eZzG - - - - Go в примерах: Закрытие каналов (Closing Channels) - - - - -
-

Go в примерах: Закрытие каналов (Closing Channels)

- - -

- Следующий пример: Перебор значений из каналов (Range over Channels). -

- - -
- - - - diff --git a/public/closures b/public/closures deleted file mode 100644 index 1d3cbc4..0000000 --- a/public/closures +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Замыкания (Closures) - - - - -
-

Go в примерах: Замыкания (Closures)

- - -

- Следующий пример: Рекурсия (Recursion). -

- - -
- - - - diff --git a/public/collection-functions b/public/collection-functions deleted file mode 100644 index 9efcde8..0000000 --- a/public/collection-functions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Функции коллекции (Collection Functions) - - - - -
-

Go в примерах: Функции коллекции (Collection Functions)

- - -

- Следующий пример: Строковые функции (String Functions). -

- - -
- - - - diff --git a/public/command-line-arguments b/public/command-line-arguments deleted file mode 100644 index d3857df..0000000 --- a/public/command-line-arguments +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Аргументы командной строки (Command-Line Arguments) - - - - -
-

Go в примерах: Аргументы командной строки (Command-Line Arguments)

- - -

- Следующий пример: Флаги командной строки (Command-Line Flags). -

- - -
- - - - diff --git a/public/command-line-flags b/public/command-line-flags deleted file mode 100644 index 97d6350..0000000 --- a/public/command-line-flags +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Флаги командной строки (Command-Line Flags) - - - - -
-

Go в примерах: Флаги командной строки (Command-Line Flags)

- - -

- Следующий пример: Подкоманды командной строки (Command-Line Subcommands). -

- - -
- - - - diff --git a/public/command-line-subcommands b/public/command-line-subcommands deleted file mode 100644 index f90fce7..0000000 --- a/public/command-line-subcommands +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Подкоманды командной строки (Command-Line Subcommands) - - - - -
-

Go в примерах: Подкоманды командной строки (Command-Line Subcommands)

- - -

- Следующий пример: Переменные среды (Environment Variables). -

- - -
- - - - diff --git a/public/constants b/public/constants deleted file mode 100644 index bc51abe..0000000 --- a/public/constants +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Константы (Constants) - - - - -
-

Go в примерах: Константы (Constants)

- - -

- Следующий пример: Цикл For. -

- - -
- - - - diff --git a/public/defer b/public/defer deleted file mode 100644 index 2beb109..0000000 --- a/public/defer +++ /dev/null @@ -1,220 +0,0 @@ - - - - - Go в примерах: Defer - - - - -
-

Go в примерах: Defer

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

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

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "fmt"
-    "os"
-)
-
- -
-

Предположим, мы хотим создать файл, записать в него, -а затем закрыть, когда закончим. Вот как нам поможет -defer.

- -
- -
func main() {
-
- -
-

Сразу же после получения объекта файла с помощью -createFile мы откладываем закрытие этого файла -с помощью closeFile. Она будет выполнена в -конце включающей функции (main) после завершения -writeFile.

- -
- -
    f := createFile("/tmp/defer.txt")
-    defer closeFile(f)
-    writeFile(f)
-}
-
- -
- - - -
func createFile(p string) *os.File {
-    fmt.Println("creating")
-    f, err := os.Create(p)
-    if err != nil {
-        panic(err)
-    }
-    return f
-}
-
- -
- - - -
func writeFile(f *os.File) {
-    fmt.Println("writing")
-    fmt.Fprintln(f, "data")
-
- -
- - - -
}
-
- -
-

Важно проверять наличие ошибок при закрытии файла, -даже в отложенной функции.

- -
- -
func closeFile(f *os.File) {
-    fmt.Println("closing")
-    err := f.Close()
-
- -
- - - -
    if err != nil {
-        fmt.Fprintf(os.Stderr, "error: %v\n", err)
-        os.Exit(1)
-    }
-}
-
- -
- - - - - - - - -
-

Запуск программы подтверждает, что файл закрыт -после записи.

- -
- -
$ go run defer.go
-creating
-writing
-closing
-
- -
- - -

- Следующий пример: Функции коллекции (Collection Functions). -

- - -
- - - - diff --git a/public/directories b/public/directories deleted file mode 100644 index 2dd5c88..0000000 --- a/public/directories +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Директории (Directories) - - - - -
-

Go в примерах: Директории (Directories)

- - -

- Следующий пример: Временные файлы и директории (Temporary Files and Directories). -

- - -
- - - - diff --git a/public/environment-variables b/public/environment-variables deleted file mode 100644 index c08bf0e..0000000 --- a/public/environment-variables +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Переменные среды (Environment Variables) - - - - -
-

Go в примерах: Переменные среды (Environment Variables)

- - -

- Следующий пример: HTTP клиенты (HTTP Clients). -

- - -
- - - - diff --git a/public/epoch b/public/epoch deleted file mode 100644 index ddd321a..0000000 --- a/public/epoch +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Go в примерах: Epoch - - - - -
-

Go в примерах: Epoch

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

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

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "fmt"
-    "time"
-)
-
- -
- - - -
func main() {
-
- -
-

Используйте time.Now с Unix или UnixNano, -чтобы получить время, прошедшее с начала эпохи Unix в -секундах или наносекундах соответственно.

- -
- -
    now := time.Now()
-    secs := now.Unix()
-    nanos := now.UnixNano()
-    fmt.Println(now)
-
- -
-

Обратите внимание, что UnixMillis не существует, -поэтому, чтобы получить миллисекунды с начала эпохи Unix, -вам нужно будет вручную делить наносекунды.

- -
- -
    millis := nanos / 1000000
-    fmt.Println(secs)
-    fmt.Println(millis)
-    fmt.Println(nanos)
-
- -
-

Вы также можете конвертировать целые секунды или наносекунды -Unixtime в соответствующее время.

- -
- -
    fmt.Println(time.Unix(secs, 0))
-    fmt.Println(time.Unix(0, nanos))
-}
-
- -
- - - - - - - - - - - - - -
- - - -
$ go run epoch.go 
-2012-10-31 16:13:58.292387 +0000 UTC
-1351700038
-1351700038292
-1351700038292387000
-2012-10-31 16:13:58 +0000 UTC
-2012-10-31 16:13:58.292387 +0000 UTC
-
- -
-

Далее мы рассмотрим еще одну задачу, связанную со -временем: разбор и форматирование времени.

- -
- - -
- - -

- Следующий пример: Форматирование времени (Time Formatting / Parsing). -

- - -
- - - - diff --git a/public/errors b/public/errors deleted file mode 100644 index d276119..0000000 --- a/public/errors +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Ошибки (Errors) - - - - -
-

Go в примерах: Ошибки (Errors)

- - -

- Следующий пример: Горутины (Goroutines). -

- - -
- - - - diff --git a/public/execing-processes b/public/execing-processes deleted file mode 100644 index e0cc10d..0000000 --- a/public/execing-processes +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Исполняющие процессы (Exec'ing Processes) - - - - -
-

Go в примерах: Исполняющие процессы (Exec'ing Processes)

- - -

- Следующий пример: Сигналы (Signals). -

- - -
- - - - diff --git a/public/exit b/public/exit deleted file mode 100644 index 50c7fbe..0000000 --- a/public/exit +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Go в примерах: Выход (Exit) - - - - -
-

Go в примерах: Выход (Exit)

- - - -
- - - - diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index efa34a3abf06e01ed3456933419b0560cad9fc56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71518 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 - - - - Go в примерах: Пути к файлам (File Paths) - - - - -
-

Go в примерах: Пути к файлам (File Paths)

- - -

- Следующий пример: Директории (Directories). -

- - -
- - - - diff --git a/public/for b/public/for deleted file mode 100644 index de2ea5f..0000000 --- a/public/for +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Цикл For - - - - -
-

Go в примерах: Цикл For

- - -

- Следующий пример: If/Else. -

- - -
- - - - diff --git a/public/functions b/public/functions deleted file mode 100644 index ef4f0db..0000000 --- a/public/functions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Функции (Functions) - - - - -
-

Go в примерах: Функции (Functions)

- - -

- Следующий пример: Функции с множественным возвратом (Multiple Return Values). -

- - -
- - - - diff --git a/public/goroutines b/public/goroutines deleted file mode 100644 index dfcbc2d..0000000 --- a/public/goroutines +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Горутины (Goroutines) - - - - -
-

Go в примерах: Горутины (Goroutines)

- - -

- Следующий пример: Каналы (Channels). -

- - -
- - - - diff --git a/public/hello-world b/public/hello-world deleted file mode 100644 index 67c1c82..0000000 --- a/public/hello-world +++ /dev/null @@ -1,142 +0,0 @@ - - - - - Go в примерах: Hello World - - - - -
-

Go в примерах: Hello World

- - - - - - - - - - - - - - - - - - -
-

Наша первая программа напечатает классическое сообщение “hello world” -Полный код.

- -
- -
package main
-
- -
- - - -
import "fmt"
-
- -
- - - -
func main() {
-    fmt.Println("hello world")
-}
-
- -
- - - - - - - - - - - - - - - - - - - - - - - -
-

To run the program, put the code in hello-world.go and -use go run.

- -
- -
$ go run hello-world.go
-hello world
-
- -
-

Sometimes we’ll want to build our programs into -binaries. We can do this using go build.

- -
- -
$ go build hello-world.go
-$ ls
-hello-world    hello-world.go
-
- -
-

We can then execute the built binary directly.

- -
- -
$ ./hello-world
-hello world
-
- -
-

Now that we can run and build basic Go programs, let’s -learn more about the language.

- -
- - -
- - -

- Следующий пример: Типы данных (Values). -

- - -
- - - - diff --git a/public/http b/public/http deleted file mode 100644 index 1ddb1a7..0000000 --- a/public/http +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: HTTP серверы (HTTP Servers) - - - - -
-

Go в примерах: HTTP серверы (HTTP Servers)

- - -

- Следующий пример: Порождающие процессы (Spawning Processes). -

- - -
- - - - diff --git a/public/if-else b/public/if-else deleted file mode 100644 index fc7514b..0000000 --- a/public/if-else +++ /dev/null @@ -1,191 +0,0 @@ - - - - - Go в примерах: If/Else - - - - -
-

Go в примерах: If/Else

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Условные операторы if иelse в Go -выглядят достаточно стандартно

- -
- - -
- - - -
package main
-
- -
- - - -
import "fmt"
-
- -
- - - -
func main() {
-
- -
-

Стандартное использование

- -
- -
    if 7%2 == 0 {
-        fmt.Println("7 is even")
-    } else {
-        fmt.Println("7 is odd")
-    }
-
- -
-

Вы можете использовать блоке if без блока else.

- -
- -
    if 8%4 == 0 {
-        fmt.Println("8 is divisible by 4")
-    }
-
- -
-

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

- -
- -
    if num := 9; num < 0 {
-        fmt.Println(num, "is negative")
-    } else if num < 10 {
-        fmt.Println(num, "has 1 digit")
-    } else {
-        fmt.Println(num, "has multiple digits")
-    }
-}
-
- -
-

Имейте ввиду, что в Go не надо использовать скобки в условии, -но блок необходимо заключать в фигурные скобки

- -
- - -
- - - - - - - - - - - - - -
- - - -
$ go run if-else.go 
-7 is odd
-8 is divisible by 4
-9 has 1 digit
-
- -
-

There is no ternary if -in Go, so you’ll need to use a full if statement even -for basic conditions.

- -
- - -
- - -

- Следующий пример: Switch. -

- - -
- - - - diff --git a/public/index.html b/public/index.html deleted file mode 100644 index c777850..0000000 --- a/public/index.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Go в примерах - - - -
-

Go в примерах

-

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

- -

- Go в примерах Go by Example - это практическое введение - в Go с использованием примеров реальных программ. Проверьте - первый пример или просмотрите полный - список ниже. -

- - - -
- - diff --git a/public/interfaces b/public/interfaces deleted file mode 100644 index 9c13931..0000000 --- a/public/interfaces +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Интерфейсы (Interfaces) - - - - -
-

Go в примерах: Интерфейсы (Interfaces)

- - -

- Следующий пример: Ошибки (Errors). -

- - -
- - - - diff --git a/public/json b/public/json deleted file mode 100644 index 9e541cf..0000000 --- a/public/json +++ /dev/null @@ -1,424 +0,0 @@ - - - - - Go в примерах: JSON - - - - -
-

Go в примерах: JSON

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

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

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "encoding/json"
-    "fmt"
-    "os"
-)
-
- -
-

Мы будем использовать эти две структуры, для демонстрации -кодирования и декодирования.

- -
- -
type response1 struct {
-    Page   int
-    Fruits []string
-}
-
- -
-

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

- -
- -
type response2 struct {
-    Page   int      `json:"page"`
-    Fruits []string `json:"fruits"`
-}
-
- -
- - - -
func main() {
-
- -
-

Для начала мы рассмотрим кодирование данных в -JSON строку. Вот несколько примеров для простых -типов данных.

- -
- -
    bolB, _ := json.Marshal(true)
-    fmt.Println(string(bolB))
-
- -
- - - -
    intB, _ := json.Marshal(1)
-    fmt.Println(string(intB))
-
- -
- - - -
    fltB, _ := json.Marshal(2.34)
-    fmt.Println(string(fltB))
-
- -
- - - -
    strB, _ := json.Marshal("gopher")
-    fmt.Println(string(strB))
-
- -
-

А вот примеры для срезов и карт, которые кодируются -в JSON массивы и объекты, как мы и ожидаем.

- -
- -
    slcD := []string{"apple", "peach", "pear"}
-    slcB, _ := json.Marshal(slcD)
-    fmt.Println(string(slcB))
-
- -
- - - -
    mapD := map[string]int{"apple": 5, "lettuce": 7}
-    mapB, _ := json.Marshal(mapD)
-    fmt.Println(string(mapB))
-
- -
-

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

- -
- -
    res1D := &response1{
-        Page:   1,
-        Fruits: []string{"apple", "peach", "pear"}}
-    res1B, _ := json.Marshal(res1D)
-    fmt.Println(string(res1B))
-
- -
-

Вы можете использовать теги в объявлениях -структурных полей для настройки кодированных имен -ключей JSON. Проверьте определение response2 -выше, чтобы увидеть пример таких тегов.

- -
- -
    res2D := &response2{
-        Page:   1,
-        Fruits: []string{"apple", "peach", "pear"}}
-    res2B, _ := json.Marshal(res2D)
-    fmt.Println(string(res2B))
-
- -
-

Теперь давайте рассмотрим декодирование данных -JSON в значения Go. Вот пример для общей -структуры данных.

- -
- -
    byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
-
- -
-

Нам нужно предоставить переменную, в которую пакет -JSON может поместить декодированные данные. -`map[string]interface{} будет содержать карту -строк для произвольных типов данных.

- -
- -
    var dat map[string]interface{}
-
- -
-

Вот фактическое декодирование и проверка на наличие -ошибок.

- -
- -
    if err := json.Unmarshal(byt, &dat); err != nil {
-        panic(err)
-    }
-    fmt.Println(dat)
-
- -
-

Чтобы использовать значения в декодированной карте, -нам нужно преобразовать их в соответствующий тип. -Например, здесь мы конвертируем значение из num -в ожидаемый тип float64.

- -
- -
    num := dat["num"].(float64)
-    fmt.Println(num)
-
- -
-

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

- -
- -
    strs := dat["strs"].([]interface{})
-    str1 := strs[0].(string)
-    fmt.Println(str1)
-
- -
-

Мы также можем декодировать JSON в пользовательские -типы данных. Это дает преимущество добавления -дополнительной безопасности типов в наши программы -и устранения необходимости в определении типрв -при доступе к декодированным данным.

- -
- -
    str := `{"page": 1, "fruits": ["apple", "peach"]}`
-    res := response2{}
-    json.Unmarshal([]byte(str), &res)
-    fmt.Println(res)
-    fmt.Println(res.Fruits[0])
-
- -
-

В приведенных выше примерах мы всегда использовали -байты и строки в качестве промежуточных звеньев между -данными и представлением JSON на стандартном выходе. -Мы также можем транслировать JSON-кодировки напрямую -в os.Writer, такие как os.Stdout или даже HTTP-тела -ответа.

- -
- -
    enc := json.NewEncoder(os.Stdout)
-    d := map[string]int{"apple": 5, "lettuce": 7}
-    enc.Encode(d)
-}
-
- -
- - - - - - - - - - - - - -
- - - -
$ go run json.go
-true
-1
-2.34
-"gopher"
-["apple","peach","pear"]
-{"apple":5,"lettuce":7}
-{"Page":1,"Fruits":["apple","peach","pear"]}
-{"page":1,"fruits":["apple","peach","pear"]}
-map[num:6.13 strs:[a b]]
-6.13
-a
-{1 [apple peach]}
-apple
-{"apple":5,"lettuce":7}
-
- -
-

Мы рассмотрели основы JSON в Go, но ознакомьтесь с -публикацией в блоге JSON and Go -и документацией по пакету JSON.

- -
- - -
- - -

- Следующий пример: XML. -

- - -
- - - - diff --git a/public/line-filters b/public/line-filters deleted file mode 100644 index 92aaa21..0000000 --- a/public/line-filters +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Строковые фильтры (Line Filters) - - - - -
-

Go в примерах: Строковые фильтры (Line Filters)

- - -

- Следующий пример: Пути к файлам (File Paths). -

- - -
- - - - diff --git a/public/maps b/public/maps deleted file mode 100644 index 8d69719..0000000 --- a/public/maps +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Карты (Maps) - - - - -
-

Go в примерах: Карты (Maps)

- - -

- Следующий пример: Ряд (Range). -

- - -
- - - - diff --git a/public/methods b/public/methods deleted file mode 100644 index 268a326..0000000 --- a/public/methods +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Методы (Methods) - - - - -
-

Go в примерах: Методы (Methods)

- - -

- Следующий пример: Интерфейсы (Interfaces). -

- - -
- - - - diff --git a/public/multiple-return-values b/public/multiple-return-values deleted file mode 100644 index fc6717b..0000000 --- a/public/multiple-return-values +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Функции с множественным возвратом (Multiple Return Values) - - - - -
-

Go в примерах: Функции с множественным возвратом (Multiple Return Values)

- - -

- Следующий пример: Функции с переменным числом аргументов (Variadic Functions). -

- - -
- - - - diff --git a/public/mutexes b/public/mutexes deleted file mode 100644 index 571bd6e..0000000 --- a/public/mutexes +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Мьютексы (Mutexes) - - - - -
-

Go в примерах: Мьютексы (Mutexes)

- - -

- Следующий пример: Управление состоянием горутин (Stateful Goroutines). -

- - -
- - - - diff --git a/public/non-blocking-channel-operations b/public/non-blocking-channel-operations deleted file mode 100644 index 754f365..0000000 --- a/public/non-blocking-channel-operations +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Неблокируемые операции в каналах (Non-Blocking Channel Operations) - - - - -
-

Go в примерах: Неблокируемые операции в каналах (Non-Blocking Channel Operations)

- - -

- Следующий пример: Закрытие каналов (Closing Channels). -

- - -
- - - - diff --git a/public/number-parsing b/public/number-parsing deleted file mode 100644 index 1cf3b50..0000000 --- a/public/number-parsing +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Парсинг чисел (Number Parsing) - - - - -
-

Go в примерах: Парсинг чисел (Number Parsing)

- - -

- Следующий пример: Парсинг URL (URL Parsing). -

- - -
- - - - diff --git a/public/panic b/public/panic deleted file mode 100644 index d393582..0000000 --- a/public/panic +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Go в примерах: Panic - - - - -
-

Go в примерах: Panic

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

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

- -
- - -
- - - -
package main
-
- -
- - - -
import "os"
-
- -
- - - -
func main() {
-
- -
-

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

- -
- -
    panic("a problem")
-
- -
-

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

- -
- -
    _, err := os.Create("/tmp/file")
-    if err != nil {
-        panic(err)
-    }
-}
-
- -
- - - - - - - - - - - - - - - - - - -
-

Запуск этой программы вызовет панику, распечатает -сообщение об ошибке и трейс выполнения и завершит -работу с ненулевым статусом.

- -
- -
$ go run panic.go
-panic: a problem
-
- -
- - - -
goroutine 1 [running]:
-main.main()
-    /.../panic.go:12 +0x47
-...
-exit status 2
-
- -
-

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

- -
- - -
- - -

- Следующий пример: Defer. -

- - -
- - - - diff --git a/public/play.png b/public/play.png deleted file mode 100644 index ec7028cc111e97129b9067aebd500df2bde39f0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 739 zcmV<90v!E`P)5r00004XF*Lt007q5 z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!bxA})R4C75 z`2YVu12XRD=wJYXlpqh=OR33;AA*B}UK(mCKQh->duC%}qk^s;g|leUVrG3k-8nPc zi~jFjJ@r2bw6t~nZzzoaUy$JcKPf5M2CD(7si_Q6(J>5iQevxj?%45v>Xb?UYjb1% z@7=xg|B(ZG{vTY`|NrRfzW)xk))ff}i3~9@F{lPGF)=zyi3zT#%a8s4@x%N7Cr_XK zZ*6Y$-^Ehr|H{c#|F7?!^Z(wVMgJ2*+-?a8i!wPlIG`H9$HP@+Z?5-z<>c!ByH`y9 zzkBt}|81p-|4RyT{%>8-{{PC(S^qEZoc(|M{FeV#mKM2@QBkM{00Aoy8)e4$zP^8W z;r~n9rvo+2`oC>a_y04Srh?fZLvHV%|Gy+F?msWTKs&ktU?3{QKl$vIY5yJnp=TC;hqGCQPL-mgjk1hcR;ElcW z{@(>AB9I}4$sw317i&h4F&-L0Un?elPj`gKWtyz`+sgn!T*A! zpf?IKVhiNuKJa`yvcws48XwH#AKhFo7+}@e}6|HR}dtosHn(LUtf=6005gz V0=~sP!p;By002ovPDHLkV1h=gV>SQ) diff --git a/public/pointers b/public/pointers deleted file mode 100644 index 37d75c0..0000000 --- a/public/pointers +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Указатели (Pointers) - - - - -
-

Go в примерах: Указатели (Pointers)

- - -

- Следующий пример: Структуры (Structs). -

- - -
- - - - diff --git a/public/random-numbers b/public/random-numbers deleted file mode 100644 index eb1856a..0000000 --- a/public/random-numbers +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Случайные числа (Random Numbers) - - - - -
-

Go в примерах: Случайные числа (Random Numbers)

- - -

- Следующий пример: Парсинг чисел (Number Parsing). -

- - -
- - - - diff --git a/public/range b/public/range deleted file mode 100644 index 17e52bb..0000000 --- a/public/range +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Ряд (Range) - - - - -
-

Go в примерах: Ряд (Range)

- - -

- Следующий пример: Функции (Functions). -

- - -
- - - - diff --git a/public/range-over-channels b/public/range-over-channels deleted file mode 100644 index e9724c5..0000000 --- a/public/range-over-channels +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Перебор значений из каналов (Range over Channels) - - - - -
-

Go в примерах: Перебор значений из каналов (Range over Channels)

- - -

- Следующий пример: Таймеры (Timers). -

- - -
- - - - diff --git a/public/rate-limiting b/public/rate-limiting deleted file mode 100644 index e55807e..0000000 --- a/public/rate-limiting +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Ограничение скорости (Rate Limiting) - - - - -
-

Go в примерах: Ограничение скорости (Rate Limiting)

- - -

- Следующий пример: Атомарные счетчики (Atomic Counters). -

- - -
- - - - diff --git a/public/reading-files b/public/reading-files deleted file mode 100644 index eeab811..0000000 --- a/public/reading-files +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Чтение файлов (Reading Files) - - - - -
-

Go в примерах: Чтение файлов (Reading Files)

- - -

- Следующий пример: Запись файлов (Writing Files). -

- - -
- - - - diff --git a/public/recursion b/public/recursion deleted file mode 100644 index a7bf95e..0000000 --- a/public/recursion +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Рекурсия (Recursion) - - - - -
-

Go в примерах: Рекурсия (Recursion)

- - -

- Следующий пример: Указатели (Pointers). -

- - -
- - - - diff --git a/public/regular-expressions b/public/regular-expressions deleted file mode 100644 index 700db55..0000000 --- a/public/regular-expressions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Регулярные выражения (Regular Expressions) - - - - -
-

Go в примерах: Регулярные выражения (Regular Expressions)

- - -

- Следующий пример: JSON. -

- - -
- - - - diff --git a/public/select b/public/select deleted file mode 100644 index f45e57e..0000000 --- a/public/select +++ /dev/null @@ -1,192 +0,0 @@ - - - - - Go в примерах: Select - - - - -
-

Go в примерах: Select

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Go’s _select позволяет вам ждать нескольких -операций на канале. Сочетание горутин и каналов -с помощью select’а - мощная функция Go.

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "fmt"
-    "time"
-)
-
- -
- - - -
func main() {
-
- -
-

В нашем примере мы будем выбирать между двумя -каналами.

- -
- -
    c1 := make(chan string)
-    c2 := make(chan string)
-
- -
-

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

- -
- -
    go func() {
-        time.Sleep(1 * time.Second)
-        c1 <- "one"
-    }()
-    go func() {
-        time.Sleep(2 * time.Second)
-        c2 <- "two"
-    }()
-
- -
-

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

- -
- -
    for i := 0; i < 2; i++ {
-        select {
-        case msg1 := <-c1:
-            fmt.Println("received", msg1)
-        case msg2 := <-c2:
-            fmt.Println("received", msg2)
-        }
-    }
-}
-
- -
- - - - - - - - - - - - - -
-

Мы получаем значние "one" и потом "two", как -и ожидалось.

- -
- -
$ time go run select.go 
-received one
-received two
-
- -
-

Обратите внимание, что общее время выполнения -составляет всего ~2 секунды, так как и 1, и 2 секунды -Sleeps выполняются одновременно.

- -
- -
real    0m2.245s
-
- -
- - -

- Следующий пример: Тайм-ауты (Timeouts). -

- - -
- - - - diff --git a/public/sha1 b/public/sha1 deleted file mode 100644 index daf6a09..0000000 --- a/public/sha1 +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Хеш SHA1 (SHA1 Hashes) - - - - -
-

Go в примерах: Хеш SHA1 (SHA1 Hashes)

- - -

- Следующий пример: Кодирование Base64 (Base64 Encoding). -

- - -
- - - - diff --git a/public/signals b/public/signals deleted file mode 100644 index d4b3432..0000000 --- a/public/signals +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Сигналы (Signals) - - - - -
-

Go в примерах: Сигналы (Signals)

- - -

- Следующий пример: Выход (Exit). -

- - -
- - - - diff --git a/public/site.css b/public/site.css deleted file mode 100644 index 7e93afb..0000000 --- a/public/site.css +++ /dev/null @@ -1,212 +0,0 @@ -/* CSS reset: http://meyerweb.com/eric/tools/css/reset/ */ -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} - -/* Layout and typography */ -body { - font-family: 'Georgia', serif; - font-size: 16px; - line-height: 20px; - color: #252519; -} -em { - font-style: italic; -} -a, a:visited { - color: #261a3b; -} -h2 { - font-size: 32px; - line-height: 40px; - margin-top: 40px; -} -h2 a { - text-decoration: none; -} -div.example { - width: 900px; - min-width: 900px; - max-width: 900px; - margin-left: auto; - margin-right: auto; - margin-bottom: 120px; -} -div.example table { - margin-top: 15px; - margin-bottom: 20px; -} -p.next { - margin-bottom: 20px; -} -p.footer { - color: grey; -} -p.footer a, p.footer a:visited { - color: grey; -} -div#intro { - width: 420px; - min-width: 420px; - max-width: 420px; - margin-left: auto; - margin-right: auto; - margin-bottom: 120px; -} -div#intro p { - padding-top: 20px; -} -div#intro ul { - padding-top: 20px; -} -table td { - border: 0; - outline: 0; -} -td.docs { - width: 420px; - max-width: 420px; - min-width: 420px; - min-height: 5px; - vertical-align: top; - text-align: left; -} -td.docs p { - padding-right: 5px; - padding-top: 5px; - padding-bottom: 15px; -} -td.code { - width: 480px; - max-width: 480px; - min-width: 480px; - padding-top: 5px; - padding-right: 5px; - padding-left: 5px; - padding-bottom: 5px; - vertical-align: top; - background: #f0f0f0; -} -td.code.leading { - padding-bottom: 11px; -} -td.code.empty { - background: #ffffff; -} -pre, code { - font-size: 14px; line-height: 18px; - font-family: 'Menlo', 'Monaco', 'Consolas', 'Lucida Console', monospace; -} -img.copy, img.run { - height: 16px; - width: 16px; - float: right -} -img.copy, img.run { - cursor: pointer; -} -img.copy { - margin-right: 4px; -} - -/* Syntax highlighting */ -body .hll { background-color: #ffffcc } -body .err { border: 1px solid #FF0000 } /* Error */ -body .c { color: #408080; font-style: italic } /* Comment */ -body .k { color: #954121 } /* Keyword */ -body .o { color: #666666 } /* Operator */ -body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ -body .cp { color: #BC7A00 } /* Comment.Preproc */ -body .c1 { color: #408080; font-style: italic } /* Comment.Single */ -body .cs { color: #408080; font-style: italic } /* Comment.Special */ -body .gd { color: #A00000 } /* Generic.Deleted */ -body .ge { font-style: italic } /* Generic.Emph */ -body .gr { color: #FF0000 } /* Generic.Error */ -body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -body .gi { color: #00A000 } /* Generic.Inserted */ -body .go { color: #808080 } /* Generic.Output */ -body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -body .gs { font-weight: bold } /* Generic.Strong */ -body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -body .gt { color: #0040D0 } /* Generic.Traceback */ -body .kc { color: #954121 } /* Keyword.Constant */ -body .kd { color: #954121 } /* Keyword.Declaration */ -body .kn { color: #954121 } /* Keyword.Namespace */ -body .kp { color: #954121 } /* Keyword.Pseudo */ -body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ -body .kt { color: #B00040 } /* Keyword.Type */ -body .m { color: #666666 } /* Literal.Number */ -body .s { color: #219161 } /* Literal.String */ -body .na { color: #7D9029 } /* Name.Attribute */ -body .nb { color: #954121 } /* Name.Builtin */ -body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -body .no { color: #880000 } /* Name.Constant */ -body .nd { color: #AA22FF } /* Name.Decorator */ -body .ni { color: #999999; font-weight: bold } /* Name.Entity */ -body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -body .nf { color: #0000FF } /* Name.Function */ -body .nl { color: #A0A000 } /* Name.Label */ -body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -body .nt { color: #954121; font-weight: bold } /* Name.Tag */ -body .nv { color: #19469D } /* Name.Variable */ -body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -body .w { color: #bbbbbb } /* Text.Whitespace */ -body .mf { color: #666666 } /* Literal.Number.Float */ -body .mh { color: #666666 } /* Literal.Number.Hex */ -body .mi { color: #666666 } /* Literal.Number.Integer */ -body .mo { color: #666666 } /* Literal.Number.Oct */ -body .sb { color: #219161 } /* Literal.String.Backtick */ -body .sc { color: #219161 } /* Literal.String.Char */ -body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ -body .s2 { color: #219161 } /* Literal.String.Double */ -body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -body .sh { color: #219161 } /* Literal.String.Heredoc */ -body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -body .sx { color: #954121 } /* Literal.String.Other */ -body .sr { color: #BB6688 } /* Literal.String.Regex */ -body .s1 { color: #219161 } /* Literal.String.Single */ -body .ss { color: #19469D } /* Literal.String.Symbol */ -body .bp { color: #954121 } /* Name.Builtin.Pseudo */ -body .vc { color: #19469D } /* Name.Variable.Class */ -body .vg { color: #19469D } /* Name.Variable.Global */ -body .vi { color: #19469D } /* Name.Variable.Instance */ -body .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/public/site.js b/public/site.js deleted file mode 100644 index 752e656..0000000 --- a/public/site.js +++ /dev/null @@ -1,17 +0,0 @@ -/*! - * clipboard.js v1.5.13 - * https://zenorocha.github.io/clipboard.js - * - * Licensed MIT © Zeno Rocha - */ -!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,o){function r(c,a){if(!n[c]){if(!e[c]){var l="function"==typeof require&&require;if(!a&&l)return l(c,!0);if(i)return i(c,!0);var s=new Error("Cannot find module '"+c+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[c]={exports:{}};e[c][0].call(u.exports,function(t){var n=e[c][1][t];return r(n?n:t)},u,u.exports,t,e,n,o)}return n[c].exports}for(var i="function"==typeof require&&require,c=0;c - - - - Go в примерах: Срезы (Slices) - - - - -
-

Go в примерах: Срезы (Slices)

- - -

- Следующий пример: Карты (Maps). -

- - -
- - - - diff --git a/public/sorting b/public/sorting deleted file mode 100644 index 3cc8fc4..0000000 --- a/public/sorting +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Сортировка (Sorting) - - - - -
-

Go в примерах: Сортировка (Sorting)

- - -

- Следующий пример: Сортировка через функции (Sorting by Functions). -

- - -
- - - - diff --git a/public/sorting-by-functions b/public/sorting-by-functions deleted file mode 100644 index fb1f2fa..0000000 --- a/public/sorting-by-functions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Сортировка через функции (Sorting by Functions) - - - - -
-

Go в примерах: Сортировка через функции (Sorting by Functions)

- - -

- Следующий пример: Panic. -

- - -
- - - - diff --git a/public/spawning-processes b/public/spawning-processes deleted file mode 100644 index 1cc1f34..0000000 --- a/public/spawning-processes +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Порождающие процессы (Spawning Processes) - - - - -
-

Go в примерах: Порождающие процессы (Spawning Processes)

- - -

- Следующий пример: Исполняющие процессы (Exec'ing Processes). -

- - -
- - - - diff --git a/public/stateful-goroutines b/public/stateful-goroutines deleted file mode 100644 index df7ce5a..0000000 --- a/public/stateful-goroutines +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Управление состоянием горутин (Stateful Goroutines) - - - - -
-

Go в примерах: Управление состоянием горутин (Stateful Goroutines)

- - -

- Следующий пример: Сортировка (Sorting). -

- - -
- - - - diff --git a/public/string-formatting b/public/string-formatting deleted file mode 100644 index 3e8ab84..0000000 --- a/public/string-formatting +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Форматирование строк (String Formatting) - - - - -
-

Go в примерах: Форматирование строк (String Formatting)

- - -

- Следующий пример: Регулярные выражения (Regular Expressions). -

- - -
- - - - diff --git a/public/string-functions b/public/string-functions deleted file mode 100644 index 04ab05a..0000000 --- a/public/string-functions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Строковые функции (String Functions) - - - - -
-

Go в примерах: Строковые функции (String Functions)

- - -

- Следующий пример: Форматирование строк (String Formatting). -

- - -
- - - - diff --git a/public/structs b/public/structs deleted file mode 100644 index fadbae1..0000000 --- a/public/structs +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Структуры (Structs) - - - - -
-

Go в примерах: Структуры (Structs)

- - -

- Следующий пример: Методы (Methods). -

- - -
- - - - diff --git a/public/switch b/public/switch deleted file mode 100644 index 4f7cf2f..0000000 --- a/public/switch +++ /dev/null @@ -1,209 +0,0 @@ - - - - - Go в примерах: Switch - - - - -
-

Go в примерах: Switch

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Switch помогает проверять условие в нескольких блоках

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "fmt"
-    "time"
-)
-
- -
- - - -
func main() {
-
- -
-

Стандартное использование switch.

- -
- -
    i := 2
-    fmt.Print("Write ", i, " as ")
-    switch i {
-    case 1:
-        fmt.Println("one")
-    case 2:
-        fmt.Println("two")
-    case 3:
-        fmt.Println("three")
-    }
-
- -
-

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

- -
- -
    switch time.Now().Weekday() {
-    case time.Saturday, time.Sunday:
-        fmt.Println("It's the weekend")
-    default:
-        fmt.Println("It's a weekday")
-    }
-
- -
-

switch без условия аналогичен обычному оператору -if/else по своей логике. Так же в этом примере -что в case можно использовать не только константы.

- -
- -
    t := time.Now()
-    switch {
-    case t.Hour() < 12:
-        fmt.Println("It's before noon")
-    default:
-        fmt.Println("It's after noon")
-    }
-
- -
-

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

- -
- -
    whatAmI := func(i interface{}) {
-        switch t := i.(type) {
-        case bool:
-            fmt.Println("I'm a bool")
-        case int:
-            fmt.Println("I'm an int")
-        default:
-            fmt.Printf("Don't know type %T\n", t)
-        }
-    }
-    whatAmI(true)
-    whatAmI(1)
-    whatAmI("hey")
-}
-
- -
- - - - - - - - -
- - - -
$ go run switch.go 
-Write 2 as two
-It's a weekday
-It's after noon
-I'm a bool
-I'm an int
-Don't know type string
-
- -
- - -

- Следующий пример: Массивы (Arrays). -

- - -
- - - - diff --git a/public/temporary-files-and-directories b/public/temporary-files-and-directories deleted file mode 100644 index 0bb9089..0000000 --- a/public/temporary-files-and-directories +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Временные файлы и директории (Temporary Files and Directories) - - - - -
-

Go в примерах: Временные файлы и директории (Temporary Files and Directories)

- - -

- Следующий пример: Тестирование (Testing). -

- - -
- - - - diff --git a/public/testing b/public/testing deleted file mode 100644 index ae3d56f..0000000 --- a/public/testing +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Тестирование (Testing) - - - - -
-

Go в примерах: Тестирование (Testing)

- - -

- Следующий пример: Аргументы командной строки (Command-Line Arguments). -

- - -
- - - - diff --git a/public/tickers b/public/tickers deleted file mode 100644 index e33731e..0000000 --- a/public/tickers +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Тикеры (повторения) (Tickers) - - - - -
-

Go в примерах: Тикеры (повторения) (Tickers)

- - -

- Следующий пример: Пулы воркеров (Worker Pools). -

- - -
- - - - diff --git a/public/time b/public/time deleted file mode 100644 index 75f4c6d..0000000 --- a/public/time +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Время (Time) - - - - -
-

Go в примерах: Время (Time)

- - -

- Следующий пример: Epoch. -

- - -
- - - - diff --git a/public/time-formatting-parsing b/public/time-formatting-parsing deleted file mode 100644 index 176c27a..0000000 --- a/public/time-formatting-parsing +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Форматирование времени (Time Formatting / Parsing) - - - - -
-

Go в примерах: Форматирование времени (Time Formatting / Parsing)

- - -

- Следующий пример: Случайные числа (Random Numbers). -

- - -
- - - - diff --git a/public/timeouts b/public/timeouts deleted file mode 100644 index 0ab0267..0000000 --- a/public/timeouts +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Тайм-ауты (Timeouts) - - - - -
-

Go в примерах: Тайм-ауты (Timeouts)

- - -

- Следующий пример: Неблокируемые операции в каналах (Non-Blocking Channel Operations). -

- - -
- - - - diff --git a/public/timers b/public/timers deleted file mode 100644 index 20484a9..0000000 --- a/public/timers +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Таймеры (Timers) - - - - -
-

Go в примерах: Таймеры (Timers)

- - -

- Следующий пример: Тикеры (повторения) (Tickers). -

- - -
- - - - diff --git a/public/url b/public/url deleted file mode 100644 index 6c42ddc..0000000 --- a/public/url +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Парсинг URL (URL Parsing) - - - - -
-

Go в примерах: Парсинг URL (URL Parsing)

- - -

- Следующий пример: Хеш SHA1 (SHA1 Hashes). -

- - -
- - - - diff --git a/public/values b/public/values deleted file mode 100644 index 3abd5d6..0000000 --- a/public/values +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Типы данных (Values) - - - - -
-

Go в примерах: Типы данных (Values)

- - -

- Следующий пример: Переменные (Variables). -

- - -
- - - - diff --git a/public/variables b/public/variables deleted file mode 100644 index cacb411..0000000 --- a/public/variables +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Переменные (Variables) - - - - -
-

Go в примерах: Переменные (Variables)

- - -

- Следующий пример: Константы (Constants). -

- - -
- - - - diff --git a/public/variadic-functions b/public/variadic-functions deleted file mode 100644 index 53e6729..0000000 --- a/public/variadic-functions +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Функции с переменным числом аргументов (Variadic Functions) - - - - -
-

Go в примерах: Функции с переменным числом аргументов (Variadic Functions)

- - -

- Следующий пример: Замыкания (Closures). -

- - -
- - - - diff --git a/public/waitgroups b/public/waitgroups deleted file mode 100644 index 11682c0..0000000 --- a/public/waitgroups +++ /dev/null @@ -1,226 +0,0 @@ - - - - - Go в примерах: WaitGroups - - - - -
-

Go в примерах: WaitGroups

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Для ожидания выполнения нескольких горутин, мы можем -использовать встроенную конструкцию WaitGroup.

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "fmt"
-    "sync"
-    "time"
-)
-
- -
-

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

- -
- -
func worker(id int, wg *sync.WaitGroup) {
-    fmt.Printf("Worker %d starting\n", id)
-
- -
-

Sleep симулирует тяжелую задачу.

- -
- -
    time.Sleep(time.Second)
-    fmt.Printf("Worker %d done\n", id)
-
- -
-

Оповестить WaitGroup что воркер выполнился

- -
- -
    wg.Done()
-}
-
- -
- - - -
func main() {
-
- -
-

Эта WaitGroup используется для ожидания выполнения -всех горутинё запущенных здесь.

- -
- -
    var wg sync.WaitGroup
-
- -
-

Запускаем несколько горутин и инкрементируем счетчик -в WaitGroup для каждой запущенной горутины.

- -
- -
    for i := 1; i <= 5; i++ {
-        wg.Add(1)
-        go worker(i, &wg)
-    }
-
- -
-

Блокируем звершение программы до момента, пока -счетчик WaitGroup снова не станет равным 0. -Это будет означать, что все горутины выполнились.

- -
- -
    wg.Wait()
-}
-
- -
- - - - - - - - - - - - - -
- - - -
$ go run waitgroups.go
-Worker 5 starting
-Worker 3 starting
-Worker 4 starting
-Worker 1 starting
-Worker 2 starting
-Worker 4 done
-Worker 1 done
-Worker 2 done
-Worker 5 done
-Worker 3 done
-
- -
-

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

- -
- - -
- - -

- Следующий пример: Ограничение скорости (Rate Limiting). -

- - -
- - - - diff --git a/public/worker-pools b/public/worker-pools deleted file mode 100644 index 052fe79..0000000 --- a/public/worker-pools +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Пулы воркеров (Worker Pools) - - - - -
-

Go в примерах: Пулы воркеров (Worker Pools)

- - -

- Следующий пример: WaitGroups. -

- - -
- - - - diff --git a/public/writing-files b/public/writing-files deleted file mode 100644 index fd622c1..0000000 --- a/public/writing-files +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Go в примерах: Запись файлов (Writing Files) - - - - -
-

Go в примерах: Запись файлов (Writing Files)

- - -

- Следующий пример: Строковые фильтры (Line Filters). -

- - -
- - - - diff --git a/public/xml b/public/xml deleted file mode 100644 index 95f1a49..0000000 --- a/public/xml +++ /dev/null @@ -1,288 +0,0 @@ - - - - - Go в примерах: XML - - - - -
-

Go в примерах: XML

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Go предлагает встроенную поддержку XML и -XML-подобных форматов с пакетом encoding.xml.

- -
- - -
- - - -
package main
-
- -
- - - -
import (
-    "encoding/xml"
-    "fmt"
-)
-
- -
-

Этот тип будет сопоставлен с XML. Как и в примерах JSON, -теги полей содержат директивы для кодера и декодера. -Здесь мы используем некоторые особенности пакета XML: -XMLName определяет имя элемента XML, представляющего -эту структуру; id,attr означает, что поле Id является -атрибутом XML, а не вложенным элементом.

- -
- -
type Plant struct {
-    XMLName xml.Name `xml:"plant"`
-    Id      int      `xml:"id,attr"`
-    Name    string   `xml:"name"`
-    Origin  []string `xml:"origin"`
-}
-
- -
- - - -
func (p Plant) String() string {
-    return fmt.Sprintf("Plant id=%v, name=%v, origin=%v",
-        p.Id, p.Name, p.Origin)
-}
-
- -
- - - -
func main() {
-    coffee := &Plant{Id: 27, Name: "Coffee"}
-    coffee.Origin = []string{"Ethiopia", "Brazil"}
-
- -
-

Создаем XML, представляющий наш plant; -использование MarshalIndent для создания более -читабельного вывода.

- -
- -
    out, _ := xml.MarshalIndent(coffee, " ", "  ")
-    fmt.Println(string(out))
-
- -
-

Чтобы добавить общий заголовок XML к выводу, добавьте -его явно.

- -
- -
    fmt.Println(xml.Header + string(out))
-
- -
-

Используйте Unmarhshal для парсинга байтов с XML в -структуру данных. Если XML имеет неправильный формат -или не может быть преобразован в Plant, будет -возвращена описательная ошибка.

- -
- -
    var p Plant
-    if err := xml.Unmarshal(out, &p); err != nil {
-        panic(err)
-    }
-    fmt.Println(p)
-
- -
- - - -
    tomato := &Plant{Id: 81, Name: "Tomato"}
-    tomato.Origin = []string{"Mexico", "California"}
-
- -
-

Поле parent>child>plant сообщает кодировщику о -необходимости вложения всех plant в -<parent><child>...

- -
- -
    type Nesting struct {
-        XMLName xml.Name `xml:"nesting"`
-        Plants  []*Plant `xml:"parent>child>plant"`
-    }
-
- -
- - - -
    nesting := &Nesting{}
-    nesting.Plants = []*Plant{coffee, tomato}
-
- -
- - - -
    out, _ = xml.MarshalIndent(nesting, " ", "  ")
-    fmt.Println(string(out))
-}
-
- -
- - - - - - - - -
- - - -
$ go run xml.go
- <plant id="27">
-   <name>Coffee</name>
-   <origin>Ethiopia</origin>
-   <origin>Brazil</origin>
- </plant>
-<?xml version="1.0" encoding="UTF-8"?>
- <plant id="27">
-   <name>Coffee</name>
-   <origin>Ethiopia</origin>
-   <origin>Brazil</origin>
- </plant>
-Plant id=27, name=Coffee, origin=[Ethiopia Brazil]
- <nesting>
-   <parent>
-     <child>
-       <plant id="27">
-         <name>Coffee</name>
-         <origin>Ethiopia</origin>
-         <origin>Brazil</origin>
-       </plant>
-       <plant id="81">
-         <name>Tomato</name>
-         <origin>Mexico</origin>
-         <origin>California</origin>
-       </plant>
-     </child>
-   </parent>
- </nesting>
-
- -
- - -

- Следующий пример: Время (Time). -

- - -
- - - - diff --git a/tools/generate.go b/tools/generate.go index 4fd2dd3..1c22ada 100644 --- a/tools/generate.go +++ b/tools/generate.go @@ -238,7 +238,7 @@ func parseAndRenderSegs(sourcePath string) ([]*Seg, string) { func parseExamples() []*Example { var exampleNames []string - re := regexp.MustCompile(`(?m)[a-z0-9]{1}[a-z0-9\-]{1,}[a-z0-9]{1}`) + for _, line := range readLines("examples.txt") { if line != "" && !strings.HasPrefix(line, "#") { exampleNames = append(exampleNames, line) @@ -249,18 +249,24 @@ func parseExamples() []*Example { if verbose() { fmt.Printf("Processing %s [%d/%d]\n", exampleName, i+1, len(exampleNames)) } - example := Example{Name: exampleName} - exampleID := strings.ToLower(exampleName) + + exampleID := exampleName + + if strings.Contains(exampleName, "|") { + parts := strings.Split(exampleName, "|") + exampleName, exampleID = parts[0], parts[1] + } + + exampleID = strings.ToLower(exampleID) exampleID = strings.Replace(exampleID, " ", "-", -1) exampleID = strings.Replace(exampleID, "/", "-", -1) exampleID = strings.Replace(exampleID, "'", "", -1) exampleID = dashPat.ReplaceAllString(exampleID, "-") - //str := `хеш-sha1-(sha1-hashes)` - //fmt.Println(re.FindString(str)) + example := Example{Name: exampleName} + + example.ID = exampleID - //example.ID = exampleID - example.ID = re.FindString(exampleID) example.Segs = make([][]*Seg, 0) sourcePaths := mustGlob("examples/" + exampleID + "/*") for _, sourcePath := range sourcePaths { From 7d33b530edf77351dbd6e99cbe464ec70043971c Mon Sep 17 00:00:00 2001 From: badkaktus Date: Mon, 14 Oct 2019 23:20:44 +0300 Subject: [PATCH 2/2] fix links --- examples/.hash | 2 + public/404.html | 17 + public/arrays | 214 ++++++++++++ public/atomic-counters | 241 +++++++++++++ public/base64-encoding | 199 +++++++++++ public/channel-buffering | 160 +++++++++ public/channel-directions | 152 ++++++++ public/channel-synchronization | 192 ++++++++++ public/channels | 175 ++++++++++ public/clipboard.png | Bin 0 -> 488 bytes public/closing-channels | 201 +++++++++++ public/closures | 197 +++++++++++ public/collection-functions | 378 ++++++++++++++++++++ public/command-line-arguments | 181 ++++++++++ public/command-line-flags | 322 +++++++++++++++++ public/command-line-subcommands | 270 +++++++++++++++ public/constants | 190 ++++++++++ public/defer | 220 ++++++++++++ public/directories | 360 +++++++++++++++++++ public/environment-variables | 194 +++++++++++ public/epoch | 183 ++++++++++ public/errors | 305 ++++++++++++++++ public/execing-processes | 209 +++++++++++ public/exit | 180 ++++++++++ public/favicon.ico | Bin 0 -> 71518 bytes public/file-paths | 257 ++++++++++++++ public/for | 202 +++++++++++ public/functions | 201 +++++++++++ public/goroutines | 214 ++++++++++++ public/hello-world | 142 ++++++++ public/http-clients | 175 ++++++++++ public/http-servers | 218 ++++++++++++ public/if-else | 191 ++++++++++ public/index.html | 182 ++++++++++ public/interfaces | 242 +++++++++++++ public/json | 424 +++++++++++++++++++++++ public/line-filters | 214 ++++++++++++ public/maps | 239 +++++++++++++ public/methods | 205 +++++++++++ public/multiple-return-values | 176 ++++++++++ public/mutexes | 305 ++++++++++++++++ public/non-blocking-channel-operations | 186 ++++++++++ public/number-parsing | 221 ++++++++++++ public/panic | 183 ++++++++++ public/play.png | Bin 0 -> 739 bytes public/pointers | 199 +++++++++++ public/random-numbers | 239 +++++++++++++ public/range | 209 +++++++++++ public/range-over-channels | 160 +++++++++ public/rate-limiting | 270 +++++++++++++++ public/reading-files | 296 ++++++++++++++++ public/recursion | 132 +++++++ public/regular-expressions | 352 +++++++++++++++++++ public/select | 192 ++++++++++ public/sha1-hashes | 212 ++++++++++++ public/signals | 199 +++++++++++ public/site.css | 212 ++++++++++++ public/site.js | 17 + public/slices | 321 +++++++++++++++++ public/sorting | 168 +++++++++ public/sorting-by-functions | 185 ++++++++++ public/spawning-processes | 267 ++++++++++++++ public/stateful-goroutines | 328 ++++++++++++++++++ public/string-formatting | 462 +++++++++++++++++++++++++ public/string-functions | 216 ++++++++++++ public/structs | 279 +++++++++++++++ public/switch | 209 +++++++++++ public/temporary-files-and-directories | 247 +++++++++++++ public/testing | 240 +++++++++++++ public/tickers | 180 ++++++++++ public/time | 274 +++++++++++++++ public/time-formatting-parsing | 208 +++++++++++ public/timeouts | 189 ++++++++++ public/timers | 176 ++++++++++ public/url-parsing | 240 +++++++++++++ public/values | 159 +++++++++ public/variables | 191 ++++++++++ public/variadic-functions | 177 ++++++++++ public/waitgroups | 226 ++++++++++++ public/worker-pools | 231 +++++++++++++ public/writing-files | 298 ++++++++++++++++ public/xml | 288 +++++++++++++++ 82 files changed, 17367 insertions(+) create mode 100644 examples/.hash create mode 100644 public/404.html create mode 100644 public/arrays create mode 100644 public/atomic-counters create mode 100644 public/base64-encoding create mode 100644 public/channel-buffering create mode 100644 public/channel-directions create mode 100644 public/channel-synchronization create mode 100644 public/channels create mode 100644 public/clipboard.png create mode 100644 public/closing-channels create mode 100644 public/closures create mode 100644 public/collection-functions create mode 100644 public/command-line-arguments create mode 100644 public/command-line-flags create mode 100644 public/command-line-subcommands create mode 100644 public/constants create mode 100644 public/defer create mode 100644 public/directories create mode 100644 public/environment-variables create mode 100644 public/epoch create mode 100644 public/errors create mode 100644 public/execing-processes create mode 100644 public/exit create mode 100644 public/favicon.ico create mode 100644 public/file-paths create mode 100644 public/for create mode 100644 public/functions create mode 100644 public/goroutines create mode 100644 public/hello-world create mode 100644 public/http-clients create mode 100644 public/http-servers create mode 100644 public/if-else create mode 100644 public/index.html create mode 100644 public/interfaces create mode 100644 public/json create mode 100644 public/line-filters create mode 100644 public/maps create mode 100644 public/methods create mode 100644 public/multiple-return-values create mode 100644 public/mutexes create mode 100644 public/non-blocking-channel-operations create mode 100644 public/number-parsing create mode 100644 public/panic create mode 100644 public/play.png create mode 100644 public/pointers create mode 100644 public/random-numbers create mode 100644 public/range create mode 100644 public/range-over-channels create mode 100644 public/rate-limiting create mode 100644 public/reading-files create mode 100644 public/recursion create mode 100644 public/regular-expressions create mode 100644 public/select create mode 100644 public/sha1-hashes create mode 100644 public/signals create mode 100644 public/site.css create mode 100644 public/site.js create mode 100644 public/slices create mode 100644 public/sorting create mode 100644 public/sorting-by-functions create mode 100644 public/spawning-processes create mode 100644 public/stateful-goroutines create mode 100644 public/string-formatting create mode 100644 public/string-functions create mode 100644 public/structs create mode 100644 public/switch create mode 100644 public/temporary-files-and-directories create mode 100644 public/testing create mode 100644 public/tickers create mode 100644 public/time create mode 100644 public/time-formatting-parsing create mode 100644 public/timeouts create mode 100644 public/timers create mode 100644 public/url-parsing create mode 100644 public/values create mode 100644 public/variables create mode 100644 public/variadic-functions create mode 100644 public/waitgroups create mode 100644 public/worker-pools create mode 100644 public/writing-files create mode 100644 public/xml diff --git a/examples/.hash b/examples/.hash new file mode 100644 index 0000000..8ab57f4 --- /dev/null +++ b/examples/.hash @@ -0,0 +1,2 @@ +da39a3ee5e6b4b0d3255bfef95601890afd80709 +UCPdVNrl0-P diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..e2a089e --- /dev/null +++ b/public/404.html @@ -0,0 +1,17 @@ + + + + + Go by Example: Not Found + + + +
+

Go by Example

+

Sorry, we couldn't find that! Check out the home page?

+ +
+ + diff --git a/public/arrays b/public/arrays new file mode 100644 index 0000000..caf712a --- /dev/null +++ b/public/arrays @@ -0,0 +1,214 @@ + + + + + Go в примерах: Массивы (Arrays) + + + + +
+

Go в примерах: Массивы (Arrays)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В Go, массив это числовой ряд элементов определенной +длины.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

В данном примере мы создаем массив a, который +содержит 5 элементов с типом int. Тип элементов +и длина являются частью типа массива. По-умолчанию +массив заполняется нулевыми значениями, например, +в случае int нулевое значение - 0.

+ +
+ +
    var a [5]int
+    fmt.Println("emp:", a)
+
+ +
+

Мы можем установить значение по индексу элемента +следующим образом:array[index] = value. +Получить значение можно аналогично - array[index].

+ +
+ +
    a[4] = 100
+    fmt.Println("set:", a)
+    fmt.Println("get:", a[4])
+
+ +
+

Встроенная функция len возвращает длину массива.

+ +
+ +
    fmt.Println("len:", len(a))
+
+ +
+

Так можно инициалзировать и заполнить массив +значениеми в одну строку

+ +
+ +
    b := [5]int{1, 2, 3, 4, 5}
+    fmt.Println("dcl:", b)
+
+ +
+

Тип массив является одномерным. Но вы можете +совмещать типы, для создания многомерных +структур.

+ +
+ +
    var twoD [2][3]int
+    for i := 0; i < 2; i++ {
+        for j := 0; j < 3; j++ {
+            twoD[i][j] = i + j
+        }
+    }
+    fmt.Println("2d: ", twoD)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Обратите внимание, что массивы отображаются в виде +[v1 v2 v3 …] при выводе с помощью fmt.Println.

+ +
+ +
$ go run arrays.go
+emp: [0 0 0 0 0]
+set: [0 0 0 0 100]
+get: 100
+len: 5
+dcl: [1 2 3 4 5]
+2d:  [[0 1 2] [1 2 3]]
+
+ +
+

В Go вы будете встречать срезы гораздо чаще, чем +массивы. Срезы рассмотрим далее

+ +
+ + +
+ + +

+ Следующий пример: Срезы (Slices). +

+ + +
+ + + + diff --git a/public/atomic-counters b/public/atomic-counters new file mode 100644 index 0000000..d3775c0 --- /dev/null +++ b/public/atomic-counters @@ -0,0 +1,241 @@ + + + + + Go в примерах: Атомарные счетчики (Atomic Counters) + + + + +
+

Go в примерах: Атомарные счетчики (Atomic Counters)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Основным механизмом управления состоянием в Go является +связь по каналам. Мы видели это, например, с пулами воркеров. +Есть несколько других вариантов управления состоянием. +Здесь мы рассмотрим использование пакета sync/atomic +для атомарных счетчиков, к которым обращаются горутины.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "sync"
+    "sync/atomic"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Мы будем использовать целое число без знака +для представления нашего (всегда положительного) +счетчика.

+ +
+ +
    var ops uint64
+
+ +
+

WaitGroup поможет нам подождать, пока все горутины +завершат свою работу.

+ +
+ +
    var wg sync.WaitGroup
+
+ +
+

Мы запустим 50 горутин, каждая из которых увеличивает +счетчик ровно в 1000 раз.

+ +
+ +
    for i := 0; i < 50; i++ {
+        wg.Add(1)
+
+ +
+

Для атомарного увеличения счетчика мы +используем AddUint64, присваивая ему адрес +памяти нашего счетчика ops с префиксом &.

+ +
+ +
        go func() {
+            for c := 0; c < 1000; c++ {
+
+ +
+ + + +
                atomic.AddUint64(&ops, 1)
+            }
+            wg.Done()
+        }()
+    }
+
+ +
+

Ждем пока завершатся горутины.

+ +
+ +
    wg.Wait()
+
+ +
+

Теперь доступ к ops безопасен, потому что мы знаем, +что никакие другие горутины не пишут в него. Безопасное +чтение атомарного счетчика во время его обновления также +возможно, используя функцию atomic.LoadUint64.

+ +
+ +
    fmt.Println("ops:", ops)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Мы ожидаем получить ровно 50 000 операций. Если бы +мы использовали неатомарный ops++ для увеличения +счетчика, мы бы, вероятно, получили другое число, +изменяющееся между прогонами, потому что горутины +мешали бы друг другу. Более того, мы получим сбои +в гонке данных при работе с флагом -race.

+ +
+ +
$ go run atomic-counters.go
+ops: 50000
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Мьютексы (Mutexes). +

+ + +
+ + + + diff --git a/public/base64-encoding b/public/base64-encoding new file mode 100644 index 0000000..232a987 --- /dev/null +++ b/public/base64-encoding @@ -0,0 +1,199 @@ + + + + + Go в примерах: Кодирование Base64 (Base64 Encoding) + + + + +
+

Go в примерах: Кодирование Base64 (Base64 Encoding)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go имеет встроенную поддержку base64 +кодирования и декодирования.

+ +
+ + +
+ + + +
package main
+
+ +
+

Этот синтаксис импортирует пакет encoding/base64 с +с алиасом b64, вместо названия по-умолчанию. Это +сэкономит нам немного места.

+ +
+ +
import (
+    b64 "encoding/base64"
+    "fmt"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Строка, которую мы будем кодировать/декодировать.

+ +
+ +
    data := "abc123!?$*&()'-=@~"
+
+ +
+

Go поддерживает оба стандарта и URL-совместимого +base64. Кодируем, используя стандартнай кодировщик. +Кодировщик требует []byte на входе, поэтому +мы конвертируем нашу строку.

+ +
+ +
    sEnc := b64.StdEncoding.EncodeToString([]byte(data))
+    fmt.Println(sEnc)
+
+ +
+

Декодирование может вернуть ошибку, которую можно +проверить, если вы не уверены в корректности +входных данных.

+ +
+ +
    sDec, _ := b64.StdEncoding.DecodeString(sEnc)
+    fmt.Println(string(sDec))
+    fmt.Println()
+
+ +
+

Это кодирование/декодирование использует +URL-совместимый base64 формат.

+ +
+ +
    uEnc := b64.URLEncoding.EncodeToString([]byte(data))
+    fmt.Println(uEnc)
+    uDec, _ := b64.URLEncoding.DecodeString(uEnc)
+    fmt.Println(string(uDec))
+}
+
+ +
+ + + + + + + + + + + + + +
+

Строка кодируется в слегка отличающиеся значения с +помощью стандартных и URL-совместимые base64 +(+ vs -), но они оба декодируются в исходную +строку по желанию.

+ +
+ +
$ go run base64-encoding.go
+YWJjMTIzIT8kKiYoKSctPUB+
+abc123!?$*&()'-=@~
+
+ +
+ + + +
YWJjMTIzIT8kKiYoKSctPUB-
+abc123!?$*&()'-=@~
+
+ +
+ + +

+ Следующий пример: Чтение файлов (Reading Files). +

+ + +
+ + + + diff --git a/public/channel-buffering b/public/channel-buffering new file mode 100644 index 0000000..6cbfdc6 --- /dev/null +++ b/public/channel-buffering @@ -0,0 +1,160 @@ + + + + + Go в примерах: Буферизированный канал (Channel Buffering) + + + + +
+

Go в примерах: Буферизированный канал (Channel Buffering)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

По умолчанию каналы не буферизованы, это означает, +что они будут принимать отправления (chan <-), только +если есть соответствующий прием (<- chan), готовый +принять отправленное значение. Буферизованные каналы +принимают ограниченное количество значений без +соответствующего приемника для этих значений.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Здесь мы создаем канал строк с буфером до 2 +значений.

+ +
+ +
    messages := make(chan string, 2)
+
+ +
+

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

+ +
+ +
    messages <- "buffered"
+    messages <- "channel"
+
+ +
+

Позже мы можем получить эти значения как обычно.

+ +
+ +
    fmt.Println(<-messages)
+    fmt.Println(<-messages)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run channel-buffering.go 
+buffered
+channel
+
+ +
+ + +

+ Следующий пример: Синхронизация канала (Channel Synchronization). +

+ + +
+ + + + diff --git a/public/channel-directions b/public/channel-directions new file mode 100644 index 0000000..11d92a8 --- /dev/null +++ b/public/channel-directions @@ -0,0 +1,152 @@ + + + + + Go в примерах: Направления канала (Channel Directions) + + + + +
+

Go в примерах: Направления канала (Channel Directions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Функция ping принимает канал только для отправки +значений. При попытке получения значений в этот канал +в процессе компиляции возниканет ошибка.

+ +
+ +
func ping(pings chan<- string, msg string) {
+    pings <- msg
+}
+
+ +
+

Функция pong принимает один канал для приема +(pings) и второй для отправки (pongs).

+ +
+ +
func pong(pings <-chan string, pongs chan<- string) {
+    msg := <-pings
+    pongs <- msg
+}
+
+ +
+ + + +
func main() {
+    pings := make(chan string, 1)
+    pongs := make(chan string, 1)
+    ping(pings, "passed message")
+    pong(pings, pongs)
+    fmt.Println(<-pongs)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run channel-directions.go
+passed message
+
+ +
+ + +

+ Следующий пример: Select. +

+ + +
+ + + + diff --git a/public/channel-synchronization b/public/channel-synchronization new file mode 100644 index 0000000..c7eadbc --- /dev/null +++ b/public/channel-synchronization @@ -0,0 +1,192 @@ + + + + + Go в примерах: Синхронизация канала (Channel Synchronization) + + + + +
+

Go в примерах: Синхронизация канала (Channel Synchronization)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+

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

+ +
+ +
func worker(done chan bool) {
+    fmt.Print("working...")
+    time.Sleep(time.Second)
+    fmt.Println("done")
+
+ +
+

Отправить значение, чтобы сказать что функция +выполнена успешно.

+ +
+ +
    done <- true
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Запустите воркера в горутине и передайте ему канал +для оповещения.

+ +
+ +
    done := make(chan bool, 1)
+    go worker(done)
+
+ +
+

Блокируйте, пока мы не получим уведомление от +воркера из канала.

+ +
+ +
    <-done
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run channel-synchronization.go      
+working...done                  
+
+ +
+

Если вы удалите строку <- done из этой программы, +программа закроется до того, как воркер даже +запустится.

+ +
+ + +
+ + +

+ Следующий пример: Направления канала (Channel Directions). +

+ + +
+ + + + diff --git a/public/channels b/public/channels new file mode 100644 index 0000000..f6be4e0 --- /dev/null +++ b/public/channels @@ -0,0 +1,175 @@ + + + + + Go в примерах: Каналы (Channels) + + + + +
+

Go в примерах: Каналы (Channels)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Создаем новый канал - make(chan val-type). +Каналы типизируются в зависимости от значений, +которые они передают.

+ +
+ +
    messages := make(chan string)
+
+ +
+

Отправьте значение в канал, используя channel <-. +Здесь мы отправляем "ping" в канал messages, +который мы сделали выше, из новой горутины.

+ +
+ +
    go func() { messages <- "ping" }()
+
+ +
+

Синтаксис <-channel читает из канала. Здесь +мы получим сообщение "ping", которое мы +отправили выше, и распечатаем его.

+ +
+ +
    msg := <-messages
+    fmt.Println(msg)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Когда мы запускаем программу, сообщение "ping" успешно +передается из одной горутины в другую по нашему каналу.

+ +
+ +
$ go run channels.go 
+ping
+
+ +
+

По-умолчанию, отправление и получение блокируются, +пока оба отправителя и получателя готовы. Это +свойство позволило нам ждать в конце нашей программы +сообщения "ping" без использования какой-либо +другой синхронизации.

+ +
+ + +
+ + +

+ Следующий пример: Буферизированный канал (Channel Buffering). +

+ + +
+ + + + diff --git a/public/clipboard.png b/public/clipboard.png new file mode 100644 index 0000000000000000000000000000000000000000..0e262fec70a6efb70c8c03c67e4cfea0b230d5ab GIT binary patch literal 488 zcmVP)vs0+u6@oUjF!il?f%*EGIz@kHuY0Jz-x!^TP`0I+j#4M3yOun`C$0GLY;0}N!> z@?HR!^uMdY?T0(;4FS(8K`+4e{$(p$r=i9GO#pFzR`vm!Q+6ka*jT(SNo?u|Lt!d6 zSGM3_C`@*F72plf0fhAVfD0h{U)v;(fF70L6Q}@Ds{#v|#T@yq_0~Ezo&p%OgcqtH ze?6R7A=SQhZwYS^XuznG2EkC6sp+&;0f49d3Xi}@mm2i7x*%siPzKUY8ptjfQgpvc zU|4PGLW39J38<u`lTp#J+Cizm8Ecyw8bkh1}(e_fNd33!{0 eZzG + + + + Go в примерах: Закрытие каналов (Closing Channels) + + + + +
+

Go в примерах: Закрытие каналов (Closing Channels)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

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

+ +
+ +
func main() {
+    jobs := make(chan int, 5)
+    done := make(chan bool)
+
+ +
+

Вот наш воркер. Он многократно получает из канала +jobs значения j, more := <-jobs. В этой специальной +форме получения с двумя значениями more значение +будет ложным, если jobs были закрыты, а все +значения в канале уже получены. Мы используем +это, чтобы уведомить о выполнении, когда мы +проработали все наши работы.

+ +
+ +
    go func() {
+        for {
+            j, more := <-jobs
+            if more {
+                fmt.Println("received job", j)
+            } else {
+                fmt.Println("received all jobs")
+                done <- true
+                return
+            }
+        }
+    }()
+
+ +
+

Отправляем 3 сообщения в канал jobs, и закрываем +его.

+ +
+ +
    for j := 1; j <= 3; j++ {
+        jobs <- j
+        fmt.Println("sent job", j)
+    }
+    close(jobs)
+    fmt.Println("sent all jobs")
+
+ +
+

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

+ +
+ +
    <-done
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run closing-channels.go 
+sent job 1
+received job 1
+sent job 2
+received job 2
+sent job 3
+received job 3
+sent all jobs
+received all jobs
+
+ +
+

Идея закрытых каналов естественно приводит нас к +следующему примеру: range по каналам.

+ +
+ + +
+ + +

+ Следующий пример: Перебор значений из каналов (Range over Channels). +

+ + +
+ + + + diff --git a/public/closures b/public/closures new file mode 100644 index 0000000..a2bc20c --- /dev/null +++ b/public/closures @@ -0,0 +1,197 @@ + + + + + Go в примерах: Замыкания (Closures) + + + + +
+

Go в примерах: Замыкания (Closures)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Эта функция intSeq возвращает другую функцию, которую +мы анонимно определяем в теле intSeq. Возвращенная +функция присваивается в переменную i, чтобы +сформировать замыкание.

+ +
+ +
func intSeq() func() int {
+    i := 0
+    return func() int {
+        i++
+        return i
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Мы вызываем intSeq, присваивая результат (функцию) +nextInt. Это значение функции фиксирует свое +собственное значение i, которое будет обновляться +каждый раз, когда мы вызываем nextInt.

+ +
+ +
    nextInt := intSeq()
+
+ +
+

Посмотрите, что происходит при вызове nextInt +несколько раз.

+ +
+ +
    fmt.Println(nextInt())
+    fmt.Println(nextInt())
+    fmt.Println(nextInt())
+
+ +
+

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

+ +
+ +
    newInts := intSeq()
+    fmt.Println(newInts())
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run closures.go
+1
+2
+3
+1
+
+ +
+

Последняя особенность функций, которые мы сейчас +рассмотрим, - это рекурсия.

+ +
+ + +
+ + +

+ Следующий пример: Рекурсия (Recursion). +

+ + +
+ + + + diff --git a/public/collection-functions b/public/collection-functions new file mode 100644 index 0000000..afc3d5a --- /dev/null +++ b/public/collection-functions @@ -0,0 +1,378 @@ + + + + + Go в примерах: Функции коллекции (Collection Functions) + + + + +
+

Go в примерах: Функции коллекции (Collection Functions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+

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

+ +
+ + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "strings"
+)
+
+ +
+

Возвращает первый индекс совпадения со строкой t или -1 +если совпадение не найдено.

+ +
+ +
func Index(vs []string, t string) int {
+    for i, v := range vs {
+        if v == t {
+            return i
+        }
+    }
+    return -1
+}
+
+ +
+

Возвращает true если строка t находится в срезе.

+ +
+ +
func Include(vs []string, t string) bool {
+    return Index(vs, t) >= 0
+}
+
+ +
+

Возвращает true если одна из строк в срезе +удовлетворяет условию f.

+ +
+ +
func Any(vs []string, f func(string) bool) bool {
+    for _, v := range vs {
+        if f(v) {
+            return true
+        }
+    }
+    return false
+}
+
+ +
+

Возвращает true если все из строк в срезе +удовлетворяют условие f.

+ +
+ +
func All(vs []string, f func(string) bool) bool {
+    for _, v := range vs {
+        if !f(v) {
+            return false
+        }
+    }
+    return true
+}
+
+ +
+

Возвращает новый срез, содержащий все строки в срезе, +которые удовлетворяют условие f.

+ +
+ +
func Filter(vs []string, f func(string) bool) []string {
+    vsf := make([]string, 0)
+    for _, v := range vs {
+        if f(v) {
+            vsf = append(vsf, v)
+        }
+    }
+    return vsf
+}
+
+ +
+

Возвращает новый срез, содержащий результаты выполнения +функции f с каждой строкой исходного слайса.

+ +
+ +
func Map(vs []string, f func(string) string) []string {
+    vsm := make([]string, len(vs))
+    for i, v := range vs {
+        vsm[i] = f(v)
+    }
+    return vsm
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Здесь мы пробуем различные функции коллекций.

+ +
+ +
    var strs = []string{"peach", "apple", "pear", "plum"}
+
+ +
+ + + +
    fmt.Println(Index(strs, "pear"))
+
+ +
+ + + +
    fmt.Println(Include(strs, "grape"))
+
+ +
+ + + +
    fmt.Println(Any(strs, func(v string) bool {
+        return strings.HasPrefix(v, "p")
+    }))
+
+ +
+ + + +
    fmt.Println(All(strs, func(v string) bool {
+        return strings.HasPrefix(v, "p")
+    }))
+
+ +
+ + + +
    fmt.Println(Filter(strs, func(v string) bool {
+        return strings.Contains(v, "e")
+    }))
+
+ +
+

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

+ +
+ +
    fmt.Println(Map(strs, strings.ToUpper))
+
+ +
+ + + +
}
+
+ +
+ + + + + + + + +
+ + + +
$ go run collection-functions.go 
+2
+false
+true
+false
+[peach apple pear]
+[PEACH APPLE PEAR PLUM]
+
+ +
+ + +

+ Следующий пример: Строковые функции (String Functions). +

+ + +
+ + + + diff --git a/public/command-line-arguments b/public/command-line-arguments new file mode 100644 index 0000000..988b8d7 --- /dev/null +++ b/public/command-line-arguments @@ -0,0 +1,181 @@ + + + + + Go в примерах: Аргументы командной строки (Command-Line Arguments) + + + + +
+

Go в примерах: Аргументы командной строки (Command-Line Arguments)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Аргументы командной строки +являются распространенным способом параметризации +выполнения программ. Например, go run hello.go +использует аргументы run и hello.go для программы +go.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

os.Args предоставляет доступ к необработанным +аргументам командной строки. Обратите внимание, +что первое значение в этом срезе - это путь к +программе, а os.Args [1:] содержит аргументы +программы.

+ +
+ +
    argsWithProg := os.Args
+    argsWithoutProg := os.Args[1:]
+
+ +
+

Вы можете получить отдельные аргументы с +обычной индексацией.

+ +
+ +
    arg := os.Args[3]
+
+ +
+ + + +
    fmt.Println(argsWithProg)
+    fmt.Println(argsWithoutProg)
+    fmt.Println(arg)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Чтобы поэкспериментировать с аргументами командной +строки, лучше сначала создать двоичный файл с +помощью go build.

+ +
+ +
$ go build command-line-arguments.go
+$ ./command-line-arguments a b c d
+[./command-line-arguments a b c d]       
+[a b c d]
+c
+
+ +
+

Далее мы рассмотрим более сложную обработку командной +строки с флагами.

+ +
+ + +
+ + +

+ Следующий пример: Флаги командной строки (Command-Line Flags). +

+ + +
+ + + + diff --git a/public/command-line-flags b/public/command-line-flags new file mode 100644 index 0000000..2263aea --- /dev/null +++ b/public/command-line-flags @@ -0,0 +1,322 @@ + + + + + Go в примерах: Флаги командной строки (Command-Line Flags) + + + + +
+

Go в примерах: Флаги командной строки (Command-Line Flags)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Флаги командной строки +являются распространенным способом задания параметров +для программ командной строки. Например, в wc -l - -l +является флагом командной строки.

+ +
+ + +
+ + + +
package main
+
+ +
+

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

+ +
+ +
import (
+    "flag"
+    "fmt"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Основные объявления флагов доступны для строковых, +целочисленных и логических параметров. Здесь мы +объявляем строковой флаг word со значением по +умолчанию "foo" и кратким описанием. Функция +flag.String возвращает строковый указатель (не +строковое значение); мы увидим, как использовать +этот указатель ниже.

+ +
+ +
    wordPtr := flag.String("word", "foo", "a string")
+
+ +
+

Объявляем флаги numb и fork, используя тот же +подход, что и выше.

+ +
+ +
    numbPtr := flag.Int("numb", 42, "an int")
+    boolPtr := flag.Bool("fork", false, "a bool")
+
+ +
+

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

+ +
+ +
    var svar string
+    flag.StringVar(&svar, "svar", "bar", "a string var")
+
+ +
+

Как только все флаги объявлены, вызовите flag.Parse(), +чтобы выполнить парсинг командной строки.

+ +
+ +
    flag.Parse()
+
+ +
+

Здесь мы просто выведем результат парсинга и все +введеные аргументы. Обратите внимание, что нам +нужно разыменовать указатели, например, с +помощью *wordPtr, чтобы получить фактические +значения.

+ +
+ +
    fmt.Println("word:", *wordPtr)
+    fmt.Println("numb:", *numbPtr)
+    fmt.Println("fork:", *boolPtr)
+    fmt.Println("svar:", svar)
+    fmt.Println("tail:", flag.Args())
+}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ +
$ go build command-line-flags.go
+
+ +
+

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

+ +
+ +
$ ./command-line-flags -word=opt -numb=7 -fork -svar=flag
+word: opt
+numb: 7
+fork: true
+svar: flag
+tail: []
+
+ +
+

Обратите внимание, что если вы опустите флаги, они +автоматически примут свои значения по умолчанию.

+ +
+ +
$ ./command-line-flags -word=opt
+word: opt
+numb: 42
+fork: false
+svar: bar
+tail: []
+
+ +
+

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

+ +
+ +
$ ./command-line-flags -word=opt a1 a2 a3
+word: opt
+...
+tail: [a1 a2 a3]
+
+ +
+

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

+ +
+ +
$ ./command-line-flags -word=opt a1 a2 a3 -numb=7
+word: opt
+numb: 42
+fork: false
+svar: bar
+tail: [a1 a2 a3 -numb=7]
+
+ +
+

Используйте флаги -h или --help, чтобы получить +автоматически сгенерированный текст справки для +программы командной строки.

+ +
+ +
$ ./command-line-flags -h
+Usage of ./command-line-flags:
+  -fork=false: a bool
+  -numb=42: an int
+  -svar="bar": a string var
+  -word="foo": a string
+
+ +
+

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

+ +
+ +
$ ./command-line-flags -wat
+flag provided but not defined: -wat
+Usage of ./command-line-flags:
+...
+
+ +
+ + +

+ Следующий пример: Подкоманды командной строки (Command-Line Subcommands). +

+ + +
+ + + + diff --git a/public/command-line-subcommands b/public/command-line-subcommands new file mode 100644 index 0000000..e618477 --- /dev/null +++ b/public/command-line-subcommands @@ -0,0 +1,270 @@ + + + + + Go в примерах: Подкоманды командной строки (Command-Line Subcommands) + + + + +
+

Go в примерах: Подкоманды командной строки (Command-Line Subcommands)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Некоторые инструменты командной строки, такие как go +или git, имеют много подкоманд, каждая со своим +собственным набором флагов. Например, go build и +go get - это две разные подкоманды инструмента go. +Пакет flag позволяет нам легко определять простые +подкоманды, которые имеют свои собственные флаги.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "flag"
+    "fmt"
+    "os"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)
+    fooEnable := fooCmd.Bool("enable", false, "enable")
+    fooName := fooCmd.String("name", "", "name")
+
+ +
+

Для другой подкоманды мы можем определить другие +флаги.

+ +
+ +
    barCmd := flag.NewFlagSet("bar", flag.ExitOnError)
+    barLevel := barCmd.Int("level", 0, "level")
+
+ +
+

Подкоманда ожидается в качестве первого аргумента +программы.

+ +
+ +
    if len(os.Args) < 2 {
+        fmt.Println("expected 'foo' or 'bar' subcommands")
+        os.Exit(1)
+    }
+
+ +
+

Проверяем, какая подкоманда вызвана.

+ +
+ +
    switch os.Args[1] {
+
+ +
+

Для каждой подкоманды мы анализируем ее собственные +флаги и имеем доступ к аргументам.

+ +
+ +
    case "foo":
+        fooCmd.Parse(os.Args[2:])
+        fmt.Println("subcommand 'foo'")
+        fmt.Println("  enable:", *fooEnable)
+        fmt.Println("  name:", *fooName)
+        fmt.Println("  tail:", fooCmd.Args())
+    case "bar":
+        barCmd.Parse(os.Args[2:])
+        fmt.Println("subcommand 'bar'")
+        fmt.Println("  level:", *barLevel)
+        fmt.Println("  tail:", barCmd.Args())
+    default:
+        fmt.Println("expected 'foo' or 'bar' subcommands")
+        os.Exit(1)
+    }
+}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
$ go build command-line-subcommands.go
+
+ +
+

Первый вызов подкоманды foo.

+ +
+ +
$ ./command-line-subcommands foo -enable -name=joe a1 a2
+subcommand 'foo'
+  enable: true
+  name: joe
+  tail: [a1 a2]
+
+ +
+

Теперь пробуем bar.

+ +
+ +
$ ./command-line-subcommands bar -level 8 a1
+subcommand 'bar'
+  level: 8
+  tail: [a1]
+
+ +
+

Но bar не может принимать флаги определенные для foo.

+ +
+ +
$ ./command-line-subcommands bar -enable a1
+flag provided but not defined: -enable
+Usage of bar:
+  -level int
+        level
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Переменные среды (Environment Variables). +

+ + +
+ + + + diff --git a/public/constants b/public/constants new file mode 100644 index 0000000..6e28a5e --- /dev/null +++ b/public/constants @@ -0,0 +1,190 @@ + + + + + Go в примерах: Константы (Constants) + + + + +
+

Go в примерах: Константы (Constants)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В Go константы могут принимать значения следующих типов: +строки, числа и логические значения

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "math"
+)
+
+ +
+

Для объявления константы используется ключевое слово const.

+ +
+ +
const s string = "constant"
+
+ +
+ + + +
func main() {
+    fmt.Println(s)
+
+ +
+

Оператор const может использоваться везде, где может +быть использован оператор var.

+ +
+ +
    const n = 500000000
+
+ +
+

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

+ +
+ +
    const d = 3e20 / n
+    fmt.Println(d)
+
+ +
+

Числовая константа не имеет типа до тех пор, +пока ей не присвоен, например, при явном преобразовании.

+ +
+ +
    fmt.Println(int64(d))
+
+ +
+

Число может использоваться в контексте, который требует +его, например, присваивание переменной или вызов +функции. Например, здесь math.Sin ожидает +float64.

+ +
+ +
    fmt.Println(math.Sin(n))
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run constant.go 
+constant
+6e+11
+600000000000
+-0.28470407323754404
+
+ +
+ + +

+ Следующий пример: Цикл For. +

+ + +
+ + + + diff --git a/public/defer b/public/defer new file mode 100644 index 0000000..2beb109 --- /dev/null +++ b/public/defer @@ -0,0 +1,220 @@ + + + + + Go в примерах: Defer + + + + +
+

Go в примерах: Defer

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+)
+
+ +
+

Предположим, мы хотим создать файл, записать в него, +а затем закрыть, когда закончим. Вот как нам поможет +defer.

+ +
+ +
func main() {
+
+ +
+

Сразу же после получения объекта файла с помощью +createFile мы откладываем закрытие этого файла +с помощью closeFile. Она будет выполнена в +конце включающей функции (main) после завершения +writeFile.

+ +
+ +
    f := createFile("/tmp/defer.txt")
+    defer closeFile(f)
+    writeFile(f)
+}
+
+ +
+ + + +
func createFile(p string) *os.File {
+    fmt.Println("creating")
+    f, err := os.Create(p)
+    if err != nil {
+        panic(err)
+    }
+    return f
+}
+
+ +
+ + + +
func writeFile(f *os.File) {
+    fmt.Println("writing")
+    fmt.Fprintln(f, "data")
+
+ +
+ + + +
}
+
+ +
+

Важно проверять наличие ошибок при закрытии файла, +даже в отложенной функции.

+ +
+ +
func closeFile(f *os.File) {
+    fmt.Println("closing")
+    err := f.Close()
+
+ +
+ + + +
    if err != nil {
+        fmt.Fprintf(os.Stderr, "error: %v\n", err)
+        os.Exit(1)
+    }
+}
+
+ +
+ + + + + + + + +
+

Запуск программы подтверждает, что файл закрыт +после записи.

+ +
+ +
$ go run defer.go
+creating
+writing
+closing
+
+ +
+ + +

+ Следующий пример: Функции коллекции (Collection Functions). +

+ + +
+ + + + diff --git a/public/directories b/public/directories new file mode 100644 index 0000000..a987599 --- /dev/null +++ b/public/directories @@ -0,0 +1,360 @@ + + + + + Go в примерах: Директории (Directories) + + + + +
+

Go в примерах: Директории (Directories)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "io/ioutil"
+    "os"
+    "path/filepath"
+)
+
+ +
+ + + +
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Создадим новую суб-директорию в текущей рабочей +папке.

+ +
+ +
    err := os.Mkdir("subdir", 0755)
+    check(err)
+
+ +
+

Когда мы создаем временную директорию, хорошим +тоном является удалить ее через defer. +os.RemoveAll удалит директорию и все, что в ней +находится (по аналогии с rm -rf).

+ +
+ +
    defer os.RemoveAll("subdir")
+
+ +
+

Функция-помощник для создания нового пустого файла.

+ +
+ +
    createEmptyFile := func(name string) {
+        d := []byte("")
+        check(ioutil.WriteFile(name, d, 0644))
+    }
+
+ +
+ + + +
    createEmptyFile("subdir/file1")
+
+ +
+

Мы можем создать иерархию из директорий, включая все +родительские, с помощью MkdirAll. Это является аналогом +команды mkdir -p.

+ +
+ +
    err = os.MkdirAll("subdir/parent/child", 0755)
+    check(err)
+
+ +
+ + + +
    createEmptyFile("subdir/parent/file2")
+    createEmptyFile("subdir/parent/file3")
+    createEmptyFile("subdir/parent/child/file4")
+
+ +
+

ReadDir перечисляет содержимое каталогов, +возвращая срез объектов os.FileInfo.

+ +
+ +
    c, err := ioutil.ReadDir("subdir/parent")
+    check(err)
+
+ +
+ + + +
    fmt.Println("Listing subdir/parent")
+    for _, entry := range c {
+        fmt.Println(" ", entry.Name(), entry.IsDir())
+    }
+
+ +
+

Chdir позволяет изменить текущую рабочую +директорию, по аналогии с cd.

+ +
+ +
    err = os.Chdir("subdir/parent/child")
+    check(err)
+
+ +
+

Теперь мы увидим содержимое директории +subdir/parent/child, когда запросим листинг +текущей директории.

+ +
+ +
    c, err = ioutil.ReadDir(".")
+    check(err)
+
+ +
+ + + +
    fmt.Println("Listing subdir/parent/child")
+    for _, entry := range c {
+        fmt.Println(" ", entry.Name(), entry.IsDir())
+    }
+
+ +
+

Вернемся в начало

+ +
+ +
    err = os.Chdir("../../..")
+    check(err)
+
+ +
+

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

+ +
+ +
    fmt.Println("Visiting subdir")
+    err = filepath.Walk("subdir", visit)
+}
+
+ +
+

visit вызывается для каждого найденного элемента в filepath.Walk.

+ +
+ +
func visit(p string, info os.FileInfo, err error) error {
+    if err != nil {
+        return err
+    }
+    fmt.Println(" ", p, info.IsDir())
+    return nil
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run directories.go
+Listing subdir/parent
+  child true
+  file2 false
+  file3 false
+Listing subdir/parent/child
+  file4 false
+Visiting subdir
+  subdir true
+  subdir/file1 false
+  subdir/parent true
+  subdir/parent/child true
+  subdir/parent/child/file4 false
+  subdir/parent/file2 false
+  subdir/parent/file3 false
+
+ +
+ + +

+ Следующий пример: Временные файлы и директории (Temporary Files and Directories). +

+ + +
+ + + + diff --git a/public/environment-variables b/public/environment-variables new file mode 100644 index 0000000..2ff35bd --- /dev/null +++ b/public/environment-variables @@ -0,0 +1,194 @@ + + + + + Go в примерах: Переменные среды (Environment Variables) + + + + +
+

Go в примерах: Переменные среды (Environment Variables)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Переменные среды (или переменные окружения) +- это универсальный механизм передачи информации о конфигурации +в программы Unix. Давайте +посмотрим, как устанавливать, получать и перечислять переменные +среды.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+    "strings"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Чтобы установить пару ключ/значение, используйте +os.Setenv. Чтобы получить значение для ключа, +используйте os.Getenv. Это вернет пустую строку, +если ключ не присутствует в среде.

+ +
+ +
    os.Setenv("FOO", "1")
+    fmt.Println("FOO:", os.Getenv("FOO"))
+    fmt.Println("BAR:", os.Getenv("BAR"))
+
+ +
+

Используйте os.Environ для вывода списка всех пар +ключ/значение в среде. Это возвращает спез строк в +формате KEY=value. Вы можете использовать strings.Split, +чтобы получить ключ и значение. Здесь мы печатаем +все ключи.

+ +
+ +
    fmt.Println()
+    for _, e := range os.Environ() {
+        pair := strings.Split(e, "=")
+        fmt.Println(pair[0])
+    }
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Запуск программы показывает, что мы выбираем значение +для FOO, которое мы установили в программе, но BAR +пуст.

+ +
+ +
$ go run environment-variables.go
+FOO: 1
+BAR: 
+
+ +
+

Список ключей в среде будет зависеть от вашей системы.

+ +
+ +
TERM_PROGRAM
+PATH
+SHELL
+...
+
+ +
+

Если мы сначала установим BAR в среде, запущенная +программа использует это значение.

+ +
+ +
$ BAR=2 go run environment-variables.go
+FOO: 1
+BAR: 2
+...
+
+ +
+ + +

+ Следующий пример: HTTP клиенты (HTTP Clients). +

+ + +
+ + + + diff --git a/public/epoch b/public/epoch new file mode 100644 index 0000000..ddd321a --- /dev/null +++ b/public/epoch @@ -0,0 +1,183 @@ + + + + + Go в примерах: Epoch + + + + +
+

Go в примерах: Epoch

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Общим требованием в программах является получение +количества секунд, миллисекунд или наносекунд в Unixtime. +Вот как это сделать в Go.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Используйте time.Now с Unix или UnixNano, +чтобы получить время, прошедшее с начала эпохи Unix в +секундах или наносекундах соответственно.

+ +
+ +
    now := time.Now()
+    secs := now.Unix()
+    nanos := now.UnixNano()
+    fmt.Println(now)
+
+ +
+

Обратите внимание, что UnixMillis не существует, +поэтому, чтобы получить миллисекунды с начала эпохи Unix, +вам нужно будет вручную делить наносекунды.

+ +
+ +
    millis := nanos / 1000000
+    fmt.Println(secs)
+    fmt.Println(millis)
+    fmt.Println(nanos)
+
+ +
+

Вы также можете конвертировать целые секунды или наносекунды +Unixtime в соответствующее время.

+ +
+ +
    fmt.Println(time.Unix(secs, 0))
+    fmt.Println(time.Unix(0, nanos))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run epoch.go 
+2012-10-31 16:13:58.292387 +0000 UTC
+1351700038
+1351700038292
+1351700038292387000
+2012-10-31 16:13:58 +0000 UTC
+2012-10-31 16:13:58.292387 +0000 UTC
+
+ +
+

Далее мы рассмотрим еще одну задачу, связанную со +временем: разбор и форматирование времени.

+ +
+ + +
+ + +

+ Следующий пример: Форматирование времени (Time Formatting / Parsing). +

+ + +
+ + + + diff --git a/public/errors b/public/errors new file mode 100644 index 0000000..e4a84e5 --- /dev/null +++ b/public/errors @@ -0,0 +1,305 @@ + + + + + Go в примерах: Ошибки (Errors) + + + + +
+

Go в примерах: Ошибки (Errors)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "errors"
+    "fmt"
+)
+
+ +
+

По соглашению, ошибки - это последнее возвращаемое +значение с типом error в стандартной реализации.

+ +
+ +
func f1(arg int) (int, error) {
+    if arg == 42 {
+
+ +
+

errors.New создает стандартную ошибку с +указаннным сообщением

+ +
+ +
        return -1, errors.New("can't work with 42")
+
+ +
+ + + +
    }
+
+ +
+

Значение nil в поле ошибки, говорит о том, что +ошибок нет.

+ +
+ +
    return arg + 3, nil
+}
+
+ +
+

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

+ +
+ +
type argError struct {
+    arg  int
+    prob string
+}
+
+ +
+ + + +
func (e *argError) Error() string {
+    return fmt.Sprintf("%d - %s", e.arg, e.prob)
+}
+
+ +
+ + + +
func f2(arg int) (int, error) {
+    if arg == 42 {
+
+ +
+

В этом случае мы используем синтаксис &argError +для создания новой структуры, предоставляя +значения для двух полей arg и prob.

+ +
+ +
        return -1, &argError{arg, "can't work with it"}
+    }
+    return arg + 3, nil
+}
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    for _, i := range []int{7, 42} {
+        if r, e := f1(i); e != nil {
+            fmt.Println("f1 failed:", e)
+        } else {
+            fmt.Println("f1 worked:", r)
+        }
+    }
+    for _, i := range []int{7, 42} {
+        if r, e := f2(i); e != nil {
+            fmt.Println("f2 failed:", e)
+        } else {
+            fmt.Println("f2 worked:", r)
+        }
+    }
+
+ +
+

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

+ +
+ +
    _, e := f2(42)
+    if ae, ok := e.(*argError); ok {
+        fmt.Println(ae.arg)
+        fmt.Println(ae.prob)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run errors.go
+f1 worked: 10
+f1 failed: can't work with 42
+f2 worked: 10
+f2 failed: 42 - can't work with it
+42
+can't work with it
+
+ +
+

Посмотрите эту статью +в блоге Go для более подробной информации об ошибках.

+ +
+ + +
+ + +

+ Следующий пример: Горутины (Goroutines). +

+ + +
+ + + + diff --git a/public/execing-processes b/public/execing-processes new file mode 100644 index 0000000..18b0fc5 --- /dev/null +++ b/public/execing-processes @@ -0,0 +1,209 @@ + + + + + Go в примерах: Исполняющие процессы (Exec'ing Processes) + + + + +
+

Go в примерах: Исполняющие процессы (Exec'ing Processes)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "os"
+    "os/exec"
+    "syscall"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Для нашего примера мы выполним ls. Go требует +абсолютного пути к двоичному файлу, который мы +хотим выполнить, поэтому мы используем exec.LookPath, +чтобы найти его (вероятно, /bin/ls).

+ +
+ +
    binary, lookErr := exec.LookPath("ls")
+    if lookErr != nil {
+        panic(lookErr)
+    }
+
+ +
+

Exec требует аргументы в форме среза +(в сочетании с одной большой строкой). Мы используем в ls +несколько общих аргументов. Обратите внимание, что +первым аргументом должно быть имя программы.

+ +
+ +
    args := []string{"ls", "-a", "-l", "-h"}
+
+ +
+

Exec также нужен набор переменных среды +для использования. Здесь мы просто предоставляем +нашу текущую среду.

+ +
+ +
    env := os.Environ()
+
+ +
+

Вот фактический вызов syscall.Exec. Если этот вызов +будет успешным, выполнение нашего процесса на этом +закончится и будет заменено процессом /bin/ls -a -l -h. +В случае ошибки мы получим возвращаемое значение.

+ +
+ +
    execErr := syscall.Exec(binary, args, env)
+    if execErr != nil {
+        panic(execErr)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

When we run our program it is replaced by ls.

+ +
+ +
$ go run execing-processes.go
+total 16
+drwxr-xr-x  4 mark 136B Oct 3 16:29 .
+drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
+-rw-r--r--  1 mark 1.3K Oct 3 16:28 execing-processes.go
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Сигналы (Signals). +

+ + +
+ + + + diff --git a/public/exit b/public/exit new file mode 100644 index 0000000..3611088 --- /dev/null +++ b/public/exit @@ -0,0 +1,180 @@ + + + + + Go в примерах: Выход (Exit) + + + + +
+

Go в примерах: Выход (Exit)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Используйте os.Exit для немедленного выхода с +полученныем статусом.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

defer не будет запускаться при использовании +os.Exit, поэтому этот fmt.Println никогда не +будет вызываться.

+ +
+ +
    defer fmt.Println("!")
+
+ +
+

Выход со статусом 3.

+ +
+ +
    os.Exit(3)
+}
+
+ +
+

Обратите внимание, что в отличие, например, от C, +Go не использует целочисленное возвращаемое значение +из main, чтобы указать состояние выхода. Если +вы хотите выйти с ненулевым статусом, вы должны +использовать os.Exit.

+ +
+ + +
+ + + + + + + + + + + + + + + + + + +
+

Если вы запустите exit.go с помощью go run, +выход будет выбран go и напечатан.

+ +
+ +
$ go run exit.go
+exit status 3
+
+ +
+

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

+ +
+ +
$ go build exit.go
+$ ./exit
+$ echo $?
+3
+
+ +
+

Обратите внимание, что ! из нашей программы +никогда не был напечатан.

+ +
+ + +
+ + + +
+ + + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..efa34a3abf06e01ed3456933419b0560cad9fc56 GIT binary patch literal 71518 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 + + + + Go в примерах: Пути к файлам (File Paths) + + + + +
+

Go в примерах: Пути к файлам (File Paths)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Пакет filepath предоставляет функции для разбора и +создания путей к файлам способом, который переносим +между операционными системами; например, dir/file в +Linux против dir\file в Windows.

+ +
+ +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "path/filepath"
+    "strings"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    p := filepath.Join("dir1", "dir2", "filename")
+    fmt.Println("p:", p)
+
+ +
+

Вы должны всегда использовать Join вместо ручного +объединения с помощью слешей / или \. В дополнение +к обеспечению переносимости, Join также нормализует +пути, удаляя лишние разделители.

+ +
+ +
    fmt.Println(filepath.Join("dir1//", "filename"))
+    fmt.Println(filepath.Join("dir1/../dir1", "filename"))
+
+ +
+

Dir и Base могут использоваться для разделения +пути к каталогу и файлу. В качестве альтернативы, +Split вернет оба в одном вызове.

+ +
+ +
    fmt.Println("Dir(p):", filepath.Dir(p))
+    fmt.Println("Base(p):", filepath.Base(p))
+
+ +
+

Можно проверить является ли путь абсолютным.

+ +
+ +
    fmt.Println(filepath.IsAbs("dir/file"))
+    fmt.Println(filepath.IsAbs("/dir/file"))
+
+ +
+ + + +
    filename := "config.json"
+
+ +
+

Некоторые имена файлов имеют расширения, следующие +за точкой. Мы можем получить расширение из таких +имен с помощью Ext.

+ +
+ +
    ext := filepath.Ext(filename)
+    fmt.Println(ext)
+
+ +
+

Чтобы найти имя файла с удаленным расширением, +используйте strings.TrimSuffix.

+ +
+ +
    fmt.Println(strings.TrimSuffix(filename, ext))
+
+ +
+

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

+ +
+ +
    rel, err := filepath.Rel("a/b", "a/b/t/file")
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println(rel)
+
+ +
+ + + +
    rel, err = filepath.Rel("a/b", "a/c/t/file")
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println(rel)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run file-paths.go
+p: dir1/dir2/filename
+dir1/filename
+dir1/filename
+Dir(p): dir1/dir2
+Base(p): filename
+false
+true
+.json
+config
+t/file
+../c/t/file
+
+ +
+ + +

+ Следующий пример: Директории (Directories). +

+ + +
+ + + + diff --git a/public/for b/public/for new file mode 100644 index 0000000..975d088 --- /dev/null +++ b/public/for @@ -0,0 +1,202 @@ + + + + + Go в примерах: Цикл For + + + + +
+

Go в примерах: Цикл For

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

for - это единственный цикл доступный в Go. +Три стандартных примера использования for

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Стандартный тип с единственным условием

+ +
+ +
    i := 1
+    for i <= 3 {
+        fmt.Println(i)
+        i = i + 1
+    }
+
+ +
+

Классическая инициализация/условие/выражение после for

+ +
+ +
    for j := 7; j <= 9; j++ {
+        fmt.Println(j)
+    }
+
+ +
+

for без условия будет выполняться бесконечно +пока не выполнится break (выход из цикла) или +return, который завершит функцию с циклом

+ +
+ +
    for {
+        fmt.Println("loop")
+        break
+    }
+
+ +
+

Так же Вы можете использовать continue для +немедленного перехода к следующей итерации цикла

+ +
+ +
    for n := 0; n <= 5; n++ {
+        if n%2 == 0 {
+            continue
+        }
+        fmt.Println(n)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run for.go
+1
+2
+3
+7
+8
+9
+loop
+1
+3
+5
+
+ +
+

We’ll see some other for forms later when we look at +range statements, channels, and other data +structures.

+ +
+ + +
+ + +

+ Следующий пример: If/Else. +

+ + +
+ + + + diff --git a/public/functions b/public/functions new file mode 100644 index 0000000..ca5cf19 --- /dev/null +++ b/public/functions @@ -0,0 +1,201 @@ + + + + + Go в примерах: Функции (Functions) + + + + +
+

Go в примерах: Функции (Functions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Функции это сердце языка Go. Мы посмотрим +использование функций на нескольих примерах.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

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

+ +
+ +
func plus(a int, b int) int {
+
+ +
+

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

+ +
+ +
    return a + b
+}
+
+ +
+

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

+ +
+ +
func plusPlus(a, b, c int) int {
+    return a + b + c
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Вызов функции осуществялется через запись +функция(аргументы).

+ +
+ +
    res := plus(1, 2)
+    fmt.Println("1+2 =", res)
+
+ +
+ + + +
    res = plusPlus(1, 2, 3)
+    fmt.Println("1+2+3 =", res)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run functions.go 
+1+2 = 3
+1+2+3 = 6
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Функции с множественным возвратом (Multiple Return Values). +

+ + +
+ + + + diff --git a/public/goroutines b/public/goroutines new file mode 100644 index 0000000..0679213 --- /dev/null +++ b/public/goroutines @@ -0,0 +1,214 @@ + + + + + Go в примерах: Горутины (Goroutines) + + + + +
+

Go в примерах: Горутины (Goroutines)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Горутины - это легковесный тред.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func f(from string) {
+    for i := 0; i < 3; i++ {
+        fmt.Println(from, ":", i)
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Предположим, у нас есть вызов функции f(s). Вот +как мы бы вызвали её обычным способом, запустив +синхронно.

+ +
+ +
    f("direct")
+
+ +
+

Чтобы вызвать эту функцию в горутине, используйте +go f(s). Эта новая горутина будет выполняться +одновременно с вызывающей фукнцией.

+ +
+ +
    go f("goroutine")
+
+ +
+

Вы так же можете вызывать анонимные функции в +горутнах.

+ +
+ +
    go func(msg string) {
+        fmt.Println(msg)
+    }("going")
+
+ +
+

Наши две функции теперь выполняются асинхронно в +отдельных горутинах. Дождитесь их окончания (для +более надежного подхода используйте WaitGroup).

+ +
+ +
    time.Sleep(time.Second)
+    fmt.Println("done")
+}
+
+ +
+ + + + + + + + + + + + + +
+

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

+ +
+ +
$ go run goroutines.go
+direct : 0
+direct : 1
+direct : 2
+goroutine : 0
+going
+goroutine : 1
+goroutine : 2
+done
+
+ +
+

Далее мы рассмотрим дополнение к горутинам в +параллельных программах Go: каналы.

+ +
+ + +
+ + +

+ Следующий пример: Каналы (Channels). +

+ + +
+ + + + diff --git a/public/hello-world b/public/hello-world new file mode 100644 index 0000000..67c1c82 --- /dev/null +++ b/public/hello-world @@ -0,0 +1,142 @@ + + + + + Go в примерах: Hello World + + + + +
+

Go в примерах: Hello World

+ + + + + + + + + + + + + + + + + + +
+

Наша первая программа напечатает классическое сообщение “hello world” +Полный код.

+ +
+ +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+    fmt.Println("hello world")
+}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+

To run the program, put the code in hello-world.go and +use go run.

+ +
+ +
$ go run hello-world.go
+hello world
+
+ +
+

Sometimes we’ll want to build our programs into +binaries. We can do this using go build.

+ +
+ +
$ go build hello-world.go
+$ ls
+hello-world    hello-world.go
+
+ +
+

We can then execute the built binary directly.

+ +
+ +
$ ./hello-world
+hello world
+
+ +
+

Now that we can run and build basic Go programs, let’s +learn more about the language.

+ +
+ + +
+ + +

+ Следующий пример: Типы данных (Values). +

+ + +
+ + + + diff --git a/public/http-clients b/public/http-clients new file mode 100644 index 0000000..ebff089 --- /dev/null +++ b/public/http-clients @@ -0,0 +1,175 @@ + + + + + Go в примерах: HTTP клиенты (HTTP Clients) + + + + +
+

Go в примерах: HTTP клиенты (HTTP Clients)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Стандартная библиотека Go поставляется с отличной +поддержкой клиентов и серверов HTTP в пакете net/http. +В этом примере мы будем использовать его для +простых HTTP-запросов.

+ +
+ +
package main
+
+ +
+ + + +
import (
+    "bufio"
+    "fmt"
+    "net/http"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Отправьте HTTP-запрос GET на сервер. http.Get - это +удобный способ создания объекта http.Client и вызова +его метода Get; он использует объект http.DefaultClient, +который имеет полезные настройки по умолчанию.

+ +
+ +
    resp, err := http.Get("http://gobyexample.com")
+    if err != nil {
+        panic(err)
+    }
+    defer resp.Body.Close()
+
+ +
+

Выведем статус http-ответа.

+ +
+ +
    fmt.Println("Response status:", resp.Status)
+
+ +
+

Выведем первые 5 строк тела ответа.

+ +
+ +
    scanner := bufio.NewScanner(resp.Body)
+    for i := 0; scanner.Scan() && i < 5; i++ {
+        fmt.Println(scanner.Text())
+    }
+
+ +
+ + + +
    if err := scanner.Err(); err != nil {
+        panic(err)
+    }
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run http-clients.go
+Response status: 200 OK
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Go by Example</title>
+
+ +
+ + +

+ Следующий пример: HTTP серверы (HTTP Servers). +

+ + +
+ + + + diff --git a/public/http-servers b/public/http-servers new file mode 100644 index 0000000..4af4f3a --- /dev/null +++ b/public/http-servers @@ -0,0 +1,218 @@ + + + + + Go в примерах: HTTP серверы (HTTP Servers) + + + + +
+

Go в примерах: HTTP серверы (HTTP Servers)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Написание базового HTTP сервера очень легкореализуемо +с пакетом net/http.

+ +
+ +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "net/http"
+)
+
+ +
+

Фундаментальная концепция серверов net/http - это +обработчики. Обработчик - это объект, реализующий +интерфейс http.Handler. Распространенным способом +написания обработчика является использование адаптера +http.HandlerFunc для функций с соответствующей +подписью.

+ +
+ +
func hello(w http.ResponseWriter, req *http.Request) {
+
+ +
+

Функции, выполняющие функции обработчиков, принимают +в качестве аргументов http.ResponseWriter и +http.Request. Response writer используется для +наполнения HTTP-ответа. Здесь наш простой ответ +“hello\n”.

+ +
+ +
    fmt.Fprintf(w, "hello\n")
+}
+
+ +
+ + + +
func headers(w http.ResponseWriter, req *http.Request) {
+
+ +
+

Этот обработчик делает что-то более сложное, +читая все заголовки HTTP-запроса и вставляя их в +тело ответа.

+ +
+ +
    for name, headers := range req.Header {
+        for _, h := range headers {
+            fmt.Fprintf(w, "%v: %v\n", name, h)
+        }
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Мы регистрируем наши обработчики на сервере, +используя удобную функцию http.HandleFunc. Она +устанавливает маршрут по умолчанию в пакете +net/http и принимает функцию в качестве аргумента.

+ +
+ +
    http.HandleFunc("/hello", hello)
+    http.HandleFunc("/headers", headers)
+
+ +
+

Наконец, мы вызываем ListenAndServe с портом и +обработчиком. nil говорит использовать только что +настроенный маршрутизатор по умолчанию.

+ +
+ +
    http.ListenAndServe(":8090", nil)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Запускаем сервер в фоне.

+ +
+ +
$ go run http-servers.go &
+
+ +
+

Делаем запрос по адресу /hello.

+ +
+ +
$ curl localhost:8090/hello
+hello
+
+ +
+ + +

+ Следующий пример: Порождающие процессы (Spawning Processes). +

+ + +
+ + + + diff --git a/public/if-else b/public/if-else new file mode 100644 index 0000000..fc7514b --- /dev/null +++ b/public/if-else @@ -0,0 +1,191 @@ + + + + + Go в примерах: If/Else + + + + +
+

Go в примерах: If/Else

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Условные операторы if иelse в Go +выглядят достаточно стандартно

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Стандартное использование

+ +
+ +
    if 7%2 == 0 {
+        fmt.Println("7 is even")
+    } else {
+        fmt.Println("7 is odd")
+    }
+
+ +
+

Вы можете использовать блоке if без блока else.

+ +
+ +
    if 8%4 == 0 {
+        fmt.Println("8 is divisible by 4")
+    }
+
+ +
+

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

+ +
+ +
    if num := 9; num < 0 {
+        fmt.Println(num, "is negative")
+    } else if num < 10 {
+        fmt.Println(num, "has 1 digit")
+    } else {
+        fmt.Println(num, "has multiple digits")
+    }
+}
+
+ +
+

Имейте ввиду, что в Go не надо использовать скобки в условии, +но блок необходимо заключать в фигурные скобки

+ +
+ + +
+ + + + + + + + + + + + + +
+ + + +
$ go run if-else.go 
+7 is odd
+8 is divisible by 4
+9 has 1 digit
+
+ +
+

There is no ternary if +in Go, so you’ll need to use a full if statement even +for basic conditions.

+ +
+ + +
+ + +

+ Следующий пример: Switch. +

+ + +
+ + + + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..9bce2be --- /dev/null +++ b/public/index.html @@ -0,0 +1,182 @@ + + + + + Go в примерах + + + +
+

Go в примерах

+

+ Go - это язык программирования с + открытым исходным кодом, предназначенный для создания простого, + быстрого и надежного программного обеспечения. +

+ +

+ Go в примерах Go by Example - это практическое введение + в Go с использованием примеров реальных программ. Проверьте + первый пример или просмотрите полный + список ниже. +

+ + + +
+ + diff --git a/public/interfaces b/public/interfaces new file mode 100644 index 0000000..95c5785 --- /dev/null +++ b/public/interfaces @@ -0,0 +1,242 @@ + + + + + Go в примерах: Интерфейсы (Interfaces) + + + + +
+

Go в примерах: Интерфейсы (Interfaces)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Интерфейсы это коллекции методов.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "math"
+)
+
+ +
+

Пример базового интерфейса в Go

+ +
+ +
type geometry interface {
+    area() float64
+    perim() float64
+}
+
+ +
+

В нашем примере мы будем реализовывать этот интерфейс +для типов rect и circle.

+ +
+ +
type rect struct {
+    width, height float64
+}
+type circle struct {
+    radius float64
+}
+
+ +
+

Чтобы реализовать интерфейс на Go, нам просто нужно +реализовать все методы в интерфейсе. Здесь мы +реализуем интерфейс geometry для rect.

+ +
+ +
func (r rect) area() float64 {
+    return r.width * r.height
+}
+func (r rect) perim() float64 {
+    return 2*r.width + 2*r.height
+}
+
+ +
+

Реализация для circle.

+ +
+ +
func (c circle) area() float64 {
+    return math.Pi * c.radius * c.radius
+}
+func (c circle) perim() float64 {
+    return 2 * math.Pi * c.radius
+}
+
+ +
+

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

+ +
+ +
func measure(g geometry) {
+    fmt.Println(g)
+    fmt.Println(g.area())
+    fmt.Println(g.perim())
+}
+
+ +
+ + + +
func main() {
+    r := rect{width: 3, height: 4}
+    c := circle{radius: 5}
+
+ +
+

Типы circle и rect структур реализуют +интерфейс geometry, поэтому мы можем использовать +экземпляры этих структур в качестве аргументов для +measure.

+ +
+ +
    measure(r)
+    measure(c)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run interfaces.go
+{3 4}
+12
+14
+{5}
+78.53981633974483
+31.41592653589793
+
+ +
+

Чтобы узнать больше об интерфейсах Go, ознакомьтесь с +этой статьей.

+ +
+ + +
+ + +

+ Следующий пример: Ошибки (Errors). +

+ + +
+ + + + diff --git a/public/json b/public/json new file mode 100644 index 0000000..9e541cf --- /dev/null +++ b/public/json @@ -0,0 +1,424 @@ + + + + + Go в примерах: JSON + + + + +
+

Go в примерах: JSON

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "encoding/json"
+    "fmt"
+    "os"
+)
+
+ +
+

Мы будем использовать эти две структуры, для демонстрации +кодирования и декодирования.

+ +
+ +
type response1 struct {
+    Page   int
+    Fruits []string
+}
+
+ +
+

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

+ +
+ +
type response2 struct {
+    Page   int      `json:"page"`
+    Fruits []string `json:"fruits"`
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Для начала мы рассмотрим кодирование данных в +JSON строку. Вот несколько примеров для простых +типов данных.

+ +
+ +
    bolB, _ := json.Marshal(true)
+    fmt.Println(string(bolB))
+
+ +
+ + + +
    intB, _ := json.Marshal(1)
+    fmt.Println(string(intB))
+
+ +
+ + + +
    fltB, _ := json.Marshal(2.34)
+    fmt.Println(string(fltB))
+
+ +
+ + + +
    strB, _ := json.Marshal("gopher")
+    fmt.Println(string(strB))
+
+ +
+

А вот примеры для срезов и карт, которые кодируются +в JSON массивы и объекты, как мы и ожидаем.

+ +
+ +
    slcD := []string{"apple", "peach", "pear"}
+    slcB, _ := json.Marshal(slcD)
+    fmt.Println(string(slcB))
+
+ +
+ + + +
    mapD := map[string]int{"apple": 5, "lettuce": 7}
+    mapB, _ := json.Marshal(mapD)
+    fmt.Println(string(mapB))
+
+ +
+

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

+ +
+ +
    res1D := &response1{
+        Page:   1,
+        Fruits: []string{"apple", "peach", "pear"}}
+    res1B, _ := json.Marshal(res1D)
+    fmt.Println(string(res1B))
+
+ +
+

Вы можете использовать теги в объявлениях +структурных полей для настройки кодированных имен +ключей JSON. Проверьте определение response2 +выше, чтобы увидеть пример таких тегов.

+ +
+ +
    res2D := &response2{
+        Page:   1,
+        Fruits: []string{"apple", "peach", "pear"}}
+    res2B, _ := json.Marshal(res2D)
+    fmt.Println(string(res2B))
+
+ +
+

Теперь давайте рассмотрим декодирование данных +JSON в значения Go. Вот пример для общей +структуры данных.

+ +
+ +
    byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
+
+ +
+

Нам нужно предоставить переменную, в которую пакет +JSON может поместить декодированные данные. +`map[string]interface{} будет содержать карту +строк для произвольных типов данных.

+ +
+ +
    var dat map[string]interface{}
+
+ +
+

Вот фактическое декодирование и проверка на наличие +ошибок.

+ +
+ +
    if err := json.Unmarshal(byt, &dat); err != nil {
+        panic(err)
+    }
+    fmt.Println(dat)
+
+ +
+

Чтобы использовать значения в декодированной карте, +нам нужно преобразовать их в соответствующий тип. +Например, здесь мы конвертируем значение из num +в ожидаемый тип float64.

+ +
+ +
    num := dat["num"].(float64)
+    fmt.Println(num)
+
+ +
+

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

+ +
+ +
    strs := dat["strs"].([]interface{})
+    str1 := strs[0].(string)
+    fmt.Println(str1)
+
+ +
+

Мы также можем декодировать JSON в пользовательские +типы данных. Это дает преимущество добавления +дополнительной безопасности типов в наши программы +и устранения необходимости в определении типрв +при доступе к декодированным данным.

+ +
+ +
    str := `{"page": 1, "fruits": ["apple", "peach"]}`
+    res := response2{}
+    json.Unmarshal([]byte(str), &res)
+    fmt.Println(res)
+    fmt.Println(res.Fruits[0])
+
+ +
+

В приведенных выше примерах мы всегда использовали +байты и строки в качестве промежуточных звеньев между +данными и представлением JSON на стандартном выходе. +Мы также можем транслировать JSON-кодировки напрямую +в os.Writer, такие как os.Stdout или даже HTTP-тела +ответа.

+ +
+ +
    enc := json.NewEncoder(os.Stdout)
+    d := map[string]int{"apple": 5, "lettuce": 7}
+    enc.Encode(d)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run json.go
+true
+1
+2.34
+"gopher"
+["apple","peach","pear"]
+{"apple":5,"lettuce":7}
+{"Page":1,"Fruits":["apple","peach","pear"]}
+{"page":1,"fruits":["apple","peach","pear"]}
+map[num:6.13 strs:[a b]]
+6.13
+a
+{1 [apple peach]}
+apple
+{"apple":5,"lettuce":7}
+
+ +
+

Мы рассмотрели основы JSON в Go, но ознакомьтесь с +публикацией в блоге JSON and Go +и документацией по пакету JSON.

+ +
+ + +
+ + +

+ Следующий пример: XML. +

+ + +
+ + + + diff --git a/public/line-filters b/public/line-filters new file mode 100644 index 0000000..41dc487 --- /dev/null +++ b/public/line-filters @@ -0,0 +1,214 @@ + + + + + Go в примерах: Строковые фильтры (Line Filters) + + + + +
+

Go в примерах: Строковые фильтры (Line Filters)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Строковый фильтр - это типичный тип программы, +которая читает входные данные в stdin, обрабатывает +их и затем выводит некоторый производный результат в +стандартный вывод. grep и sed - это обычные строковые +фильтры.

+ +
+ + +
+

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

+ +
+ +
package main
+
+ +
+ + + +
import (
+    "bufio"
+    "fmt"
+    "os"
+    "strings"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Обертывание небуферизованного os.Stdin буферизованным +сканером дает нам удобный метод сканирования Scan, +который продвигает сканер к следующему токену; который +является следующей строкой в сканере по умолчанию.

+ +
+ +
    scanner := bufio.NewScanner(os.Stdin)
+
+ +
+

Text возвращает текущий токен, из ввода - на +следующую строку.

+ +
+ +
    for scanner.Scan() {
+
+ +
+ + + +
        ucl := strings.ToUpper(scanner.Text())
+
+ +
+

Печатает в верхнем регистре.

+ +
+ +
        fmt.Println(ucl)
+    }
+
+ +
+

Проверяем ошибки для Scan. Ожидается конец файла, +и он не сообщается методом Scan как ошибка.

+ +
+ +
    if err := scanner.Err(); err != nil {
+        fmt.Fprintln(os.Stderr, "error:", err)
+        os.Exit(1)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Чтобы опробовать наш фильтр строк, сначала создайте +файл с несколькими строчными строчками.

+ +
+ +
$ echo 'hello'   > /tmp/lines
+$ echo 'filter' >> /tmp/lines
+
+ +
+

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

+ +
+ +
$ cat /tmp/lines | go run line-filters.go
+HELLO
+FILTER
+
+ +
+ + +

+ Следующий пример: Пути к файлам (File Paths). +

+ + +
+ + + + diff --git a/public/maps b/public/maps new file mode 100644 index 0000000..7429741 --- /dev/null +++ b/public/maps @@ -0,0 +1,239 @@ + + + + + Go в примерах: Карты (Maps) + + + + +
+

Go в примерах: Карты (Maps)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Карты - это встроенный ассоциативный тип данных +Go (иногда называемый хешами).

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Для создания пустой карты, используйте make: +make(map[key-type]val-type).

+ +
+ +
    m := make(map[string]int)
+
+ +
+

Вы можете установить пару ключ/значение +используя привычный синтаксис name[key] = val

+ +
+ +
    m["k1"] = 7
+    m["k2"] = 13
+
+ +
+

Вывод карты на экран с помощью fmt.Println +выведет все пары ключ/значение

+ +
+ +
    fmt.Println("map:", m)
+
+ +
+

Получить значение по ключу name[key].

+ +
+ +
    v1 := m["k1"]
+    fmt.Println("v1: ", v1)
+
+ +
+

Встроенная функция len возвращает количество +пар ключ/значение для карты.

+ +
+ +
    fmt.Println("len:", len(m))
+
+ +
+

Встроенная функция delete удаляет пару key/value +из карты.

+ +
+ +
    delete(m, "k2")
+    fmt.Println("map:", m)
+
+ +
+

Необязательное второе возвращаемое значение +из карты сообщает о том, существовал ли ключ в карте. +Это может быть использовано для устранения +неоднозначности между отсутствующими ключами и +ключами с нулевыми значениями, такими как 0 или +“”. Здесь нам не нужно само значение, поэтому +мы проигнорировали его с пустым идентификатором _.

+ +
+ +
    _, prs := m["k2"]
+    fmt.Println("prs:", prs)
+
+ +
+

Вы можете объявить и наполнить карту в одной +строке с помощью подобного синтаксиса.

+ +
+ +
    n := map[string]int{"foo": 1, "bar": 2}
+    fmt.Println("map:", n)
+}
+
+ +
+ + + + + + + + +
+

Обратите внимание, что карты отображаются в виде +map[k:v k:v]при печати с помощью fmt.Println

+ +
+ +
$ go run maps.go 
+map: map[k1:7 k2:13]
+v1:  7
+len: 2
+map: map[k1:7]
+prs: false
+map: map[bar:2 foo:1]
+
+ +
+ + +

+ Следующий пример: Ряд (Range). +

+ + +
+ + + + diff --git a/public/methods b/public/methods new file mode 100644 index 0000000..12b866f --- /dev/null +++ b/public/methods @@ -0,0 +1,205 @@ + + + + + Go в примерах: Методы (Methods) + + + + +
+

Go в примерах: Методы (Methods)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go поддерживает методы для структур

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
type rect struct {
+    width, height int
+}
+
+ +
+

Метод area принимает получателя *rect.

+ +
+ +
func (r *rect) area() int {
+    return r.width * r.height
+}
+
+ +
+

Методы могут принимать как указатели, так и значения. +Вот пример со значением.

+ +
+ +
func (r rect) perim() int {
+    return 2*r.width + 2*r.height
+}
+
+ +
+ + + +
func main() {
+    r := rect{width: 10, height: 5}
+
+ +
+

Вызываем 2 метода, определенные для нашей структуры.

+ +
+ +
    fmt.Println("area: ", r.area())
+    fmt.Println("perim:", r.perim())
+
+ +
+

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

+ +
+ +
    rp := &r
+    fmt.Println("area: ", rp.area())
+    fmt.Println("perim:", rp.perim())
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run methods.go 
+area:  50
+perim: 30
+area:  50
+perim: 30
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Интерфейсы (Interfaces). +

+ + +
+ + + + diff --git a/public/multiple-return-values b/public/multiple-return-values new file mode 100644 index 0000000..fdce803 --- /dev/null +++ b/public/multiple-return-values @@ -0,0 +1,176 @@ + + + + + Go в примерах: Функции с множественным возвратом (Multiple Return Values) + + + + +
+

Go в примерах: Функции с множественным возвратом (Multiple Return Values)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Запись (int, int) в описании этой функции, говорит о +том, что функция возвращает два целых числа.

+ +
+ +
func vals() (int, int) {
+    return 3, 7
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Здесь функция возвращает два разных значения и +присваивает их переменным a,b. Это называется +множественное присваивание.

+ +
+ +
    a, b := vals()
+    fmt.Println(a)
+    fmt.Println(b)
+
+ +
+

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

+ +
+ +
    _, c := vals()
+    fmt.Println(c)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run multiple-return-values.go
+3
+7
+7
+
+ +
+

Принятие переменного количества аргументов - +еще одна приятная особенность функций Go; +Рассмотрим это дальше.

+ +
+ + +
+ + +

+ Следующий пример: Функции с переменным числом аргументов (Variadic Functions). +

+ + +
+ + + + diff --git a/public/mutexes b/public/mutexes new file mode 100644 index 0000000..9574470 --- /dev/null +++ b/public/mutexes @@ -0,0 +1,305 @@ + + + + + Go в примерах: Мьютексы (Mutexes) + + + + +
+

Go в примерах: Мьютексы (Mutexes)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В предыдущем примере мы увидели, как управлять простым +состоянием счетчика с помощью атомарных операций. +Для более сложного состояния мы можем использовать мьютекс(http://en.wikipedia.org/wiki/Mutual_exclusion) +для безопасного доступа к данным в нескольких горутинах.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "math/rand"
+    "sync"
+    "sync/atomic"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Для нашего примера state будет картой.

+ +
+ +
    var state = make(map[int]int)
+
+ +
+

Этот mutex будет синхронизировать доступ к state.

+ +
+ +
    var mutex = &sync.Mutex{}
+
+ +
+

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

+ +
+ +
    var readOps uint64
+    var writeOps uint64
+
+ +
+

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

+ +
+ +
    for r := 0; r < 100; r++ {
+        go func() {
+            total := 0
+            for {
+
+ +
+

Для каждого чтения мы выбираем ключ для +доступа, блокируем mutex с помощью Lock() , +чтобы обеспечить исключительный доступ к +состоянию, читаем значение в выбранном ключе, +разблокируем мьютекс Unlock() и увеличиваем +количество readOps.

+ +
+ +
                key := rand.Intn(5)
+                mutex.Lock()
+                total += state[key]
+                mutex.Unlock()
+                atomic.AddUint64(&readOps, 1)
+
+ +
+

Немного ждем между чтениями.

+ +
+ +
                time.Sleep(time.Millisecond)
+            }
+        }()
+    }
+
+ +
+

Запустим так же 10 горутин для симуляции записи, +так же как мы делали для чтения.

+ +
+ +
    for w := 0; w < 10; w++ {
+        go func() {
+            for {
+                key := rand.Intn(5)
+                val := rand.Intn(100)
+                mutex.Lock()
+                state[key] = val
+                mutex.Unlock()
+                atomic.AddUint64(&writeOps, 1)
+                time.Sleep(time.Millisecond)
+            }
+        }()
+    }
+
+ +
+

Пусть 10 горутин работают над состоянием и +мьютексом на секунду.

+ +
+ +
    time.Sleep(time.Second)
+
+ +
+

Смотрим финальное количество операций

+ +
+ +
    readOpsFinal := atomic.LoadUint64(&readOps)
+    fmt.Println("readOps:", readOpsFinal)
+    writeOpsFinal := atomic.LoadUint64(&writeOps)
+    fmt.Println("writeOps:", writeOpsFinal)
+
+ +
+

С окончательной блокировкой состояния смотрим, +как все закончилось.

+ +
+ +
    mutex.Lock()
+    fmt.Println("state:", state)
+    mutex.Unlock()
+}
+
+ +
+ + + + + + + + + + + + + +
+

Запуск программы показывает, что мы выполнили +около 90000 операций в нашем синхронизированном +с мьютексомсостоянии.

+ +
+ +
$ go run mutexes.go
+readOps: 83285
+writeOps: 8320
+state: map[1:97 4:53 0:33 2:15 3:2]
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Управление состоянием горутин (Stateful Goroutines). +

+ + +
+ + + + diff --git a/public/non-blocking-channel-operations b/public/non-blocking-channel-operations new file mode 100644 index 0000000..313bb01 --- /dev/null +++ b/public/non-blocking-channel-operations @@ -0,0 +1,186 @@ + + + + + Go в примерах: Неблокируемые операции в каналах (Non-Blocking Channel Operations) + + + + +
+

Go в примерах: Неблокируемые операции в каналах (Non-Blocking Channel Operations)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+    messages := make(chan string)
+    signals := make(chan bool)
+
+ +
+

Вот неблокирующее получение. Если значение +доступно в messages, тогда select выберет +<-messages с этим значением. Если нет, он +сразу же примет случай по-умолчанию.

+ +
+ +
    select {
+    case msg := <-messages:
+        fmt.Println("received message", msg)
+    default:
+        fmt.Println("no message received")
+    }
+
+ +
+

Неблокирующая отправка работает аналогично. +Здесь msg не может быть отправлено в канал +messages, потому что у канала нет буфера и +нет получателя. Поэтому выбирается действие +по-умолчанию.

+ +
+ +
    msg := "hi"
+    select {
+    case messages <- msg:
+        fmt.Println("sent message", msg)
+    default:
+        fmt.Println("no message sent")
+    }
+
+ +
+

Мы можем использовать несколько case‘ов перед +действием по-умолчанию для реализации +многоцелевого неблокирующего выбора. Здесь мы +пытаемся получить неблокирующее получение +messages и signals.

+ +
+ +
    select {
+    case msg := <-messages:
+        fmt.Println("received message", msg)
+    case sig := <-signals:
+        fmt.Println("received signal", sig)
+    default:
+        fmt.Println("no activity")
+    }
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run non-blocking-channel-operations.go 
+no message received
+no message sent
+no activity
+
+ +
+ + +

+ Следующий пример: Закрытие каналов (Closing Channels). +

+ + +
+ + + + diff --git a/public/number-parsing b/public/number-parsing new file mode 100644 index 0000000..276c297 --- /dev/null +++ b/public/number-parsing @@ -0,0 +1,221 @@ + + + + + Go в примерах: Парсинг чисел (Number Parsing) + + + + +
+

Go в примерах: Парсинг чисел (Number Parsing)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Парсинг чисел из строк является распространенной задачей; +Вот как это реализовать в Go.

+ +
+ + +
+ + + +
package main
+
+ +
+

Для решения этой задачи подойдет встроенный пакет +strconv.

+ +
+ +
import (
+    "fmt"
+    "strconv"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

С помощью ParseFloat, параметр 64 говорит о том, +сколько битов точности необходимо использовать.

+ +
+ +
    f, _ := strconv.ParseFloat("1.234", 64)
+    fmt.Println(f)
+
+ +
+

Для ParseInt 0 означает вывод базы из строки. 64 +необходимо, чтобы результат соответствовал 64 битам.

+ +
+ +
    i, _ := strconv.ParseInt("123", 0, 64)
+    fmt.Println(i)
+
+ +
+

ParseInt будет распознавать числа в шестнадцатеричной +системе.

+ +
+ +
    d, _ := strconv.ParseInt("0x1c8", 0, 64)
+    fmt.Println(d)
+
+ +
+

ParseUint так же доступен.

+ +
+ +
    u, _ := strconv.ParseUint("789", 0, 64)
+    fmt.Println(u)
+
+ +
+

Atoi это удобная функция для парсинга в десятеричный +int.

+ +
+ +
    k, _ := strconv.Atoi("135")
+    fmt.Println(k)
+
+ +
+

Функции парсинга возвращают ошибку в случае некорректных +аргументов.

+ +
+ +
    _, e := strconv.Atoi("wat")
+    fmt.Println(e)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run number-parsing.go 
+1.234
+123
+456
+789
+135
+strconv.ParseInt: parsing "wat": invalid syntax
+
+ +
+

Далее мы рассмотрим парсинг URL.

+ +
+ + +
+ + +

+ Следующий пример: Парсинг URL (URL Parsing). +

+ + +
+ + + + diff --git a/public/panic b/public/panic new file mode 100644 index 0000000..d393582 --- /dev/null +++ b/public/panic @@ -0,0 +1,183 @@ + + + + + Go в примерах: Panic + + + + +
+

Go в примерах: Panic

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "os"
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    panic("a problem")
+
+ +
+

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

+ +
+ +
    _, err := os.Create("/tmp/file")
+    if err != nil {
+        panic(err)
+    }
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Запуск этой программы вызовет панику, распечатает +сообщение об ошибке и трейс выполнения и завершит +работу с ненулевым статусом.

+ +
+ +
$ go run panic.go
+panic: a problem
+
+ +
+ + + +
goroutine 1 [running]:
+main.main()
+    /.../panic.go:12 +0x47
+...
+exit status 2
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Defer. +

+ + +
+ + + + diff --git a/public/play.png b/public/play.png new file mode 100644 index 0000000000000000000000000000000000000000..ec7028cc111e97129b9067aebd500df2bde39f0a GIT binary patch literal 739 zcmV<90v!E`P)5r00004XF*Lt007q5 z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!bxA})R4C75 z`2YVu12XRD=wJYXlpqh=OR33;AA*B}UK(mCKQh->duC%}qk^s;g|leUVrG3k-8nPc zi~jFjJ@r2bw6t~nZzzoaUy$JcKPf5M2CD(7si_Q6(J>5iQevxj?%45v>Xb?UYjb1% z@7=xg|B(ZG{vTY`|NrRfzW)xk))ff}i3~9@F{lPGF)=zyi3zT#%a8s4@x%N7Cr_XK zZ*6Y$-^Ehr|H{c#|F7?!^Z(wVMgJ2*+-?a8i!wPlIG`H9$HP@+Z?5-z<>c!ByH`y9 zzkBt}|81p-|4RyT{%>8-{{PC(S^qEZoc(|M{FeV#mKM2@QBkM{00Aoy8)e4$zP^8W z;r~n9rvo+2`oC>a_y04Srh?fZLvHV%|Gy+F?msWTKs&ktU?3{QKl$vIY5yJnp=TC;hqGCQPL-mgjk1hcR;ElcW z{@(>AB9I}4$sw317i&h4F&-L0Un?elPj`gKWtyz`+sgn!T*A! zpf?IKVhiNuKJa`yvcws48XwH#AKhFo7+}@e}6|HR}dtosHn(LUtf=6005gz V0=~sP!p;By002ovPDHLkV1h=gV>SQ) literal 0 HcmV?d00001 diff --git a/public/pointers b/public/pointers new file mode 100644 index 0000000..e6f4ca7 --- /dev/null +++ b/public/pointers @@ -0,0 +1,199 @@ + + + + + Go в примерах: Указатели (Pointers) + + + + +
+

Go в примерах: Указатели (Pointers)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Мы покажем, как работают указатели, на примере 2 функций: +zeroval и zeroptr. В zeroval определен только 1 +аргумент с типом int, который передается по значению. +zeroval получает копию ival при вызове функции.

+ +
+ +
func zeroval(ival int) {
+    ival = 0
+}
+
+ +
+

zeroptr получает в качестве аргумента параметр *int, +который является указателем на int. Запись *iptr в +теле функции разыменовывает указатель с его адреса +памяти на текущее значение по этому адресу. Присвоение +значения разыменованному указателю изменяет значение +по указанному адресу.

+ +
+ +
func zeroptr(iptr *int) {
+    *iptr = 0
+}
+
+ +
+ + + +
func main() {
+    i := 1
+    fmt.Println("initial:", i)
+
+ +
+ + + +
    zeroval(i)
+    fmt.Println("zeroval:", i)
+
+ +
+

Запись &i получается ссылку на область памяти, в +которой хранится i, т.е. указатель на i.

+ +
+ +
    zeroptr(&i)
+    fmt.Println("zeroptr:", i)
+
+ +
+

Указатели могут быть выведены на экран

+ +
+ +
    fmt.Println("pointer:", &i)
+}
+
+ +
+ + + + + + + + +
+

zeroval не изменяет значение i в main, но +zeroptr изменяет, т.к. в него передается указатель +на область памяти, в которой хранится переменная.

+ +
+ +
$ go run pointers.go
+initial: 1
+zeroval: 1
+zeroptr: 0
+pointer: 0x42131100
+
+ +
+ + +

+ Следующий пример: Структуры (Structs). +

+ + +
+ + + + diff --git a/public/random-numbers b/public/random-numbers new file mode 100644 index 0000000..cc419d2 --- /dev/null +++ b/public/random-numbers @@ -0,0 +1,239 @@ + + + + + Go в примерах: Случайные числа (Random Numbers) + + + + +
+

Go в примерах: Случайные числа (Random Numbers)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Пакет Go math/rand обеспечивает генерацию +псевдослучайных чисел.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "math/rand"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Например, rand.Intn вернет случайное целое число в +диапазоне 0 <= n < 100.

+ +
+ +
    fmt.Print(rand.Intn(100), ",")
+    fmt.Print(rand.Intn(100))
+    fmt.Println()
+
+ +
+

rand.Float64 вернет число с плавающей точкой в присвоит +его в f, где f будет в промежутке 0.0 <= f < 1.0.

+ +
+ +
    fmt.Println(rand.Float64())
+
+ +
+

Этот способ может быть использован для генерации других +случайных чисел с плавающей точкой в разных диапазонах, +например для диапазона 5.0 <= f' < 10.0.

+ +
+ +
    fmt.Print((rand.Float64()*5)+5, ",")
+    fmt.Print((rand.Float64() * 5) + 5)
+    fmt.Println()
+
+ +
+

Генератор чисел по умолчанию является детерминированным, +поэтому по умолчанию он будет каждый раз генерировать +одну и ту же последовательность чисел. Чтобы произвести +различные последовательности, дайте ему соль(https://ru.wikipedia.org/wiki/Соль_(криптография)), +которая изменяется. Обратите внимание, что это не +безопасно использовать для генерации случайных чисел, +которые вы намерены хранить в секрете, используйте +crypto/rand для них.

+ +
+ +
    s1 := rand.NewSource(time.Now().UnixNano())
+    r1 := rand.New(s1)
+
+ +
+

Вызвать результат rand.Rand можно точно так же, как и +функции в пакете rand.

+ +
+ +
    fmt.Print(r1.Intn(100), ",")
+    fmt.Print(r1.Intn(100))
+    fmt.Println()
+
+ +
+

Если вы используете одну и ту же соль для генерации +чисел, то они будут совпадать.

+ +
+ +
    s2 := rand.NewSource(42)
+    r2 := rand.New(s2)
+    fmt.Print(r2.Intn(100), ",")
+    fmt.Print(r2.Intn(100))
+    fmt.Println()
+    s3 := rand.NewSource(42)
+    r3 := rand.New(s3)
+    fmt.Print(r3.Intn(100), ",")
+    fmt.Print(r3.Intn(100))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run random-numbers.go
+81,87
+0.6645600532184904
+7.123187485356329,8.434115364335547
+0,28
+5,87
+5,87
+
+ +
+

Обратитесь к документации по пакету math/rand +для ознакомления с другими случайными величинами, +которые может предоставить Go.

+ +
+ + +
+ + +

+ Следующий пример: Парсинг чисел (Number Parsing). +

+ + +
+ + + + diff --git a/public/range b/public/range new file mode 100644 index 0000000..043d3ac --- /dev/null +++ b/public/range @@ -0,0 +1,209 @@ + + + + + Go в примерах: Ряд (Range) + + + + +
+

Go в примерах: Ряд (Range)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

range перебирает элементы в различных структурах +данных. Давайте посмотрим, как использовать +range с некоторыми из структур данных, которые +мы уже изучили.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    nums := []int{2, 3, 4}
+    sum := 0
+    for _, num := range nums {
+        sum += num
+    }
+    fmt.Println("sum:", sum)
+
+ +
+

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

+ +
+ +
    for i, num := range nums {
+        if num == 3 {
+            fmt.Println("index:", i)
+        }
+    }
+
+ +
+

range для карт перебирает пары ключ/значение.

+ +
+ +
    kvs := map[string]string{"a": "apple", "b": "banana"}
+    for k, v := range kvs {
+        fmt.Printf("%s -> %s\n", k, v)
+    }
+
+ +
+

range может перебирать только ключи в карте

+ +
+ +
    for k := range kvs {
+        fmt.Println("key:", k)
+    }
+
+ +
+

range для строк перебирает кодовые точки Unicode. +Первое значение - это начальный байтовый индекс +руны, а второе - сама руна.

+ +
+ +
    for i, c := range "go" {
+        fmt.Println(i, c)
+    }
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run range.go
+sum: 9
+index: 1
+a -> apple
+b -> banana
+key: a
+key: b
+0 103
+1 111
+
+ +
+ + +

+ Следующий пример: Функции (Functions). +

+ + +
+ + + + diff --git a/public/range-over-channels b/public/range-over-channels new file mode 100644 index 0000000..24b1cc2 --- /dev/null +++ b/public/range-over-channels @@ -0,0 +1,160 @@ + + + + + Go в примерах: Перебор значений из каналов (Range over Channels) + + + + +
+

Go в примерах: Перебор значений из каналов (Range over Channels)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В предыдущем примере мы виделе как for и +range позволяют перебирать базовые структуры. Мы +так же можем использовать этот синтаксис для чтения +значений из канала.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Мы будем итерировать 2 значения в канале queue.

+ +
+ +
    queue := make(chan string, 2)
+    queue <- "one"
+    queue <- "two"
+    close(queue)
+
+ +
+

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

+ +
+ +
    for elem := range queue {
+        fmt.Println(elem)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run range-over-channels.go
+one
+two
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Таймеры (Timers). +

+ + +
+ + + + diff --git a/public/rate-limiting b/public/rate-limiting new file mode 100644 index 0000000..24eeca4 --- /dev/null +++ b/public/rate-limiting @@ -0,0 +1,270 @@ + + + + + Go в примерах: Ограничение скорости (Rate Limiting) + + + + +
+

Go в примерах: Ограничение скорости (Rate Limiting)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    requests := make(chan int, 5)
+    for i := 1; i <= 5; i++ {
+        requests <- i
+    }
+    close(requests)
+
+ +
+

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

+ +
+ +
    limiter := time.Tick(200 * time.Millisecond)
+
+ +
+

Блокируя прием от канала limiter перед +обслуживанием каждого запроса, мы ограничиваем себя +одним запросом каждые 200 миллисекунд.

+ +
+ +
    for req := range requests {
+        <-limiter
+        fmt.Println("request", req, time.Now())
+    }
+
+ +
+

Мы можем разрешить короткие всплески запросов в +нашей схеме ограничения скорости при сохранении +общего ограничения скорости. Мы можем сделать это +путем буферизации нашего канала ограничения. Этот +канал burstyLimiter будет позволять делать до +3 событий.

+ +
+ +
    burstyLimiter := make(chan time.Time, 3)
+
+ +
+

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

+ +
+ +
    for i := 0; i < 3; i++ {
+        burstyLimiter <- time.Now()
+    }
+
+ +
+

Каждые 200мс мы будем пытаться добавлять новое +значение в burstyLimiter, до своего предела +в 3 значения.

+ +
+ +
    go func() {
+        for t := range time.Tick(200 * time.Millisecond) {
+            burstyLimiter <- t
+        }
+    }()
+
+ +
+

Теперь смоделируем еще 5 входящих запросов. Первые +3 из них получат выгоду от вместимости burstyLimiter.

+ +
+ +
    burstyRequests := make(chan int, 5)
+    for i := 1; i <= 5; i++ {
+        burstyRequests <- i
+    }
+    close(burstyRequests)
+    for req := range burstyRequests {
+        <-burstyLimiter
+        fmt.Println("request", req, time.Now())
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

При запуске нашей программы мы видим, что первая +партия запросов обрабатывается каждые ~200мс.

+ +
+ +
$ go run rate-limiting.go
+request 1 2012-10-19 00:38:18.687438 +0000 UTC
+request 2 2012-10-19 00:38:18.887471 +0000 UTC
+request 3 2012-10-19 00:38:19.087238 +0000 UTC
+request 4 2012-10-19 00:38:19.287338 +0000 UTC
+request 5 2012-10-19 00:38:19.487331 +0000 UTC
+
+ +
+

Для второго пула запросов мы обслуживаем первые +3 сразу из-за использования ограничения скорости, +затем обслуживаем оставшиеся 2 с задержками ~200мс +каждый.

+ +
+ +
request 1 2012-10-19 00:38:20.487578 +0000 UTC
+request 2 2012-10-19 00:38:20.487645 +0000 UTC
+request 3 2012-10-19 00:38:20.487676 +0000 UTC
+request 4 2012-10-19 00:38:20.687483 +0000 UTC
+request 5 2012-10-19 00:38:20.887542 +0000 UTC
+
+ +
+ + +

+ Следующий пример: Атомарные счетчики (Atomic Counters). +

+ + +
+ + + + diff --git a/public/reading-files b/public/reading-files new file mode 100644 index 0000000..802617d --- /dev/null +++ b/public/reading-files @@ -0,0 +1,296 @@ + + + + + Go в примерах: Чтение файлов (Reading Files) + + + + +
+

Go в примерах: Чтение файлов (Reading Files)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Чтение и запись файлов это базовая задача, необходимая +для решения множества задач. Для начала мы рассмотрим +несколько примеров чтения файлов.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "bufio"
+    "fmt"
+    "io"
+    "io/ioutil"
+    "os"
+)
+
+ +
+

Чтение файлов требует проверок множества вызовов на +наличие ошибок. Эта функция-хелпер поможет нам +обрабатывать ошибки в одном месте.

+ +
+ +
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Возможно, самая основная задача чтения файлов - +это сохранение всего содержимого файла в памяти.

+ +
+ +
    dat, err := ioutil.ReadFile("/tmp/dat")
+    check(err)
+    fmt.Print(string(dat))
+
+ +
+

Вам часто может потребоваться больший контроль +над тем, как и какие части файла читаются. Для +решения этих задач начните с открытия файла, +чтобы получить значение os.File..

+ +
+ +
    f, err := os.Open("/tmp/dat")
+    check(err)
+
+ +
+

Прочитаем несколько байт с начала файла. Будет +прочитано первые 5 байт, но также выведем, +сколько фактически было прочитано.

+ +
+ +
    b1 := make([]byte, 5)
+    n1, err := f.Read(b1)
+    check(err)
+    fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]))
+
+ +
+

Вы так же можете получить конкретное место файла +с помощью Seek и выполнить Read оттуда.

+ +
+ +
    o2, err := f.Seek(6, 0)
+    check(err)
+    b2 := make([]byte, 2)
+    n2, err := f.Read(b2)
+    check(err)
+    fmt.Printf("%d bytes @ %d: ", n2, o2)
+    fmt.Printf("%v\n", string(b2[:n2]))
+
+ +
+

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

+ +
+ +
    o3, err := f.Seek(6, 0)
+    check(err)
+    b3 := make([]byte, 2)
+    n3, err := io.ReadAtLeast(f, b3, 2)
+    check(err)
+    fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
+
+ +
+

Тут нет встроенной перемотки назад, но можно +использовать Seek(0, 0) для этого.

+ +
+ +
    _, err = f.Seek(0, 0)
+    check(err)
+
+ +
+

В пакете bufio реализован буферизованный ридер, +который может быть полезен из-за своей эффективности +при большом количестве небольших операций чтения, и +из-за наличия дополнительных методов чтения, которые +он предоставляет.

+ +
+ +
    r4 := bufio.NewReader(f)
+    b4, err := r4.Peek(5)
+    check(err)
+    fmt.Printf("5 bytes: %s\n", string(b4))
+
+ +
+

Закройте файл, когда вы закончите использовать его +(обычно закрытие с defer‘ом делается сразу после открытия).

+ +
+ +
    f.Close()
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ echo "hello" > /tmp/dat
+$ echo "go" >>   /tmp/dat
+$ go run reading-files.go
+hello
+go
+5 bytes: hello
+2 bytes @ 6: go
+2 bytes @ 6: go
+5 bytes: hello
+
+ +
+

Далее рассмотрим запись в файл.

+ +
+ + +
+ + +

+ Следующий пример: Запись файлов (Writing Files). +

+ + +
+ + + + diff --git a/public/recursion b/public/recursion new file mode 100644 index 0000000..3db9aa5 --- /dev/null +++ b/public/recursion @@ -0,0 +1,132 @@ + + + + + Go в примерах: Рекурсия (Recursion) + + + + +
+

Go в примерах: Рекурсия (Recursion)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go поддерживает +рекурсивные функции. +Ниже приведено классическое вычисление факториала.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Фукция fact вызывает себя по не достигнет +fact(0).

+ +
+ +
func fact(n int) int {
+    if n == 0 {
+        return 1
+    }
+    return n * fact(n-1)
+}
+
+ +
+ + + +
func main() {
+    fmt.Println(fact(7))
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run recursion.go 
+5040
+
+ +
+ + +

+ Следующий пример: Указатели (Pointers). +

+ + +
+ + + + diff --git a/public/regular-expressions b/public/regular-expressions new file mode 100644 index 0000000..1f38c4b --- /dev/null +++ b/public/regular-expressions @@ -0,0 +1,352 @@ + + + + + Go в примерах: Регулярные выражения (Regular Expressions) + + + + +
+

Go в примерах: Регулярные выражения (Regular Expressions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "bytes"
+    "fmt"
+    "regexp"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Проверяем, соответствует ли шаблон строке

+ +
+ +
    match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
+    fmt.Println(match)
+
+ +
+

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

+ +
+ +
    r, _ := regexp.Compile("p([a-z]+)ch")
+
+ +
+

Множество методов доступны для этой структуры. +Вот тест на совпадение, который мы видели ранее.

+ +
+ +
    fmt.Println(r.MatchString("peach"))
+
+ +
+

Этот метод находит соответствие для регулярного +выражения.

+ +
+ +
    fmt.Println(r.FindString("peach punch"))
+
+ +
+

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

+ +
+ +
    fmt.Println(r.FindStringIndex("peach punch"))
+
+ +
+

Варианты Submatch включают в себя информацию +как о совпадениях с полным шаблоном, так и о +совпадениях с частями шаблона. Например, эта +конструкция вернет информацию как +для p([a-z]+)ch, так и для ([a-z]+).

+ +
+ +
    fmt.Println(r.FindStringSubmatch("peach punch"))
+
+ +
+

Точно так же это возвратит информацию об индексах +совпадений и подсовпадений.

+ +
+ +
    fmt.Println(r.FindStringSubmatchIndex("peach punch"))
+
+ +
+

Метод All применяется ко всем совпадениям на входе, +а не только к первому. Например, чтобы найти все +совпадения для регулярного выражения.

+ +
+ +
    fmt.Println(r.FindAllString("peach punch pinch", -1))
+
+ +
+

Этот метод All доступен и для других функций, +которые мы видели выше.

+ +
+ +
    fmt.Println(r.FindAllStringSubmatchIndex(
+        "peach punch pinch", -1))
+
+ +
+

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

+ +
+ +
    fmt.Println(r.FindAllString("peach punch pinch", 2))
+
+ +
+

В наших примерах выше были строковые аргументы и +использовались такие имена, как MatchString. Мы +также можем предоставить []byte аргументы и удалить +String из имени функции.

+ +
+ +
    fmt.Println(r.Match([]byte("peach")))
+
+ +
+

При создании констант с регулярными выражениями +вы можете использовать MustCompile, как аналог +Compile. Обычный Compile не будет работать +для констант, потому что он возвращает 2 значения.

+ +
+ +
    r = regexp.MustCompile("p([a-z]+)ch")
+    fmt.Println(r)
+
+ +
+

Пакет regexp также можно использовать для +замены подмножеств строк другими значениями.

+ +
+ +
    fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
+
+ +
+

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

+ +
+ +
    in := []byte("a peach")
+    out := r.ReplaceAllFunc(in, bytes.ToUpper)
+    fmt.Println(string(out))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run regular-expressions.go 
+true
+true
+peach
+[0 5]
+[peach ea]
+[0 5 1 3]
+[peach punch pinch]
+[[0 5 1 3] [6 11 7 9] [12 17 13 15]]
+[peach punch]
+true
+p([a-z]+)ch
+a <fruit>
+a PEACH
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: JSON. +

+ + +
+ + + + diff --git a/public/select b/public/select new file mode 100644 index 0000000..f45e57e --- /dev/null +++ b/public/select @@ -0,0 +1,192 @@ + + + + + Go в примерах: Select + + + + +
+

Go в примерах: Select

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s _select позволяет вам ждать нескольких +операций на канале. Сочетание горутин и каналов +с помощью select’а - мощная функция Go.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

В нашем примере мы будем выбирать между двумя +каналами.

+ +
+ +
    c1 := make(chan string)
+    c2 := make(chan string)
+
+ +
+

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

+ +
+ +
    go func() {
+        time.Sleep(1 * time.Second)
+        c1 <- "one"
+    }()
+    go func() {
+        time.Sleep(2 * time.Second)
+        c2 <- "two"
+    }()
+
+ +
+

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

+ +
+ +
    for i := 0; i < 2; i++ {
+        select {
+        case msg1 := <-c1:
+            fmt.Println("received", msg1)
+        case msg2 := <-c2:
+            fmt.Println("received", msg2)
+        }
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Мы получаем значние "one" и потом "two", как +и ожидалось.

+ +
+ +
$ time go run select.go 
+received one
+received two
+
+ +
+

Обратите внимание, что общее время выполнения +составляет всего ~2 секунды, так как и 1, и 2 секунды +Sleeps выполняются одновременно.

+ +
+ +
real    0m2.245s
+
+ +
+ + +

+ Следующий пример: Тайм-ауты (Timeouts). +

+ + +
+ + + + diff --git a/public/sha1-hashes b/public/sha1-hashes new file mode 100644 index 0000000..5ae7bdc --- /dev/null +++ b/public/sha1-hashes @@ -0,0 +1,212 @@ + + + + + Go в примерах: Хеш SHA1 (SHA1 Hashes) + + + + +
+

Go в примерах: Хеш SHA1 (SHA1 Hashes)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Хеши SHA1 часто +используются для вычисления коротких идентификаторов +для двоичных или текстовых BLOB-объектов. Например, +система контроля версий git широко использует SHA1 для +идентификации версионных файлов и каталогов. Вот как +вычислить хэши SHA1 в Go.

+ +
+ + +
+ + + +
package main
+
+ +
+

Go реализует несколько хеш-функций в пакете +crypto/*.

+ +
+ +
import (
+    "crypto/sha1"
+    "fmt"
+)
+
+ +
+ + + +
func main() {
+    s := "sha1 this string"
+
+ +
+

Для генерации хеша используется функция sha1.New(), +sha1.Write(bytes), затем sha1.Sum([]byte{}). +Тут мы создаем новый хеш.

+ +
+ +
    h := sha1.New()
+
+ +
+

В Write необходимо передать байты. Если у вас есть +строка s, используйте []byte(s), чтобы привести +ее к байтам.

+ +
+ +
    h.Write([]byte(s))
+
+ +
+

Получаем окончательный результат хеш-функции в виде +байтового фрагмента. Аргумент в Sum добавляет к +существующему фрагменту байты, но обычно он не используется.

+ +
+ +
    bs := h.Sum(nil)
+
+ +
+

Значения SHA1 часто печатаются в шестнадцатеричном формате, +например, в git commit. Используйте %x для преобразования +результатов хеширования в шестнадцатеричную строку.

+ +
+ +
    fmt.Println(s)
+    fmt.Printf("%x\n", bs)
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Запущенная программа вычисляет хеш и печатает его в +удобочитаемом шестнадцатеричном формате.

+ +
+ +
$ go run sha1-hashes.go
+sha1 this string
+cf23df2207d99a74fbe169e3eba035e633b65d94
+
+ +
+

Вы можете вычислить другие хэши, используя шаблон, +аналогичный показанному выше. Например, для вычисления +хэшей MD5 импортируйте crypto/md5 и используйте +md5.New().

+ +
+ + +
+

Обратите внимание, что если вам нужны криптографически +защищенные хэши, вы должны тщательно исследовать +стойкость хэша!

+ +
+ + +
+ + +

+ Следующий пример: Кодирование Base64 (Base64 Encoding). +

+ + +
+ + + + diff --git a/public/signals b/public/signals new file mode 100644 index 0000000..639ad78 --- /dev/null +++ b/public/signals @@ -0,0 +1,199 @@ + + + + + Go в примерах: Сигналы (Signals) + + + + +
+

Go в примерах: Сигналы (Signals)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Иногда нам хотелось бы, чтобы наши программы на Go +интеллектуально обрабатывали сигналы Unix. +Например, мы можем захотеть, чтобы сервер корректно +завершил работу при получении SIGTERM, или инструмент +командной строки остановил обработку ввода, если он +получил SIGINT. Вот как обрабатывать сигналы в Go +с каналами.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+    "os/signal"
+    "syscall"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Уведомление о выходе сигнала работает путем +отправки значений os.Signal в канал. Мы создадим +канал для получения этих уведомлений (мы также +создадим канал, чтобы уведомить нас, когда программа +может выйти).

+ +
+ +
    sigs := make(chan os.Signal, 1)
+    done := make(chan bool, 1)
+
+ +
+

signal.Notify регистрирует данный канал для +получения уведомлений об указанных сигналах.

+ +
+ +
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+
+ +
+

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

+ +
+ +
    go func() {
+        sig := <-sigs
+        fmt.Println()
+        fmt.Println(sig)
+        done <- true
+    }()
+
+ +
+

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

+ +
+ +
    fmt.Println("awaiting signal")
+    <-done
+    fmt.Println("exiting")
+}
+
+ +
+ + + + + + + + +
+

Когда мы запустим эту программу, она заблокирует +ожидание сигнала. Набрав ctrl-C (который терминал +показывает как ^C), мы можем послать сигнал SIGINT, +в результате чего программа напечатает interrupt +и затем выйдет.

+ +
+ +
$ go run signals.go
+awaiting signal
+^C
+interrupt
+exiting
+
+ +
+ + +

+ Следующий пример: Выход (Exit). +

+ + +
+ + + + diff --git a/public/site.css b/public/site.css new file mode 100644 index 0000000..7e93afb --- /dev/null +++ b/public/site.css @@ -0,0 +1,212 @@ +/* CSS reset: http://meyerweb.com/eric/tools/css/reset/ */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* Layout and typography */ +body { + font-family: 'Georgia', serif; + font-size: 16px; + line-height: 20px; + color: #252519; +} +em { + font-style: italic; +} +a, a:visited { + color: #261a3b; +} +h2 { + font-size: 32px; + line-height: 40px; + margin-top: 40px; +} +h2 a { + text-decoration: none; +} +div.example { + width: 900px; + min-width: 900px; + max-width: 900px; + margin-left: auto; + margin-right: auto; + margin-bottom: 120px; +} +div.example table { + margin-top: 15px; + margin-bottom: 20px; +} +p.next { + margin-bottom: 20px; +} +p.footer { + color: grey; +} +p.footer a, p.footer a:visited { + color: grey; +} +div#intro { + width: 420px; + min-width: 420px; + max-width: 420px; + margin-left: auto; + margin-right: auto; + margin-bottom: 120px; +} +div#intro p { + padding-top: 20px; +} +div#intro ul { + padding-top: 20px; +} +table td { + border: 0; + outline: 0; +} +td.docs { + width: 420px; + max-width: 420px; + min-width: 420px; + min-height: 5px; + vertical-align: top; + text-align: left; +} +td.docs p { + padding-right: 5px; + padding-top: 5px; + padding-bottom: 15px; +} +td.code { + width: 480px; + max-width: 480px; + min-width: 480px; + padding-top: 5px; + padding-right: 5px; + padding-left: 5px; + padding-bottom: 5px; + vertical-align: top; + background: #f0f0f0; +} +td.code.leading { + padding-bottom: 11px; +} +td.code.empty { + background: #ffffff; +} +pre, code { + font-size: 14px; line-height: 18px; + font-family: 'Menlo', 'Monaco', 'Consolas', 'Lucida Console', monospace; +} +img.copy, img.run { + height: 16px; + width: 16px; + float: right +} +img.copy, img.run { + cursor: pointer; +} +img.copy { + margin-right: 4px; +} + +/* Syntax highlighting */ +body .hll { background-color: #ffffcc } +body .err { border: 1px solid #FF0000 } /* Error */ +body .c { color: #408080; font-style: italic } /* Comment */ +body .k { color: #954121 } /* Keyword */ +body .o { color: #666666 } /* Operator */ +body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +body .cp { color: #BC7A00 } /* Comment.Preproc */ +body .c1 { color: #408080; font-style: italic } /* Comment.Single */ +body .cs { color: #408080; font-style: italic } /* Comment.Special */ +body .gd { color: #A00000 } /* Generic.Deleted */ +body .ge { font-style: italic } /* Generic.Emph */ +body .gr { color: #FF0000 } /* Generic.Error */ +body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +body .gi { color: #00A000 } /* Generic.Inserted */ +body .go { color: #808080 } /* Generic.Output */ +body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +body .gs { font-weight: bold } /* Generic.Strong */ +body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +body .gt { color: #0040D0 } /* Generic.Traceback */ +body .kc { color: #954121 } /* Keyword.Constant */ +body .kd { color: #954121 } /* Keyword.Declaration */ +body .kn { color: #954121 } /* Keyword.Namespace */ +body .kp { color: #954121 } /* Keyword.Pseudo */ +body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ +body .kt { color: #B00040 } /* Keyword.Type */ +body .m { color: #666666 } /* Literal.Number */ +body .s { color: #219161 } /* Literal.String */ +body .na { color: #7D9029 } /* Name.Attribute */ +body .nb { color: #954121 } /* Name.Builtin */ +body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +body .no { color: #880000 } /* Name.Constant */ +body .nd { color: #AA22FF } /* Name.Decorator */ +body .ni { color: #999999; font-weight: bold } /* Name.Entity */ +body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +body .nf { color: #0000FF } /* Name.Function */ +body .nl { color: #A0A000 } /* Name.Label */ +body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +body .nt { color: #954121; font-weight: bold } /* Name.Tag */ +body .nv { color: #19469D } /* Name.Variable */ +body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +body .w { color: #bbbbbb } /* Text.Whitespace */ +body .mf { color: #666666 } /* Literal.Number.Float */ +body .mh { color: #666666 } /* Literal.Number.Hex */ +body .mi { color: #666666 } /* Literal.Number.Integer */ +body .mo { color: #666666 } /* Literal.Number.Oct */ +body .sb { color: #219161 } /* Literal.String.Backtick */ +body .sc { color: #219161 } /* Literal.String.Char */ +body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ +body .s2 { color: #219161 } /* Literal.String.Double */ +body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +body .sh { color: #219161 } /* Literal.String.Heredoc */ +body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +body .sx { color: #954121 } /* Literal.String.Other */ +body .sr { color: #BB6688 } /* Literal.String.Regex */ +body .s1 { color: #219161 } /* Literal.String.Single */ +body .ss { color: #19469D } /* Literal.String.Symbol */ +body .bp { color: #954121 } /* Name.Builtin.Pseudo */ +body .vc { color: #19469D } /* Name.Variable.Class */ +body .vg { color: #19469D } /* Name.Variable.Global */ +body .vi { color: #19469D } /* Name.Variable.Instance */ +body .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/public/site.js b/public/site.js new file mode 100644 index 0000000..e2539fb --- /dev/null +++ b/public/site.js @@ -0,0 +1,17 @@ +/*! + * clipboard.js v1.5.13 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,o){function r(c,a){if(!n[c]){if(!e[c]){var l="function"==typeof require&&require;if(!a&&l)return l(c,!0);if(i)return i(c,!0);var s=new Error("Cannot find module '"+c+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[c]={exports:{}};e[c][0].call(u.exports,function(t){var n=e[c][1][t];return r(n?n:t)},u,u.exports,t,e,n,o)}return n[c].exports}for(var i="function"==typeof require&&require,c=0;c + + + + Go в примерах: Срезы (Slices) + + + + +
+

Go в примерах: Срезы (Slices)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    s := make([]string, 3)
+    fmt.Println("emp:", s)
+
+ +
+

Мы можем устанавливать и получать значения, как в массивах.

+ +
+ +
    s[0] = "a"
+    s[1] = "b"
+    s[2] = "c"
+    fmt.Println("set:", s)
+    fmt.Println("get:", s[2])
+
+ +
+

len возвращает длину среза, как и ожидалось.

+ +
+ +
    fmt.Println("len:", len(s))
+
+ +
+

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

+ +
+ +
    s = append(s, "d")
+    s = append(s, "e", "f")
+    fmt.Println("apd:", s)
+
+ +
+

Срезы могут быть скопированы с помощью copy. В +данном примере мы создаем пустой срез c такой же +длины как и s и копируем данные из s в c.

+ +
+ +
    c := make([]string, len(s))
+    copy(c, s)
+    fmt.Println("cpy:", c)
+
+ +
+

Срезы поддерживают оператор slice (синтаксис +использование slice[low:high]). Для примера, +тут мы получаем срез состоящий из элементов +s[2], s[3], и s[4].

+ +
+ +
    l := s[2:5]
+    fmt.Println("sl1:", l)
+
+ +
+

Тут мы получаем срез до элемента s[5] (исключая его).

+ +
+ +
    l = s[:5]
+    fmt.Println("sl2:", l)
+
+ +
+

А тут получаем срез от s[2] (включая его) и до конца +исходного среза.

+ +
+ +
    l = s[2:]
+    fmt.Println("sl3:", l)
+
+ +
+

Мы можем объявить и заполнить срез значениями в одну +строку.

+ +
+ +
    t := []string{"g", "h", "i"}
+    fmt.Println("dcl:", t)
+
+ +
+

Срезы можно объединять в многомерные структуры +данных. Длина внутренних срезов может варьироваться, +в отличии от многомерных массивов.

+ +
+ +
    twoD := make([][]int, 3)
+    for i := 0; i < 3; i++ {
+        innerLen := i + 1
+        twoD[i] = make([]int, innerLen)
+        for j := 0; j < innerLen; j++ {
+            twoD[i][j] = i + j
+        }
+    }
+    fmt.Println("2d: ", twoD)
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

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

+ +
+ +
$ go run slices.go
+emp: [  ]
+set: [a b c]
+get: c
+len: 3
+apd: [a b c d e f]
+cpy: [a b c d e f]
+sl1: [c d e]
+sl2: [a b c d e]
+sl3: [c d e f]
+dcl: [g h i]
+2d:  [[0] [1 2] [2 3 4]]
+
+ +
+

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

+ +
+ + +
+

Теперь, когда мы рассмотрели массивы и срезы, мы +посмотрим другую ключевую встроенную структуру +данных Go: карты.

+ +
+ + +
+ + +

+ Следующий пример: Карты (Maps). +

+ + +
+ + + + diff --git a/public/sorting b/public/sorting new file mode 100644 index 0000000..80cd209 --- /dev/null +++ b/public/sorting @@ -0,0 +1,168 @@ + + + + + Go в примерах: Сортировка (Sorting) + + + + +
+

Go в примерах: Сортировка (Sorting)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Пакет sort реализует сортировку для встроенных и +пользовательских типов. Сначала рассмотрим сортировку +встроенных типов.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "sort"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Методы сортировки специфичны для встроенного типа; +Вот пример для строк. Обратите внимание, что +сортировка выполняется на месте, поэтому она +изменяет данный фрагмент и не возвращает новый.

+ +
+ +
    strs := []string{"c", "a", "b"}
+    sort.Strings(strs)
+    fmt.Println("Strings:", strs)
+
+ +
+

Пример сортировки int‘ов

+ +
+ +
    ints := []int{7, 2, 4}
+    sort.Ints(ints)
+    fmt.Println("Ints:   ", ints)
+
+ +
+

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

+ +
+ +
    s := sort.IntsAreSorted(ints)
+    fmt.Println("Sorted: ", s)
+}
+
+ +
+ + + + + + + + +
+

После запуска наша программа выведет отсортированные +строки и срез целых чисел и true, как результат +выполнения AreSorted.

+ +
+ +
$ go run sorting.go
+Strings: [a b c]
+Ints:    [2 4 7]
+Sorted:  true
+
+ +
+ + +

+ Следующий пример: Сортировка через функции (Sorting by Functions). +

+ + +
+ + + + diff --git a/public/sorting-by-functions b/public/sorting-by-functions new file mode 100644 index 0000000..f4e2df7 --- /dev/null +++ b/public/sorting-by-functions @@ -0,0 +1,185 @@ + + + + + Go в примерах: Сортировка через функции (Sorting by Functions) + + + + +
+

Go в примерах: Сортировка через функции (Sorting by Functions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "sort"
+)
+
+ +
+

Для сортировки по пользовательской функции в Go нам +нужен соответствующий тип. Здесь мы создали тип +byLength, который является просто псевдонимом для +[]string.

+ +
+ +
type byLength []string
+
+ +
+

Мы реализуем sort.Interface - Len,LessиSwap +- для нашего типа, чтобы мы могли использовать общую +функциюSortпакетаsort.LenиSwapобычно +одинаковы для разных типов, аLessбудет содержать +реальную пользовательскую логику сортировки. В нашем +случае мы хотим отсортировать в порядке увеличения +длины строки, поэтому мы используемlen(s[i])и +len(s[j])` здесь.

+ +
+ +
func (s byLength) Len() int {
+    return len(s)
+}
+func (s byLength) Swap(i, j int) {
+    s[i], s[j] = s[j], s[i]
+}
+func (s byLength) Less(i, j int) bool {
+    return len(s[i]) < len(s[j])
+}
+
+ +
+

Реализовав интерфейс, мы можем теперь реализовать +нашу собственную сортировку, преобразовав исходный +срез fruits в byLength, а затем использовать +sort.Sort для этого типизированного среза.

+ +
+ +
func main() {
+    fruits := []string{"peach", "banana", "kiwi"}
+    sort.Sort(byLength(fruits))
+    fmt.Println(fruits)
+}
+
+ +
+ + + + + + + + + + + + + +
+

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

+ +
+ +
$ go run sorting-by-functions.go 
+[kiwi peach banana]
+
+ +
+

Следуя той же схеме создания пользовательского типа, +реализации трех методов интерфейса для этого типа +и последующего вызова sort.Sort для коллекции +этого типа, мы можем сортировать срезы Go +по произвольным функциям.

+ +
+ + +
+ + +

+ Следующий пример: Panic. +

+ + +
+ + + + diff --git a/public/spawning-processes b/public/spawning-processes new file mode 100644 index 0000000..611921e --- /dev/null +++ b/public/spawning-processes @@ -0,0 +1,267 @@ + + + + + Go в примерах: Порождающие процессы (Spawning Processes) + + + + +
+

Go в примерах: Порождающие процессы (Spawning Processes)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Иногда наши программы Go должны порождать другие, не +Go процессы. Например, подсветка синтаксиса на этом +сайте реализуется +путем запуска pygmentize +процесса из программы Go. Давайте рассмотрим несколько +примеров порождающих процессов из Go.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "io/ioutil"
+    "os/exec"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Мы начнем с простой команды, которая не принимает +аргументов или ввода и просто печатает что-то на +стандартный вывод. Хелпер exec.Command создает +объект для представления этого внешнего процесса.

+ +
+ +
    dateCmd := exec.Command("date")
+
+ +
+

.Output - это еще один хелпер, который обрабатывает +общий случай запуска команды, ожидаетее завершения +и сбора выходных данных. Если ошибок не было, dateOut +будет содержать байты с информацией о дате.

+ +
+ +
    dateOut, err := dateCmd.Output()
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println("> date")
+    fmt.Println(string(dateOut))
+
+ +
+

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

+ +
+ +
    grepCmd := exec.Command("grep", "hello")
+
+ +
+

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

+ +
+ +
    grepIn, _ := grepCmd.StdinPipe()
+    grepOut, _ := grepCmd.StdoutPipe()
+    grepCmd.Start()
+    grepIn.Write([]byte("hello grep\ngoodbye grep"))
+    grepIn.Close()
+    grepBytes, _ := ioutil.ReadAll(grepOut)
+    grepCmd.Wait()
+
+ +
+

Мы опускаем проверки ошибок в приведенном выше +примере, но вы можете использовать обычный шаблон +if err != nil для них. Мы также собираем только +результаты StdoutPipe, но вы можете собирать +StderrPipe точно таким же образом.

+ +
+ +
    fmt.Println("> grep hello")
+    fmt.Println(string(grepBytes))
+
+ +
+

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

+ +
+ +
    lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
+    lsOut, err := lsCmd.Output()
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println("> ls -a -l -h")
+    fmt.Println(string(lsOut))
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

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

+ +
+ +
$ go run spawning-processes.go 
+> date
+Wed Oct 10 09:53:11 PDT 2012
+
+ +
+ + + +
> grep hello
+hello grep
+
+ +
+ + + +
> ls -a -l -h
+drwxr-xr-x  4 mark 136B Oct 3 16:29 .
+drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
+-rw-r--r--  1 mark 1.3K Oct 3 16:28 spawning-processes.go
+
+ +
+ + +

+ Следующий пример: Исполняющие процессы (Exec'ing Processes). +

+ + +
+ + + + diff --git a/public/stateful-goroutines b/public/stateful-goroutines new file mode 100644 index 0000000..66ba49a --- /dev/null +++ b/public/stateful-goroutines @@ -0,0 +1,328 @@ + + + + + Go в примерах: Управление состоянием горутин (Stateful Goroutines) + + + + +
+

Go в примерах: Управление состоянием горутин (Stateful Goroutines)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "math/rand"
+    "sync/atomic"
+    "time"
+)
+
+ +
+

В этом примере наше состояние будет принадлежать +единственной горутине. Это гарантирует, что данные +никогда не будут повреждены при одновременном доступе. +Чтобы прочитать или записать это состояние, другие +горутины будут отправлять сообщения горутин-владельцу +и получать соответствующие ответы. Эти структуры +readOp и writeOp инкапсулируют эти запросы и +способ, которым владеет горутина-ответчик. +In this example our state will be owned by a single +goroutine. This will guarantee that the data is never +corrupted with concurrent access. In order to read or +write that state, other goroutines will send messages +to the owning goroutine and receive corresponding +replies. These readOp and writeOp structs +encapsulate those requests and a way for the owning +goroutine to respond.

+ +
+ +
type readOp struct {
+    key  int
+    resp chan int
+}
+type writeOp struct {
+    key  int
+    val  int
+    resp chan bool
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Как и прежде, мы посчитаем, сколько операций мы +выполняем.

+ +
+ +
    var readOps uint64
+    var writeOps uint64
+
+ +
+

Каналы чтения и записи будут использоваться +другими горутинами для выдачи запросов на чтение +и запись соответственно.

+ +
+ +
    reads := make(chan readOp)
+    writes := make(chan writeOp)
+
+ +
+

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

+ +
+ +
    go func() {
+        var state = make(map[int]int)
+        for {
+            select {
+            case read := <-reads:
+                read.resp <- state[read.key]
+            case write := <-writes:
+                state[write.key] = write.val
+                write.resp <- true
+            }
+        }
+    }()
+
+ +
+

Запускаем 100 горутин для выдачи операций чтения +в горутину владеющую состоянием, через канал reads. +Каждое чтение требует создания readOp, отправки +его по каналу reads и получения результата по +resp каналу.

+ +
+ +
    for r := 0; r < 100; r++ {
+        go func() {
+            for {
+                read := readOp{
+                    key:  rand.Intn(5),
+                    resp: make(chan int)}
+                reads <- read
+                <-read.resp
+                atomic.AddUint64(&readOps, 1)
+                time.Sleep(time.Millisecond)
+            }
+        }()
+    }
+
+ +
+

Так же делаем 10 записей.

+ +
+ +
    for w := 0; w < 10; w++ {
+        go func() {
+            for {
+                write := writeOp{
+                    key:  rand.Intn(5),
+                    val:  rand.Intn(100),
+                    resp: make(chan bool)}
+                writes <- write
+                <-write.resp
+                atomic.AddUint64(&writeOps, 1)
+                time.Sleep(time.Millisecond)
+            }
+        }()
+    }
+
+ +
+

Дадим горутинам отработать 1 секунду

+ +
+ +
    time.Sleep(time.Second)
+
+ +
+

Наконец, выводим данные счетчиков

+ +
+ +
    readOpsFinal := atomic.LoadUint64(&readOps)
+    fmt.Println("readOps:", readOpsFinal)
+    writeOpsFinal := atomic.LoadUint64(&writeOps)
+    fmt.Println("writeOps:", writeOpsFinal)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Запуск нашей программы показывает, что управление +состоянием на основе горутин завершает около +80 000 операций.

+ +
+ +
$ go run stateful-goroutines.go
+readOps: 71708
+writeOps: 7177
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Сортировка (Sorting). +

+ + +
+ + + + diff --git a/public/string-formatting b/public/string-formatting new file mode 100644 index 0000000..d4c397f --- /dev/null +++ b/public/string-formatting @@ -0,0 +1,462 @@ + + + + + Go в примерах: Форматирование строк (String Formatting) + + + + +
+

Go в примерах: Форматирование строк (String Formatting)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go предлагает отличную поддержку форматирования строк +с помощью printf. Вот несколько примеров типичных +задач форматирования строк.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "os"
+)
+
+ +
+ + + +
type point struct {
+    x, y int
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Go предлагает несколько “глаголов” созданных для +форматирования общих Go значений. Например, +это выведет инстанс нашей point структуры.

+ +
+ +
    p := point{1, 2}
+    fmt.Printf("%v\n", p)
+
+ +
+

Если значение является структурой, запись %+v +выведет названия полей структуры.

+ +
+ +
    fmt.Printf("%+v\n", p)
+
+ +
+

Вариант %#v печатает синтаксическое представление +Go, то есть фрагмент исходного кода, который будет +генерировать это значение.

+ +
+ +
    fmt.Printf("%#v\n", p)
+
+ +
+

Для вывода типа значения, используйте %T.

+ +
+ +
    fmt.Printf("%T\n", p)
+
+ +
+

Форматирование логических значений не вызывает затруднений.

+ +
+ +
    fmt.Printf("%t\n", true)
+
+ +
+

Возможно большое количество опций для форматирования +целых чисел. Используйте %d для стандартного, +десятеричного вывода.

+ +
+ +
    fmt.Printf("%d\n", 123)
+
+ +
+

Бинарный вывод

+ +
+ +
    fmt.Printf("%b\n", 14)
+
+ +
+

Вывод символа, соответсвующего заданному числу.

+ +
+ +
    fmt.Printf("%c\n", 33)
+
+ +
+

%x - шестнадцатиричное значение.

+ +
+ +
    fmt.Printf("%x\n", 456)
+
+ +
+

Так же есть несколько вариантов форматирования +чисел с плавающей точкой. Стандартный вывод %f.

+ +
+ +
    fmt.Printf("%f\n", 78.9)
+
+ +
+

%e и %E приводит числло с плавающей точкой +к экспоненциальному представлению.

+ +
+ +
    fmt.Printf("%e\n", 123400000.0)
+    fmt.Printf("%E\n", 123400000.0)
+
+ +
+

Для стандартного вывода строк используйте %s.

+ +
+ +
    fmt.Printf("%s\n", "\"string\"")
+
+ +
+

Для двойных ковычек как в исходниках Go, используйте %q.

+ +
+ +
    fmt.Printf("%q\n", "\"string\"")
+
+ +
+

Так же как и с целочисленными ранее, %x отображает +строку в виде шестнадцатеричного исчисления, с двумя +символами вывода за каждый байт ввода.

+ +
+ +
    fmt.Printf("%x\n", "hex this")
+
+ +
+

Чтобы вывести ссылку на указатель, используйте %p.

+ +
+ +
    fmt.Printf("%p\n", &p)
+
+ +
+

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

+ +
+ +
    fmt.Printf("|%6d|%6d|\n", 12, 345)
+
+ +
+

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

+ +
+ +
    fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
+
+ +
+

Для выравнивания по левому краю используйте флаг -.

+ +
+ +
    fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
+
+ +
+

Вы также можете контролировать ширину при форматировании +строк, особенно для обеспечения их выравнивания в табличном +выводе. Стандартное выравнивание по правому краю.

+ +
+ +
    fmt.Printf("|%6s|%6s|\n", "foo", "b")
+
+ +
+

Для выравнивания по левому краю используйте флаг -.

+ +
+ +
    fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
+
+ +
+

До сих пор мы видели Printf, который печатает +отформатированную строку в os.Stdout. Sprintf +форматирует и возвращает строку, нигде не печатая.

+ +
+ +
    s := fmt.Sprintf("a %s", "string")
+    fmt.Println(s)
+
+ +
+

Вы можете отформатировать+вывести в io.Writers, используя +Fprintf.

+ +
+ +
    fmt.Fprintf(os.Stderr, "an %s\n", "error")
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run string-formatting.go
+{1 2}
+{x:1 y:2}
+main.point{x:1, y:2}
+main.point
+true
+123
+1110
+!
+1c8
+78.900000
+1.234000e+08
+1.234000E+08
+"string"
+"\"string\""
+6865782074686973
+0x42135100
+|    12|   345|
+|  1.20|  3.45|
+|1.20  |3.45  |
+|   foo|     b|
+|foo   |b     |
+a string
+an error
+
+ +
+ + +

+ Следующий пример: Регулярные выражения (Regular Expressions). +

+ + +
+ + + + diff --git a/public/string-functions b/public/string-functions new file mode 100644 index 0000000..8516f53 --- /dev/null +++ b/public/string-functions @@ -0,0 +1,216 @@ + + + + + Go в примерах: Строковые функции (String Functions) + + + + +
+

Go в примерах: Строковые функции (String Functions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Стандартная библиотека пакета strings предоставляет +множество удобных функций для работы со строками. Вот +некоторые из них.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    s "strings"
+)
+
+ +
+

Создаем алиас для функции fmt.Println, т.к. далее мы будем +часто вызывать эту функцию.

+ +
+ +
var p = fmt.Println
+
+ +
+ + + +
func main() {
+
+ +
+

Данные функции доступны в пакете strings. Обратите внимание, +что все эти функции из пакета, а не методы строковых объектов. +Это означает, что нам необходимо передать первым аргументом +функции, строку, над которой мы производим операцию. Вы можете +найти больше строковых функций в официальной документации +к пакету.

+ +
+ +
    p("Contains:  ", s.Contains("test", "es"))
+    p("Count:     ", s.Count("test", "t"))
+    p("HasPrefix: ", s.HasPrefix("test", "te"))
+    p("HasSuffix: ", s.HasSuffix("test", "st"))
+    p("Index:     ", s.Index("test", "e"))
+    p("Join:      ", s.Join([]string{"a", "b"}, "-"))
+    p("Repeat:    ", s.Repeat("a", 5))
+    p("Replace:   ", s.Replace("foo", "o", "0", -1))
+    p("Replace:   ", s.Replace("foo", "o", "0", 1))
+    p("Split:     ", s.Split("a-b-c-d-e", "-"))
+    p("ToLower:   ", s.ToLower("TEST"))
+    p("ToUpper:   ", s.ToUpper("test"))
+    p()
+
+ +
+

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

+ +
+ +
    p("Len: ", len("hello"))
+    p("Char:", "hello"[1])
+}
+
+ +
+

Обратите внимание, что len и индексация выше работают на +уровне байтов. Go использует строки в кодировке UTF-8, так +что это часто полезно как есть. Если вы работаете с +потенциально многобайтовыми символами, вам нужно использовать +операции с кодировкой. Смотрите строки, байты, руны и символы +в Go для получения дополнительной +информации.

+ +
+ + +
+ + + + + + + + + + + + + +
+ + + +
$ go run string-functions.go
+Contains:   true
+Count:      2
+HasPrefix:  true
+HasSuffix:  true
+Index:      1
+Join:       a-b
+Repeat:     aaaaa
+Replace:    f00
+Replace:    f0o
+Split:      [a b c d e]
+ToLower:    test
+ToUpper:    TEST
+
+ +
+ + + +
Len:  5
+Char: 101
+
+ +
+ + +

+ Следующий пример: Форматирование строк (String Formatting). +

+ + +
+ + + + diff --git a/public/structs b/public/structs new file mode 100644 index 0000000..800cbf0 --- /dev/null +++ b/public/structs @@ -0,0 +1,279 @@ + + + + + Go в примерах: Структуры (Structs) + + + + +
+

Go в примерах: Структуры (Structs)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Структуры в Go - это коллекции полей определенных +типов. Как правило, они используются для логической +группировки данных.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

Структура person имеет два поля name и age.

+ +
+ +
type person struct {
+    name string
+    age  int
+}
+
+ +
+

Функция NewPerson создает новую струкутуру person с +заданным именем.

+ +
+ +
func NewPerson(name string) *person {
+
+ +
+

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

+ +
+ +
    p := person{name: name}
+    p.age = 42
+    return &p
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Так создается новая структура

+ +
+ +
    fmt.Println(person{"Bob", 20})
+
+ +
+

Вы можете задавать имена для корректного +присваивания значений при создании структуры

+ +
+ +
    fmt.Println(person{name: "Alice", age: 30})
+
+ +
+

Пропущенные поля будут нулевыми.

+ +
+ +
    fmt.Println(person{name: "Fred"})
+
+ +
+

Префикс & возвращает указатель на структуру.

+ +
+ +
    fmt.Println(&person{name: "Ann", age: 40})
+
+ +
+

Можно инкапсулировать создание новой структуры +в функцию

+ +
+ +
    fmt.Println(NewPerson("Jon"))
+
+ +
+

Доступ к полям структуры осуществляется через +точку.

+ +
+ +
    s := person{name: "Sean", age: 50}
+    fmt.Println(s.name)
+
+ +
+

Вы также можете использовать точки со +структурными указателями - указатели автоматически +разыменовываются.

+ +
+ +
    sp := &s
+    fmt.Println(sp.age)
+
+ +
+

Структуры мутабельны.

+ +
+ +
    sp.age = 51
+    fmt.Println(sp.age)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run structs.go
+{Bob 20}
+{Alice 30}
+{Fred 0}
+&{Ann 40}
+Sean
+50
+51
+&{Jon 42}
+
+ +
+ + +

+ Следующий пример: Методы (Methods). +

+ + +
+ + + + diff --git a/public/switch b/public/switch new file mode 100644 index 0000000..4f7cf2f --- /dev/null +++ b/public/switch @@ -0,0 +1,209 @@ + + + + + Go в примерах: Switch + + + + +
+

Go в примерах: Switch

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Switch помогает проверять условие в нескольких блоках

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Стандартное использование switch.

+ +
+ +
    i := 2
+    fmt.Print("Write ", i, " as ")
+    switch i {
+    case 1:
+        fmt.Println("one")
+    case 2:
+        fmt.Println("two")
+    case 3:
+        fmt.Println("three")
+    }
+
+ +
+

Вы можете использовать запятую в качестве разделителя, +для перечисления нескольких значений в case. +Так же в данном примере используется блок +по-умолчанию default.

+ +
+ +
    switch time.Now().Weekday() {
+    case time.Saturday, time.Sunday:
+        fmt.Println("It's the weekend")
+    default:
+        fmt.Println("It's a weekday")
+    }
+
+ +
+

switch без условия аналогичен обычному оператору +if/else по своей логике. Так же в этом примере +что в case можно использовать не только константы.

+ +
+ +
    t := time.Now()
+    switch {
+    case t.Hour() < 12:
+        fmt.Println("It's before noon")
+    default:
+        fmt.Println("It's after noon")
+    }
+
+ +
+

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

+ +
+ +
    whatAmI := func(i interface{}) {
+        switch t := i.(type) {
+        case bool:
+            fmt.Println("I'm a bool")
+        case int:
+            fmt.Println("I'm an int")
+        default:
+            fmt.Printf("Don't know type %T\n", t)
+        }
+    }
+    whatAmI(true)
+    whatAmI(1)
+    whatAmI("hey")
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run switch.go 
+Write 2 as two
+It's a weekday
+It's after noon
+I'm a bool
+I'm an int
+Don't know type string
+
+ +
+ + +

+ Следующий пример: Массивы (Arrays). +

+ + +
+ + + + diff --git a/public/temporary-files-and-directories b/public/temporary-files-and-directories new file mode 100644 index 0000000..0827cd6 --- /dev/null +++ b/public/temporary-files-and-directories @@ -0,0 +1,247 @@ + + + + + Go в примерах: Временные файлы и директории (Temporary Files and Directories) + + + + +
+

Go в примерах: Временные файлы и директории (Temporary Files and Directories)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "io/ioutil"
+    "os"
+    "path/filepath"
+)
+
+ +
+ + + +
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Простейший способ создания временного файла - это +вызов ioutil.TempFile. Он создаст и откроет +файл для чтения и записи. Мы использовали "" в +качестве первого аргумента, и поэтому ioutil.TempFile +создаст файл в директории по-умолчанию.

+ +
+ +
    f, err := ioutil.TempFile("", "sample")
+    check(err)
+
+ +
+

Показать имя временного файла. В ОС на основе Unix +каталог, вероятно, будет /tmp. Имя файла начинается +с префикса, заданного в качестве второго аргумента +ioutil.TempFile, а остальное выбирается автоматически, +чтобы параллельные вызовы всегда создавали разные +имена файлов.

+ +
+ +
    fmt.Println("Temp file name:", f.Name())
+
+ +
+

Удалите файл после того, как мы закончим. Через +некоторое время ОС, скорее всего, сама очистит +временные файлы, но рекомендуется делать это явно.

+ +
+ +
    defer os.Remove(f.Name())
+
+ +
+

Мы можем записать какую-то информацию в файл.

+ +
+ +
    _, err = f.Write([]byte{1, 2, 3, 4})
+    check(err)
+
+ +
+

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

+ +
+ +
    dname, err := ioutil.TempDir("", "sampledir")
+    fmt.Println("Temp dir name:", dname)
+
+ +
+ + + +
    defer os.RemoveAll(dname)
+
+ +
+

Теперь мы можем синтезировать временные имена +файлов, добавив к ним префикс нашего +временного каталога.

+ +
+ +
    fname := filepath.Join(dname, "file1")
+    err = ioutil.WriteFile(fname, []byte{1, 2}, 0666)
+    check(err)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run temporary-files-and-directories.go
+Temp file name: /tmp/sample610887201
+Temp dir name: /tmp/sampledir898854668
+
+ +
+ + +

+ Следующий пример: Тестирование (Testing). +

+ + +
+ + + + diff --git a/public/testing b/public/testing new file mode 100644 index 0000000..52be24a --- /dev/null +++ b/public/testing @@ -0,0 +1,240 @@ + + + + + Go в примерах: Тестирование (Testing) + + + + +
+

Go в примерах: Тестирование (Testing)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Unit тестирование является важной частью написания +правильных программ Go. Пакет тестирования testing +предоставляет инструменты, необходимые для +написания unit тестов, а команда go test запускает +тесты.

+ +
+ + +
+

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

+ +
+ +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "testing"
+)
+
+ +
+

Мы будем тестировать эту простую реализацию +целочисленного минимума. Обычно код, который мы +тестируем, находится в исходном файле с именем +что-то вроде intutils.go, а тестовый файл для +него будет называться intutils_test.go.

+ +
+ +
func IntMin(a, b int) int {
+    if a < b {
+        return a
+    } else {
+        return b
+    }
+}
+
+ +
+

Тест создается путем написания функции с именем, +начинающимся с Test.

+ +
+ +
func TestIntMinBasic(t *testing.T) {
+    ans := IntMin(2, -2)
+    if ans != -2 {
+
+ +
+

t.Error* сообщит об ошибках теста, но продолжит +выполнение теста. t.Fail* сообщит об ошибках +теста и немедленно остановит тест.

+ +
+ +
        t.Errorf("IntMin(2, -2) = %d; want -2", ans)
+    }
+}
+
+ +
+

Написание тестов может быть повторяющимся, поэтому +идиоматично использовать table-driven style, где тестовые +входы и ожидаемые выходы перечислены в таблице, а один +цикл проходит по ним и выполняет тестовую логику.

+ +
+ +
func TestIntMinTableDriven(t *testing.T) {
+    var tests = []struct {
+        a, b int
+        want int
+    }{
+        {0, 1, 0},
+        {1, 0, 0},
+        {2, -2, -2},
+        {0, -1, -1},
+        {-1, 0, -1},
+    }
+
+ +
+

t.Run позволяет запускать «подтесты», по одному +для каждой записи таблицы. Они показываются +отдельно при выполнении go test -v.

+ +
+ +
    for _, tt := range tests {
+
+ +
+ + + +
        testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
+        t.Run(testname, func(t *testing.T) {
+            ans := IntMin(tt.a, tt.b)
+            if ans != tt.want {
+                t.Errorf("got %d, want %d", ans, tt.want)
+            }
+        })
+    }
+}
+
+ +
+ + + + + + + + +
+

Run all tests in the current project in verbose mode.

+ +
+ +
$ go test -v
+== RUN   TestIntMinBasic
+--- PASS: TestIntMinBasic (0.00s)
+=== RUN   TestIntMinTableDriven
+=== RUN   TestIntMinTableDriven/0,1
+=== RUN   TestIntMinTableDriven/1,0
+=== RUN   TestIntMinTableDriven/2,-2
+=== RUN   TestIntMinTableDriven/0,-1
+=== RUN   TestIntMinTableDriven/-1,0
+--- PASS: TestIntMinTableDriven (0.00s)
+    --- PASS: TestIntMinTableDriven/0,1 (0.00s)
+    --- PASS: TestIntMinTableDriven/1,0 (0.00s)
+    --- PASS: TestIntMinTableDriven/2,-2 (0.00s)
+    --- PASS: TestIntMinTableDriven/0,-1 (0.00s)
+    --- PASS: TestIntMinTableDriven/-1,0 (0.00s)
+PASS
+ok      examples/testing    0.023s
+
+ +
+ + +

+ Следующий пример: Аргументы командной строки (Command-Line Arguments). +

+ + +
+ + + + diff --git a/public/tickers b/public/tickers new file mode 100644 index 0000000..0d4ddd4 --- /dev/null +++ b/public/tickers @@ -0,0 +1,180 @@ + + + + + Go в примерах: Тикеры (повторения) (Tickers) + + + + +
+

Go в примерах: Тикеры (повторения) (Tickers)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Таймеры необходимы, когда надо выполнить +что-то в будущем один раз, а тикеры позволяют +повторять действия через определенные интервалы. Вот +пример того, как тикер выводит сообщение Tick at... +через заданный период, пока мы не остановим его.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    ticker := time.NewTicker(500 * time.Millisecond)
+    done := make(chan bool)
+
+ +
+ + + +
    go func() {
+        for {
+            select {
+            case <-done:
+                return
+            case t := <-ticker.C:
+                fmt.Println("Tick at", t)
+            }
+        }
+    }()
+
+ +
+

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

+ +
+ +
    time.Sleep(1600 * time.Millisecond)
+    ticker.Stop()
+    done <- true
+    fmt.Println("Ticker stopped")
+}
+
+ +
+ + + + + + + + +
+

Когда мы запускаем эту программу, тикер должен +выполнится 3 раза, после чего остановиться.

+ +
+ +
$ go run tickers.go
+Tick at 2012-09-23 11:29:56.487625 -0700 PDT
+Tick at 2012-09-23 11:29:56.988063 -0700 PDT
+Tick at 2012-09-23 11:29:57.488076 -0700 PDT
+Ticker stopped
+
+ +
+ + +

+ Следующий пример: Пулы воркеров (Worker Pools). +

+ + +
+ + + + diff --git a/public/time b/public/time new file mode 100644 index 0000000..607b336 --- /dev/null +++ b/public/time @@ -0,0 +1,274 @@ + + + + + Go в примерах: Время (Time) + + + + +
+

Go в примерах: Время (Time)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go предлагает обширную поддержку для времени и +продолжительности; вот несколько примеров.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+    p := fmt.Println
+
+ +
+

Начнем с получения текущего времени

+ +
+ +
    now := time.Now()
+    p(now)
+
+ +
+

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

+ +
+ +
    then := time.Date(
+        2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
+    p(then)
+
+ +
+

Вы можете извлечь различные компоненты значения времени.

+ +
+ +
    p(then.Year())
+    p(then.Month())
+    p(then.Day())
+    p(then.Hour())
+    p(then.Minute())
+    p(then.Second())
+    p(then.Nanosecond())
+    p(then.Location())
+
+ +
+

Получения дня недели доступно через метод Weekday.

+ +
+ +
    p(then.Weekday())
+
+ +
+

Эти методы сравниваются два раза, проверяя, +происходит ли первый случай до, после или +одновременно со вторым, соответственно.

+ +
+ +
    p(then.Before(now))
+    p(then.After(now))
+    p(then.Equal(now))
+
+ +
+

Метод Sub возвращает Duration, интервал между +двумя временами.

+ +
+ +
    diff := now.Sub(then)
+    p(diff)
+
+ +
+

Мы можем вычислить продолжительность.

+ +
+ +
    p(diff.Hours())
+    p(diff.Minutes())
+    p(diff.Seconds())
+    p(diff.Nanoseconds())
+
+ +
+

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

+ +
+ +
    p(then.Add(diff))
+    p(then.Add(-diff))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run time.go
+2012-10-31 15:50:13.793654 +0000 UTC
+2009-11-17 20:34:58.651387237 +0000 UTC
+2009
+November
+17
+20
+34
+58
+651387237
+UTC
+Tuesday
+true
+false
+false
+25891h15m15.142266763s
+25891.25420618521
+1.5534752523711128e+06
+9.320851514226677e+07
+93208515142266763
+2012-10-31 15:50:13.793654 +0000 UTC
+2006-12-05 01:19:43.509120474 +0000 UTC
+
+ +
+

Далее мы рассмотрим время относительно эпохи Unix.

+ +
+ + +
+ + +

+ Следующий пример: Epoch. +

+ + +
+ + + + diff --git a/public/time-formatting-parsing b/public/time-formatting-parsing new file mode 100644 index 0000000..b267f39 --- /dev/null +++ b/public/time-formatting-parsing @@ -0,0 +1,208 @@ + + + + + Go в примерах: Форматирование времени (Time Formatting / Parsing) + + + + +
+

Go в примерах: Форматирование времени (Time Formatting / Parsing)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports time formatting and parsing via +pattern-based layouts.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+    p := fmt.Println
+
+ +
+

Вот пример форматирования времени в соответствии с +RFC3339 с использованием соответствующей константы.

+ +
+ +
    t := time.Now()
+    p(t.Format(time.RFC3339))
+
+ +
+

Парсинг значений использует тот же синтаксис, что и Format.

+ +
+ +
    t1, e := time.Parse(
+        time.RFC3339,
+        "2012-11-01T22:08:41+00:00")
+    p(t1)
+
+ +
+

Форматирование и парсинг используют аргументы на +основе примеров. Обычно вы используете константу из пакета +time, но вы также можете предоставить собственные шаблоны. +Они должны использовать время в формате Mon Jan 2 +15:04:05 MST 2006, чтобы вывести на экран. Время в примере +должно быть точно таким, как показано: 2006 год, 15 для часа, +понедельник для дня недели и т.д.

+ +
+ +
    p(t.Format("3:04PM"))
+    p(t.Format("Mon Jan _2 15:04:05 2006"))
+    p(t.Format("2006-01-02T15:04:05.999999-07:00"))
+    form := "3 04 PM"
+    t2, e := time.Parse(form, "8 41 PM")
+    p(t2)
+
+ +
+

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

+ +
+ +
    fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
+        t.Year(), t.Month(), t.Day(),
+        t.Hour(), t.Minute(), t.Second())
+
+ +
+

Parse вернет ошибку. если не сможет распарсить данные.

+ +
+ +
    ansic := "Mon Jan _2 15:04:05 2006"
+    _, e = time.Parse(ansic, "8:41PM")
+    p(e)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run time-formatting-parsing.go 
+2014-04-15T18:00:15-07:00
+2012-11-01 22:08:41 +0000 +0000
+6:00PM
+Tue Apr 15 18:00:15 2014
+2014-04-15T18:00:15.161182-07:00
+0000-01-01 20:41:00 +0000 UTC
+2014-04-15T18:00:15-00:00
+parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": ...
+
+ +
+ + +

+ Следующий пример: Случайные числа (Random Numbers). +

+ + +
+ + + + diff --git a/public/timeouts b/public/timeouts new file mode 100644 index 0000000..d84da21 --- /dev/null +++ b/public/timeouts @@ -0,0 +1,189 @@ + + + + + Go в примерах: Тайм-ауты (Timeouts) + + + + +
+

Go в примерах: Тайм-ауты (Timeouts)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Тайм-ауты важны для программ, которые подключаются +к внешним ресурсам или которым необходимо ограничить +время выполнения. Тайм-ауты в Go реализуются легко +и элегантно благодаря каналам и select‘ам.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

В нашем примере предположим, что мы выполняем внешний +вызов, который возвращает результат на канале c1 +через 2с. Обратите внимание, что канал буферизован, +поэтому отправка в goroutine неблокирующая. Это +обычная схема предотвращения утечек горутин в случае, +если канал никогда не читается.ё

+ +
+ +
    c1 := make(chan string, 1)
+    go func() {
+        time.Sleep(2 * time.Second)
+        c1 <- "result 1"
+    }()
+
+ +
+

Вот select, реализующий тайм-аут. res := <-c1 +ожидает результата, а <-Time.After ожидает +значения, которое будет отправлено после истечения +времени ожидания 1с. Поскольку select продолжает +работу с первым полученным запросом, мы возьмем +тайм-аут, если операция займет больше разрешенных 1с.

+ +
+ +
    select {
+    case res := <-c1:
+        fmt.Println(res)
+    case <-time.After(1 * time.Second):
+        fmt.Println("timeout 1")
+    }
+
+ +
+

Если мы допустим время ожидания более 3с, то +получение от c2 будет успешным, и мы распечатаем +результат.

+ +
+ +
    c2 := make(chan string, 1)
+    go func() {
+        time.Sleep(2 * time.Second)
+        c2 <- "result 2"
+    }()
+    select {
+    case res := <-c2:
+        fmt.Println(res)
+    case <-time.After(3 * time.Second):
+        fmt.Println("timeout 2")
+    }
+}
+
+ +
+ + + + + + + + +
+

Запуск этой программы показывает время ожидания +первой и второй успешной операции.

+ +
+ +
$ go run timeouts.go 
+timeout 1
+result 2
+
+ +
+ + +

+ Следующий пример: Неблокируемые операции в каналах (Non-Blocking Channel Operations). +

+ + +
+ + + + diff --git a/public/timers b/public/timers new file mode 100644 index 0000000..3c17241 --- /dev/null +++ b/public/timers @@ -0,0 +1,176 @@ + + + + + Go в примерах: Таймеры (Timers) + + + + +
+

Go в примерах: Таймеры (Timers)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Таймеры позволяет выполнить одно событие в будущем. +Вы сообщаете таймеру, как долго вы хотите ждать, +и он предоставляет канал, который будет уведомлен +в это время. Этот таймер будет ждать 2 секунды.

+ +
+ +
    timer1 := time.NewTimer(2 * time.Second)
+
+ +
+

<-timer1.C блокирует канал таймера C пока +не будет отправлено сообщение о том, что таймер истек

+ +
+ +
    <-timer1.C
+    fmt.Println("Timer 1 expired")
+
+ +
+

Если бы вы просто хотели подождать, вы могли бы +использовать time.Sleep. Одна из причин, по +которой таймер может быть полезен, заключается +в том, что вы можете отменить таймер до его +истечения, как в этом примере.

+ +
+ +
    timer2 := time.NewTimer(time.Second)
+    go func() {
+        <-timer2.C
+        fmt.Println("Timer 2 expired")
+    }()
+    stop2 := timer2.Stop()
+    if stop2 {
+        fmt.Println("Timer 2 stopped")
+    }
+}
+
+ +
+ + + + + + + + +
+

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

+ +
+ +
$ go run timers.go
+Timer 1 expired
+Timer 2 stopped
+
+ +
+ + +

+ Следующий пример: Тикеры (повторения) (Tickers). +

+ + +
+ + + + diff --git a/public/url-parsing b/public/url-parsing new file mode 100644 index 0000000..c05f749 --- /dev/null +++ b/public/url-parsing @@ -0,0 +1,240 @@ + + + + + Go в примерах: Парсинг URL (URL Parsing) + + + + +
+

Go в примерах: Парсинг URL (URL Parsing)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

URL - это уникальный локатор ресурса. +Рассмотрим как парсить URL в Go.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "net"
+    "net/url"
+)
+
+ +
+ + + +
func main() {
+
+ +
+

Мы будем разбирать этот URL, который содержит схему, +аутентификационные данные, хост, порт, путь, параметры +и фрагмент запроса.

+ +
+ +
    s := "postgres://user:pass@host.com:5432/path?k=v#f"
+
+ +
+

Парсим URL и убеждаемся, что нет ошибок.

+ +
+ +
    u, err := url.Parse(s)
+    if err != nil {
+        panic(err)
+    }
+
+ +
+

Получаем схему

+ +
+ +
    fmt.Println(u.Scheme)
+
+ +
+

User содержит всю аутентификационную информацию; используйте +Username и Password если надо получить конкретное поле.

+ +
+ +
    fmt.Println(u.User)
+    fmt.Println(u.User.Username())
+    p, _ := u.User.Password()
+    fmt.Println(p)
+
+ +
+

Host содержит поля хост и порт, если они определены. +Воспользуйтесь SplitHostPort, чтобы разделить их.

+ +
+ +
    fmt.Println(u.Host)
+    host, port, _ := net.SplitHostPort(u.Host)
+    fmt.Println(host)
+    fmt.Println(port)
+
+ +
+

Так можно получить путь и фрагмент после #.

+ +
+ +
    fmt.Println(u.Path)
+    fmt.Println(u.Fragment)
+
+ +
+

Для получения параметров в строке вида k=v +используйте RawQuery. Вы так же можете разобрать +запрос в карту. Разобранный запрос в карту из строк +превращается в срез строк, так первый элемент будет +находиться по адресу [0].

+ +
+ +
    fmt.Println(u.RawQuery)
+    m, _ := url.ParseQuery(u.RawQuery)
+    fmt.Println(m)
+    fmt.Println(m["k"][0])
+}
+
+ +
+ + + + + + + + +
+

Запуск нашей программы парсинга URL показывает все +различные фрагменты, которые мы извлекли.

+ +
+ +
$ go run url-parsing.go 
+postgres
+user:pass
+user
+pass
+host.com:5432
+host.com
+5432
+/path
+f
+k=v
+map[k:[v]]
+v
+
+ +
+ + +

+ Следующий пример: Хеш SHA1 (SHA1 Hashes). +

+ + +
+ + + + diff --git a/public/values b/public/values new file mode 100644 index 0000000..9acf817 --- /dev/null +++ b/public/values @@ -0,0 +1,159 @@ + + + + + Go в примерах: Типы данных (Values) + + + + +
+

Go в примерах: Типы данных (Values)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

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

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

Строки могут быть сложены с помощью символа +.

+ +
+ +
    fmt.Println("go" + "lang")
+
+ +
+

Целый числа и числа с плавающей точкой.

+ +
+ +
    fmt.Println("1+1 =", 1+1)
+    fmt.Println("7.0/3.0 =", 7.0/3.0)
+
+ +
+

Логические значения с логическими операторами

+ +
+ +
    fmt.Println(true && false)
+    fmt.Println(true || false)
+    fmt.Println(!true)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run values.go
+golang
+1+1 = 2
+7.0/3.0 = 2.3333333333333335
+false
+true
+false
+
+ +
+ + +

+ Следующий пример: Переменные (Variables). +

+ + +
+ + + + diff --git a/public/variables b/public/variables new file mode 100644 index 0000000..dba89ad --- /dev/null +++ b/public/variables @@ -0,0 +1,191 @@ + + + + + Go в примерах: Переменные (Variables) + + + + +
+

Go в примерах: Переменные (Variables)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В Go, переменные объявляются явно и используются +компилятором, например, для проверки корректного +вызова функции (типы аргументов)

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+ + + +
func main() {
+
+ +
+

var объявляет 1 или более переменных

+ +
+ +
    var a = "initial"
+    fmt.Println(a)
+
+ +
+

Вы можете объявить несколько переменных за раз

+ +
+ +
    var b, c int = 1, 2
+    fmt.Println(b, c)
+
+ +
+

Go будет определять тип по инициализированной переменной.

+ +
+ +
    var d = true
+    fmt.Println(d)
+
+ +
+

Переменные, объявленные без соответствующей инициализации, +имеют нулевое значение. Например, нулевое значение +для int равно 0.

+ +
+ +
    var e int
+    fmt.Println(e)
+
+ +
+

В Go существует короткий пператор := для +объявления и инициализации переменной. +Например, var f string = "apple" в короткой записи +превратится в

+ +
+ +
    f := "apple"
+    fmt.Println(f)
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run variables.go
+initial
+1 2
+true
+0
+apple
+
+ +
+ + +

+ Следующий пример: Константы (Constants). +

+ + +
+ + + + diff --git a/public/variadic-functions b/public/variadic-functions new file mode 100644 index 0000000..20f43c3 --- /dev/null +++ b/public/variadic-functions @@ -0,0 +1,177 @@ + + + + + Go в примерах: Функции с переменным числом аргументов (Variadic Functions) + + + + +
+

Go в примерах: Функции с переменным числом аргументов (Variadic Functions)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Функции с переменным числом аргументов +могут быть вызваны с любым количество аргументов. +Пример такой функции - это fmt.Println.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import "fmt"
+
+ +
+

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

+ +
+ +
func sum(nums ...int) {
+    fmt.Print(nums, " ")
+    total := 0
+    for _, num := range nums {
+        total += num
+    }
+    fmt.Println(total)
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Такие функции можно вызывать обычным способом.

+ +
+ +
    sum(1, 2)
+    sum(1, 2, 3)
+
+ +
+

Если у вас есть несколько аргументов в срезе, +вы можете применить его к функции с переменным +числом аргументов таким образом func(slice...).

+ +
+ +
    nums := []int{1, 2, 3, 4}
+    sum(nums...)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run variadic-functions.go 
+[1 2] 3
+[1 2 3] 6
+[1 2 3 4] 10
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Замыкания (Closures). +

+ + +
+ + + + diff --git a/public/waitgroups b/public/waitgroups new file mode 100644 index 0000000..11682c0 --- /dev/null +++ b/public/waitgroups @@ -0,0 +1,226 @@ + + + + + Go в примерах: WaitGroups + + + + +
+

Go в примерах: WaitGroups

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Для ожидания выполнения нескольких горутин, мы можем +использовать встроенную конструкцию WaitGroup.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "sync"
+    "time"
+)
+
+ +
+

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

+ +
+ +
func worker(id int, wg *sync.WaitGroup) {
+    fmt.Printf("Worker %d starting\n", id)
+
+ +
+

Sleep симулирует тяжелую задачу.

+ +
+ +
    time.Sleep(time.Second)
+    fmt.Printf("Worker %d done\n", id)
+
+ +
+

Оповестить WaitGroup что воркер выполнился

+ +
+ +
    wg.Done()
+}
+
+ +
+ + + +
func main() {
+
+ +
+

Эта WaitGroup используется для ожидания выполнения +всех горутинё запущенных здесь.

+ +
+ +
    var wg sync.WaitGroup
+
+ +
+

Запускаем несколько горутин и инкрементируем счетчик +в WaitGroup для каждой запущенной горутины.

+ +
+ +
    for i := 1; i <= 5; i++ {
+        wg.Add(1)
+        go worker(i, &wg)
+    }
+
+ +
+

Блокируем звершение программы до момента, пока +счетчик WaitGroup снова не станет равным 0. +Это будет означать, что все горутины выполнились.

+ +
+ +
    wg.Wait()
+}
+
+ +
+ + + + + + + + + + + + + +
+ + + +
$ go run waitgroups.go
+Worker 5 starting
+Worker 3 starting
+Worker 4 starting
+Worker 1 starting
+Worker 2 starting
+Worker 4 done
+Worker 1 done
+Worker 2 done
+Worker 5 done
+Worker 3 done
+
+ +
+

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

+ +
+ + +
+ + +

+ Следующий пример: Ограничение скорости (Rate Limiting). +

+ + +
+ + + + diff --git a/public/worker-pools b/public/worker-pools new file mode 100644 index 0000000..734dae3 --- /dev/null +++ b/public/worker-pools @@ -0,0 +1,231 @@ + + + + + Go в примерах: Пулы воркеров (Worker Pools) + + + + +
+

Go в примерах: Пулы воркеров (Worker Pools)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

В этом примере мы рассмотрим, как реализовать +пул воркеров с использованием каналов и +горутин.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "fmt"
+    "time"
+)
+
+ +
+

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

+ +
+ +
func worker(id int, jobs <-chan int, results chan<- int) {
+    for j := range jobs {
+        fmt.Println("worker", id, "started  job", j)
+        time.Sleep(time.Second)
+        fmt.Println("worker", id, "finished job", j)
+        results <- j * 2
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

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

+ +
+ +
    jobs := make(chan int, 100)
+    results := make(chan int, 100)
+
+ +
+

Стартуем 3 воркера, первоначально заблокированных, +т.к. еще нет заданий.

+ +
+ +
    for w := 1; w <= 3; w++ {
+        go worker(w, jobs, results)
+    }
+
+ +
+

Посылаем 5 заданий (jobs) и затем закрываем +канал, сообщая о том что все задания отправлены.

+ +
+ +
    for j := 1; j <= 5; j++ {
+        jobs <- j
+    }
+    close(jobs)
+
+ +
+

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

+ +
+ +
    for a := 1; a <= 5; a++ {
+        <-results
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Наша программа показывает 5 заданий, выполняемых +различными воркерами. Программа занимает всего около +2 секунд, несмотря на выполнение около 5 секунд общей +работы, потому что одновременно работают 3 воркера.

+ +
+ +
$ time go run worker-pools.go 
+worker 1 started  job 1
+worker 2 started  job 2
+worker 3 started  job 3
+worker 1 finished job 1
+worker 1 started  job 4
+worker 2 finished job 2
+worker 2 started  job 5
+worker 3 finished job 3
+worker 1 finished job 4
+worker 2 finished job 5
+
+ +
+ + + +
real    0m2.358s
+
+ +
+ + +

+ Следующий пример: WaitGroups. +

+ + +
+ + + + diff --git a/public/writing-files b/public/writing-files new file mode 100644 index 0000000..18f0906 --- /dev/null +++ b/public/writing-files @@ -0,0 +1,298 @@ + + + + + Go в примерах: Запись файлов (Writing Files) + + + + +
+

Go в примерах: Запись файлов (Writing Files)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Запись файло в Go следует тем же шаблонам, что мы +видели ранее в главе “Чтение”.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "bufio"
+    "fmt"
+    "io/ioutil"
+    "os"
+)
+
+ +
+ + + +
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + + +
func main() {
+
+ +
+

В этом примере показано вот как записать строку +(или только байты) в файл.

+ +
+ +
    d1 := []byte("hello\ngo\n")
+    err := ioutil.WriteFile("/tmp/dat1", d1, 0644)
+    check(err)
+
+ +
+

Для более детальной записи откройте файл для записи.

+ +
+ +
    f, err := os.Create("/tmp/dat2")
+    check(err)
+
+ +
+

Идиоматично откладывать закрытие с помощью defer‘a +сразу после открытия файла.

+ +
+ +
    defer f.Close()
+
+ +
+

Вы можете записать срез байт, как и ожидается.

+ +
+ +
    d2 := []byte{115, 111, 109, 101, 10}
+    n2, err := f.Write(d2)
+    check(err)
+    fmt.Printf("wrote %d bytes\n", n2)
+
+ +
+

Запись строки WriteString так же доступна.

+ +
+ +
    n3, err := f.WriteString("writes\n")
+    fmt.Printf("wrote %d bytes\n", n3)
+
+ +
+

Выполните синхронизацию Sync для сброса записей +в стабильное хранилище.

+ +
+ +
    f.Sync()
+
+ +
+

bufio предоставляет буферизованных писателей +в дополнение к буферизованным читателям, которые +мы видели ранее.

+ +
+ +
    w := bufio.NewWriter(f)
+    n4, err := w.WriteString("buffered\n")
+    fmt.Printf("wrote %d bytes\n", n4)
+
+ +
+

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

+ +
+ +
    w.Flush()
+
+ +
+ + + +
}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Пробуем запустить запись в файл.

+ +
+ +
$ go run writing-files.go 
+wrote 5 bytes
+wrote 7 bytes
+wrote 9 bytes
+
+ +
+

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

+ +
+ +
$ cat /tmp/dat1
+hello
+go
+$ cat /tmp/dat2
+some
+writes
+buffered
+
+ +
+

Далее мы рассмотрим применение некоторых идей файлового +ввода-вывода, которые мы только что видели, к потокам +stdin и stdout.

+ +
+ + +
+ + +

+ Следующий пример: Строковые фильтры (Line Filters). +

+ + +
+ + + + diff --git a/public/xml b/public/xml new file mode 100644 index 0000000..95f1a49 --- /dev/null +++ b/public/xml @@ -0,0 +1,288 @@ + + + + + Go в примерах: XML + + + + +
+

Go в примерах: XML

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go предлагает встроенную поддержку XML и +XML-подобных форматов с пакетом encoding.xml.

+ +
+ + +
+ + + +
package main
+
+ +
+ + + +
import (
+    "encoding/xml"
+    "fmt"
+)
+
+ +
+

Этот тип будет сопоставлен с XML. Как и в примерах JSON, +теги полей содержат директивы для кодера и декодера. +Здесь мы используем некоторые особенности пакета XML: +XMLName определяет имя элемента XML, представляющего +эту структуру; id,attr означает, что поле Id является +атрибутом XML, а не вложенным элементом.

+ +
+ +
type Plant struct {
+    XMLName xml.Name `xml:"plant"`
+    Id      int      `xml:"id,attr"`
+    Name    string   `xml:"name"`
+    Origin  []string `xml:"origin"`
+}
+
+ +
+ + + +
func (p Plant) String() string {
+    return fmt.Sprintf("Plant id=%v, name=%v, origin=%v",
+        p.Id, p.Name, p.Origin)
+}
+
+ +
+ + + +
func main() {
+    coffee := &Plant{Id: 27, Name: "Coffee"}
+    coffee.Origin = []string{"Ethiopia", "Brazil"}
+
+ +
+

Создаем XML, представляющий наш plant; +использование MarshalIndent для создания более +читабельного вывода.

+ +
+ +
    out, _ := xml.MarshalIndent(coffee, " ", "  ")
+    fmt.Println(string(out))
+
+ +
+

Чтобы добавить общий заголовок XML к выводу, добавьте +его явно.

+ +
+ +
    fmt.Println(xml.Header + string(out))
+
+ +
+

Используйте Unmarhshal для парсинга байтов с XML в +структуру данных. Если XML имеет неправильный формат +или не может быть преобразован в Plant, будет +возвращена описательная ошибка.

+ +
+ +
    var p Plant
+    if err := xml.Unmarshal(out, &p); err != nil {
+        panic(err)
+    }
+    fmt.Println(p)
+
+ +
+ + + +
    tomato := &Plant{Id: 81, Name: "Tomato"}
+    tomato.Origin = []string{"Mexico", "California"}
+
+ +
+

Поле parent>child>plant сообщает кодировщику о +необходимости вложения всех plant в +<parent><child>...

+ +
+ +
    type Nesting struct {
+        XMLName xml.Name `xml:"nesting"`
+        Plants  []*Plant `xml:"parent>child>plant"`
+    }
+
+ +
+ + + +
    nesting := &Nesting{}
+    nesting.Plants = []*Plant{coffee, tomato}
+
+ +
+ + + +
    out, _ = xml.MarshalIndent(nesting, " ", "  ")
+    fmt.Println(string(out))
+}
+
+ +
+ + + + + + + + +
+ + + +
$ go run xml.go
+ <plant id="27">
+   <name>Coffee</name>
+   <origin>Ethiopia</origin>
+   <origin>Brazil</origin>
+ </plant>
+<?xml version="1.0" encoding="UTF-8"?>
+ <plant id="27">
+   <name>Coffee</name>
+   <origin>Ethiopia</origin>
+   <origin>Brazil</origin>
+ </plant>
+Plant id=27, name=Coffee, origin=[Ethiopia Brazil]
+ <nesting>
+   <parent>
+     <child>
+       <plant id="27">
+         <name>Coffee</name>
+         <origin>Ethiopia</origin>
+         <origin>Brazil</origin>
+       </plant>
+       <plant id="81">
+         <name>Tomato</name>
+         <origin>Mexico</origin>
+         <origin>California</origin>
+       </plant>
+     </child>
+   </parent>
+ </nesting>
+
+ +
+ + +

+ Следующий пример: Время (Time). +

+ + +
+ + + +