diff --git a/README.md b/README.md index 3ed8d02..73d1b2c 100644 --- a/README.md +++ b/README.md @@ -1011,14 +1011,14 @@ v := make([]int, 100) [^](#Оглавление) -Массивы популярны когда точно известно необходимое количество памяти, чтобы не делать излишних пересозданий, но в первую очередь они являются составной частью для срезов, о которых будет описано в следующем разделе. +Массивы популярны когда точно известно необходимое количество памяти, чтобы не делать излишних пересозданий. Но в первую очередь они являются составной частью срезов, о которых будет описано в следующем разделе. -Какие основные отличия между обращением с массивами между языками Go и C: -* Массивы значений. Присвоение одно массива другому копирует все элементы. -* Если вы передаёте массив в функцию, то передаётся копия массива, а не указатель на него. +Какие основные отличия между обращением с массивами в языках Go и C: +* Массивы значений. Присвоение одного массива другому копирует все элементы; +* Если вы передаёте массив в функцию, то передаётся копия массива, а не указатель на него; * Размер массива является частью массива. Типы `[10]int` и `[20]int` разные. -Массивы могут быть полезными, но дорогими(с точки зрения производительности) и если Вы хотите иметь гибкость и эффективность схожее с поведением в языке C-like, то необходимо использовать в функциях указатели. +Массивы могут быть полезными, но дорогими с точки зрения производительности. Если Вы хотите иметь гибкость и эффективность, схожие с поведением в языке C-like, то в функциях необходимо использовать указатели. ```golang @@ -1043,26 +1043,27 @@ x := Sum(&array) // Note the explicit address-of operator [^](#Оглавление) -Срезы это обёртка для массивов и при этом более общий и мощный, и предоставляет собой более удобный интерфейс по управлению данными, в случаях, когда не известно точное количество элементов и необходимо преобразование размера массивов. -Большинство программ на языке Go, выполнены с использованием срезов, а не простых массивов. +Срезы это обёртка для массивов. И при этом более общая, мощная, и предоставляет собой более удобный интерфейс по управлению данными в случаях, когда не известно точное количество элементов и необходимо преобразование размера массивов. +Большинство программ на языке Go выполнены с использованием срезов, а не простых массивов. -Срез хранит ссылку на массив и поэтому если приравнять срез к другому срезу, то будет тот же массив. -Если срез является аргументом функции, то изменения элементов в срезе будут видны вызывающему данному функцию, это аналогично передаче указателя на базовый массив. -В функция `Read` может принимать в качестве аргумента срез, что равнозначно указателю на массив и длины массива; длина среза указывает верхний предел количество данных которые необходимо прочитать. +Срез хранит ссылку на массив. Поэтому если приравнять срез к другому срезу, то будет тот же массив. +Если срез является аргументом функции, то изменения элементов в срезе будут видны вызывающему данному функцию. Это аналогично передаче указателя на базовый массив. +Функция `Read` может принимать срез в качестве аргумента, что равнозначно указателю на массив и длины массива; длина среза указывает верхний предел количества данных, которые необходимо прочитать. В данном случае тип `File` пакета `os` имеет следующую сигнатуру метода `Read`: ```golang func (f * File) Read(buf []byte) (n int, err error) ``` -Метод возвращает количество прочитанных байт или если есть, то ошибку. +Метод возвращает количество прочитанных байт или ошибку, если она есть. Для чтения первых 32 байт в буфере `buf`, *получить(срезать) часть* буфера. ```golang n, err := f.Read(buf[0:32]) ``` -Такой срез является эффективным. На самом деле, если оставить в стороне эффективность, то следующий пример показывает чтение первых 32 байт из буфера. +Такой срез является эффективным. +На самом деле, если оставить в стороне эффективность, то следующий пример показывает чтение первых 32 байт из буфера. ```golang var n int @@ -1078,10 +1079,10 @@ func (f * File) Read(buf []byte) (n int, err error) ``` Длина среза может меняться, пока не исчерпает размер внутреннего массива. -С помощью встроенной функции `cap` можно узнать *емкость* среза, представляющий максимальную длину среза. +С помощью встроенной функции `cap` можно узнать *емкость* среза, представляющую максимальную длину среза. В следующем примере рассматривается функция для добавления данных в срез. Если данные превышают ёмкость среза, то срез необходимо переопределить. -Функция `Append` возвращает результирующий срез. Функция использует тот факт что использование `len` и `cap` допустимо, даже если у нас имеется нулевой срез `nil` - при этом возвращая 0. +Функция `Append` возвращает результирующий срез. Функция использует тот факт, что использование `len` и `cap` допустимо, даже если у нас имеется нулевой срез `nil` - при этом возвращая 0. ```golang func Append(slice, data []byte) []byte { @@ -1101,14 +1102,11 @@ func Append(slice, data []byte) []byte { } ``` +После этого мы должны вернуть срез, потому что, хотя `Append` +и может изменять элементы `slice`, сам по себе срез (т.е рантайм +структура данных, содержащая указатель, длину и емкость) передается по значению. -**TODO** -We must return the slice afterwards because, although `Append` -can modify the elements of `slice`, the slice itself (the run-time data -structure holding the pointer, length, and capacity) is passed by value. -**-** - -Добавление элементов в срез настолько популярно, что функция `append` стала встроенной. Для того чтобы понять принцип работы данной функции нам необходимо больше информации, поэтому мы вернёмся к этому позже. +Добавление элементов в срез настолько популярно, что функция `append` стала встроенной. Для того чтобы понять принцип работы данной функции, нам необходимо больше информации. Поэтому мы вернёмся к`append` позже. [^](#Оглавление) @@ -1138,11 +1136,12 @@ text := LinesOfText{ Иногда необходимо создавать двухмерные срезы, к примеру при обработки пикселей. Есть 2 способа для этого: - * Первый, создание каждого среза независимо - * Второй, создание простого массива срезов. + * Первый - создание каждого среза независимо; + * Второй - создание простого массива срезов. Наилучший способ выбирается в зависимости от программы. -Если срез можно увеличивать или уменьшать, они должны быть независимы, для того чтобы избежать перезаписи новых строк. Если не требуется изменять размер, то наиболее эффективным был бы способ с создание одним их аллоцированием(инициализацией). +Если срезы могут увеличиваться или уменьшаться, то они должны быть независимы. Это нужно чтобы избежать перезаписи новых строк. Если не требуется изменять размер, то наиболее эффективным был бы способ создания одним их аллоцированием(инициализацией). Рассмотрим оба способа. +Первый - одна строка (и срез) за раз: ```golang // Allocate the top-level slice. @@ -1153,7 +1152,7 @@ for i := range picture { } ``` -с одним созданием: +Второй - один большой срез "режем" на строки: ```golang // Allocate the top-level slice, the same as before. @@ -1173,7 +1172,7 @@ for i := range picture { [^](#Оглавление) Карты - это удобная и мощная встроенная структура данных, связывающая значение одного типа(*ключ (key)*) со значением другого типа (*элемент (element)* или *значение (value)*). -Ключ может быть любого типа, для которого определён оператор равно, как для целых чисел, чисел с плавающей точкой или комплексные числа, строки, указатели, интерфейсы (если динамические типы поддерживают равенство), структуры и массивы. +Ключ может быть любого типа, для которого определён оператор равенства (==): целые числа, числа с плавающей точкой или комплексные числа, строки, указатели, интерфейсы (если динамические типы поддерживают равенство), структуры и массивы. Срезы не используются в качестве ключа для карт, так как равенство не определено для них. Карты, также как и срезы, имеют внутреннюю структуру данных. Если Вы передадите карту в функции и измените содержание карты, то изменения останутся для вызывающего. @@ -1189,15 +1188,16 @@ var timeZone = map[string]int{ } ``` -Добавление и получение значений из карт, синтаксически, выглядит как для массивов или срезов, за тем исключением того что индекс не обязательно должен быть целым числом. +Добавление и получение значений из карт синтаксически похожи на те же самые операции у массивов или срезов. (**но за тем исключением, что индекс не обязательно должен быть целым числом**). ```golang offset := timeZone["EST"] ``` -При попытке получения значения из карты по ключу, которого нет в карте, приведёт к возвращению нулевого значения. -К примеру, если карта содержит целые числа, как описывалось выше, для несуществующего ключа будет возвращено `0`. -Это можно представить как карту у которой в качестве типа значения используется `bool`. Добавление записи в карту это как добавление со значением `true` в карту и дальнейшая простая проверка на индексирование. +Попытка получения значения из карты по ключу, которого нет в карте, приведёт к возвращению нулевого значения. +К примеру, если карта содержит целые числа, поиск несуществующего ключа вернёт `0`. +Это можно представить как карту, у которой в качестве типа значения используется `bool`. +Задайте для записи карты значение true, чтобы поместить значение в набор, а затем протестируйте его с помощью простой индексации. ```golang attended := map[string]bool{ @@ -1211,8 +1211,8 @@ if attended[person] { // will be false if person is not in the map } ``` -Иногда необходимо отличать отсутствие записи от нулевого значения. К примеру, есть ли запись для `"UTC"` или это пустая строка потому что отсутствует значение в карте? -Для того чтобы отличить - Вы можете использовать множественное присвоение. +Иногда необходимо отличать отсутствие записи от нулевого значения. К примеру, есть ли запись для `"UTC"` или же это пустая строка, потому что значение вообще отсутствует в карте? +Для того чтобы это отличить - можно использовать множественное присвоение. ```golang var seconds int @@ -1220,9 +1220,9 @@ var ok bool seconds, ok = timeZone[tz] ``` -Очевидная причина называть данную идиому "запятая ок". -В данном примере, если `tz` существует, то `seconds` будет иметь необходимое значение и `ok` будет `true`, но если не существует, то `seconds` будет иметь нулевое значение а `ok` будет `false`. -В следующем примере, представлена функция с хорошим описанием ошибки: +По очевидным причинам данная идиома называется "запятая ок". +В данном примере, если `tz` существует, то `seconds` будет иметь необходимое значение и `ok` будет `true`; но если `tz` не существует, то `seconds` будет иметь нулевое значение, а `ok` будет `false`. +В следующем примере представлена функция с хорошим описанием ошибки: ```golang func offset(tz string) int { @@ -1240,7 +1240,7 @@ func offset(tz string) int { _ , present := timeZone[tz] ``` -Для удаления записи из карты, необходимо использовать встроенную функцию `delete`, где в качестве аргументов задаётся карта и ключ для удаления. +Для удаления записи из карты необходимо использовать встроенную функцию `delete`, где в качестве аргументов задаётся карта и ключ для удаления. Данная операция безопасна, даже если данного ключа уже нет в карте. ```golang @@ -1253,9 +1253,9 @@ delete(timeZone, "PDT") // Now on Standard Time [^](#Оглавление) -Форматированная печать в Go подобна стилю в языке C `printf`, но более богаче и более обобщенное. Необходимые функции расположены в пакете `fmt` и имеют названия с большой буквы: `fmt.Printf`, `fmt.Fprintf`, `fmt.Sprintf` и так далее. Функции (`Sprintf` и другие) возвращают строку, а не заполняют предоставленный буфер. +Форматированная печать в Go подобна стилю в языке C `printf`, но более богаче и обобщенее. Необходимые функции расположены в пакете `fmt` и имеют названия с большой буквы: `fmt.Printf`, `fmt.Fprintf`, `fmt.Sprintf` и так далее. Строковые функции (`Sprintf` и другие) возвращают строку, а не заполняют предоставленный буфер. -Вам нет необходимости в создании форматировании строк, так как для каждой `Printf`, `Fprintf` and `Sprintf` есть пара функций к примеру `Print` и `Println`. +Вам нет необходимости предусматривать форматирование строк, так как для каждой `Printf`, `Fprintf` and `Sprintf` есть пара функций. К примеру, `Print` и `Println`. Данные функции не берут формат строки, а вместо этого устанавливают форматирование по умолчанию для каждого аргумента. Функция `Println` также добавляет пробел между аргументами и добавляет разрыв строки в конце строки. Функция `Print` добавляет пробел только той же строке. В примере каждая строка производит одинаковый результат. @@ -1267,11 +1267,10 @@ fmt.Println("Hello", 23) fmt.Println(fmt.Sprint("Hello ", 23)) ``` -Для форматированной печати функцией `fmt.Fprint` и его друзьями, принимают в качестве первого аргумента объект реализующий интерфейс `io.Writer`. -Значения `os.Stdout` и `os.Stderr` знакомы. +Отформатированные функции печати (`fmt.Fprint` и другие) принимают в качестве первого аргумента любой объект, реализующий интерфейс `io.Writer`; значения `os.Stdout` и `os.Stderr` нам уже знакомы. -Следующее расходится с реализацией на языке С. Первое, числовые форматы `%d` не имеют флагов знаковости или размера; Вместо этого, функции печати используют тип аргумента для задания свойств. +Следующее расходится с реализацией на языке С. Первое, числовые форматы `%d` не имеют флагов знаковости или размера; Вместо этого функции печати используют тип аргумента для задания этих свойств. ```golang var x uint64 = 1<<64 - 1 @@ -1284,7 +1283,7 @@ fmt.Printf("%d %x; %d %x\n", x, x, int64(x), int64(x)) 18446744073709551615 ffffffffffffffff; -1 -1 ``` -Если вы используете соглашение по умолчанию, то для целых чисел можно использовать обобщенный формат `%v` (для "значений"); и результат будет одинаков как для `Print` так и для `Println`. +Если вы используете соглашение по умолчанию, то для целых чисел можно использовать обобщенный формат `%v` (*значение*, *value*); и результат будет одинаков как для `Print`, так и для `Println`. Более того, данный формат может напечатать *любое* значение, даже срез, структуру или карту. Печать карты временной зоны из предыдущего раздела. @@ -1300,7 +1299,7 @@ map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200] ``` Ключи карт могут быть напечатаны в любом порядке. -При печати структуры, с аннотацией `%+v` производиться печать полей структуры с их именами и для каждого значения с форматом `%#v` печатается значение с полным синтаксисом Go. +При печати структуры, с аннотацией `%+v` производиться печать полей структуры с их именами и для каждого значения; с форматом `%#v` печатается значение с полным синтаксисом Go. ```golang type T struct { @@ -1344,7 +1343,7 @@ fmt.Printf("%T\n", timeZone) map[string] int ``` -Если Вы хотите свой собственный формат типа, то для этого достаточно метод с сигнатурой `String() string` для Вашего типа. +Если Вы хотите свой собственный формат типа, то для этого достаточно метода с сигнатурой `String() string` для Вашего типа. Для нашего простого примера, тип `T`, выглядит следующим образом. ```golang @@ -1384,17 +1383,15 @@ func (m MyString) String() string { } ``` -Другой способ печати это допустить печать функции аргументов напрямую в другую функцию. +Другой способ печати - это допустить печать функции аргументов напрямую в другую функцию. Сигнатура `Printf` используется для типов `...interface{}`, что допускает произвольное число аргументов, которые добавляются после формата *format*. ```golang func Printf(format string, v ...interface{}) (n int, err error) { ``` -**TODO** -Within the function `Printf`, `v` acts like a variable of type `[]interface{}` but if it is passed to another variadic function, it acts like a regular list of arguments. -Here is the implementation of the function `log.Println` we used above. It passes its arguments directly to `fmt.Sprintln` for the actual formatting. -**-** +Внутри данной функции `Printf` переменная `v` ведёт себя как переменная типа `[]interface{}`. Но, попав в другую вариативную функцию([wiki](https://ru.wikipedia.org/wiki/%D0%92%D0%B0%D1%80%D0%B8%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F)) (т.е функцию с переменным числом аргументов), эта же переменная будет вести себя как обычный список аргументов. +Вот реализация функции `log.Println`, которую мы использовали выше. Она передает свои аргументы непосредственно в `fmt.Sprintln` для текущего форматирования. ```golang // Println prints to the standard logger in the manner of fmt.Println. @@ -1403,11 +1400,11 @@ func Println(v ...interface{}) { } ``` -Запись `...` после `v` при вызове функции `Sprintln` объявляет компилятору о том что `v` является списком аргументов; с другой стороны `v` воспринимается как простой срез аргументов. +Запись `...` после `v` при вызове функции `Sprintln` указывает компилятору что `v` является списком аргументов; с другой стороны `v` воспринимается как простой срез аргументов. Если Вам необходимо большее количество информации, то смотрите документацию `godoc` в пакете `fmt`. -Кстати параметр `...` может иметь тип, для примера`...int` для функции определения минимума используется список целых чисел: +Кстати, параметр `...` может иметь тип. Для примера`...int` для функции определения минимума (`func Min` ниже) используется список целых чисел: ```golang func Min(a ...int) int { @@ -1427,17 +1424,17 @@ func Min(a ...int) int { [^](#Оглавление) -В настоящий момент? пришел момент для разъяснения конструкции встроенной функции `append`. Сигнатура функции `append` отличается от ранее описанной функции `Append`. -Схематично, выглядит следующим образом: +Пришел момент для разъяснения конструкции встроенной функции `append`. Сигнатура функции `append` отличается от ранее описанной функции `Append`. +Схематично выглядит следующим образом: ```golang func append(slice []*T*, elements ...*T*) []*T* ``` -где *T* любой тип. Вы не можете написать в языке Go функцию в которой `T` определена вызывающим. Поэтому необходима поддержка компилятора для функции `append`. +где *T* любой тип. Вы не можете написать в языке Go функцию, в которой `T` определена вызывающей стороной. Поэтому для функции `append` необходима поддержка компилятора. Данная функция `append` добавляет элемент в конец среза и возвращает результат. -Причина возврата результата, в том что как и в рукописной функции `Append` массив может измениться. +Причина возврата результата в том, что, как и в рукописной функции `Append`, массив может измениться. Простой пример: ```golang @@ -1449,7 +1446,8 @@ fmt.Println(x) печатает `[1 2 3 4 5 6]`. Итак, `append` работает в принципе как `Printf` с произвольным количеством аргументов. -Но что если необходимо добавить срез в срез, как в нашей реализации `Append`? Все просто: используем `...` который мы использовали в `Output`. Вот пример кода для получение того же результата. +Но что если необходимо добавить срез в срез, как в нашей реализации `Append`? +Все просто: используем `...` который мы использовали в `Output`. Вот пример кода для получение того же результата. ```golang x := []int{1,2,3} @@ -1467,8 +1465,8 @@ fmt.Println(x) [^](#Оглавление) -Инициализация в языке Go более мощный инструмент нежели в языках С или С++. -Даже сложные структуры можно инициализировать. Упорядочивание между инициализируемыми объектами разных пакетов, обрабатывается корректно. +Инициализация в языке Go - более мощный инструмент, нежели в языках С или С++. +Даже сложные структуры можно инициализировать. Упорядочивание обрабатывается корректно даже между инициализируемыми объектами разных пакетов. [^](#Оглавление) @@ -1478,11 +1476,11 @@ fmt.Println(x) Константы в Go это просто константы. -Они создаются во время компиляции даже если она определена в локальной функции и могут быть цифры, символы(руны), строки или булевый тип. +Они создаются во время компиляции, даже если она определена в локальной функции. Константами могут быть только цифры, символы(руны), строки или булевый тип. Из-за ограничения времени компиляции, компилятор должен определять какие выражения могут быть константами. К примеру, выражение `1<<3` это константное выражение, в то время как выражение `math.Sin(math.Pi/4)` не является константой, так как вызывает функцию `math.Sin` требующую выполнения по время выполнения. -В языке Go, перечисление констант производиться с помощью перечислителя **`iota`**. Так как `iota` может быть неявно повторяемой для выражения или выражений, то легко можно строить сложные наборы значений. +В языке Go перечисление констант производиться с помощью перечислителя **`iota`**. Так как `iota` может быть неявно повторяемой для выражения или выражений, то легко можно строить сложные наборы значений. ```golang @@ -1510,10 +1508,7 @@ const ( ) ``` -Использование функции `String` к пользовательским типам производить печать необходимым образом. -**TODO** -Although you'll see it most often applied to structs, this technique is also useful for scalar types such as floating-point types like `ByteSize`. -**-** +Возможность прикрепить метод, такой как String, к любому определяемому пользователем типу, позволяет произвольным значениям автоматически форматировать себя для печати. Хотя вы чаще всего будете применять его к структурам, этот метод также полезен для скалярных типов, таких как типы с плавающей запятой (например, ByteSize). ```golang //See code "/doc/progs/eff_bytesize.go" @@ -1544,7 +1539,7 @@ func (b ByteSize) String() string { Выражение `YB` печатается как `1.00YB`, когда `ByteSize(1e13)` печатает как `9.09TB`. -Используемый здесь `Sprintf` в функции `String` типа `ByteSize` безопасна(не вызывается рекурсивно), не потому что происходит конвертирование, а потому что вызывается функция `Sprintf` с `%f`, который не строковый формат:`Sprintf` будет вызывать функцию `String`, функцию которой необходима строка и `%f` число с плавающей точкой. +Использование здесь `Sprintf` в функции `String` типа `ByteSize` безопасно, ведь не вызывается рекурсивно. Но безопасно оно не потому что происходит конвертирование, а потому что вызывается функция `Sprintf`(для строкового формата) с `%f`(для не строкового формата). То есть когда `Sprintf` будет нужна строка - она будет вызывать функцию `String`; когда будет нужно число с плавающей точкой - `Sprintf` вызовет `%f`. [^](#Оглавление) @@ -1569,10 +1564,10 @@ var ( [^](#Оглавление) -Каждый исходный код может определить свою первичную функцию `init` для обязательных настройки. (На самом деле файл может иметь несколько функций `init`.) +Каждый исходный код может определить свою первичную функцию `init` для обязательных настройки. (На самом деле файл может иметь несколько функций `init`.) Функция `init` вызывается после всех объявлений переменных и после всех объявлений переменных всех пакетов. -Общее применение функции `init` в проверки или починки состояния программы до начала реального исполнения. +Помимо инициализаций, которые не могут быть выражены как декларации, обычное использование функций `init` заключается в проверке или исправлении правильности состояния программы ДО начала реального выполнения. ```golang func init() {