HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Предлагаем вашему вниманию<strong>подборку полезных советов</strong>, которые будут интересны разработчикам Go. При их использовании учитывайте, что далеко не все из этих рекомендаций можно применять в production, так как вы рискуете остаться без премии!</p>
1 <p>Предлагаем вашему вниманию<strong>подборку полезных советов</strong>, которые будут интересны разработчикам Go. При их использовании учитывайте, что далеко не все из этих рекомендаций можно применять в production, так как вы рискуете остаться без премии!</p>
2 <h2>1. Как заставить пользователей пакетов использовать имена полей в составных литералах для структур?</h2>
2 <h2>1. Как заставить пользователей пакетов использовать имена полей в составных литералах для структур?</h2>
3 <p>Разработчики пакетов могут добавлять неэкспортируемые поля нулевого размера в определения структур. В этом случае компилятор не позволит использовать составные литералы с неименованными полями для создания экземпляров структур.</p>
3 <p>Разработчики пакетов могут добавлять неэкспортируемые поля нулевого размера в определения структур. В этом случае компилятор не позволит использовать составные литералы с неименованными полями для создания экземпляров структур.</p>
4 <p>Пример:</p>
4 <p>Пример:</p>
5 // foo.go package foo type Config struct { _ [0]int Name string Size int } // main.go package main import "foo" func main() { //_ = foo.Config{[0]int{}, "bar", 123} // error _ = foo.Config{Name: "bar", Size: 123} // compile ok }<p>Не рекомендуется размещать неэкспортируемые поля нулевого размера в структуре последними, поскольку<a>это может увеличить размер структуры</a>.</p>
5 // foo.go package foo type Config struct { _ [0]int Name string Size int } // main.go package main import "foo" func main() { //_ = foo.Config{[0]int{}, "bar", 123} // error _ = foo.Config{Name: "bar", Size: 123} // compile ok }<p>Не рекомендуется размещать неэкспортируемые поля нулевого размера в структуре последними, поскольку<a>это может увеличить размер структуры</a>.</p>
6 <h2>2. Как создать структурный тип, который невозможно использовать в операциях сравнения?</h2>
6 <h2>2. Как создать структурный тип, который невозможно использовать в операциях сравнения?</h2>
7 <p>В некоторых случаях необходимо запретить использование пользовательских структурных типов в качестве ключей отображения. Для этого достаточно добавить в структуру поле нулевого размера неэкспортируемого типа, для которого не реализована операция сравнения.</p>
7 <p>В некоторых случаях необходимо запретить использование пользовательских структурных типов в качестве ключей отображения. Для этого достаточно добавить в структуру поле нулевого размера неэкспортируемого типа, для которого не реализована операция сравнения.</p>
8 <p>Пример:</p>
8 <p>Пример:</p>
9 package main type T struct { dummy [0]func() AnotherField int } var x map[T]int // ошибка компилятора: тип Т не может использоваться в качестве ключа отображения (invalid map key type T) func main() { var a, b T _ = a == b // ошибка компилятора: недопустимая операция (invalid operation) }<h2>3. Не используйте оператор присваивания с взаимозависимыми выражениями</h2>
9 package main type T struct { dummy [0]func() AnotherField int } var x map[T]int // ошибка компилятора: тип Т не может использоваться в качестве ключа отображения (invalid map key type T) func main() { var a, b T _ = a == b // ошибка компилятора: недопустимая операция (invalid operation) }<h2>3. Не используйте оператор присваивания с взаимозависимыми выражениями</h2>
10 <p>В текущей версии компилятора (Go 1.12) существует<a>неопределенность порядка вычисления значений, присваиваемых одним оператором</a>нескольким переменным с использованием взаимозависимых выражений. Таким образом, следует разделить оператор множественного присваивания значений на несколько присваиваний отдельных значений, если между выражениями, значения которых присваиваются, есть зависимости либо если вы не уверены, что таких зависимостей нет.</p>
10 <p>В текущей версии компилятора (Go 1.12) существует<a>неопределенность порядка вычисления значений, присваиваемых одним оператором</a>нескольким переменным с использованием взаимозависимых выражений. Таким образом, следует разделить оператор множественного присваивания значений на несколько присваиваний отдельных значений, если между выражениями, значения которых присваиваются, есть зависимости либо если вы не уверены, что таких зависимостей нет.</p>
11 <p>В некоторых неудачных вариантах присваивания отдельных значений также возможен неопределенный порядок вычисления выражений. Например, следующая программа выводит [7 0 9], [0 8 9] или [7 8 9] в зависимости от реализации компилятора.</p>
11 <p>В некоторых неудачных вариантах присваивания отдельных значений также возможен неопределенный порядок вычисления выражений. Например, следующая программа выводит [7 0 9], [0 8 9] или [7 8 9] в зависимости от реализации компилятора.</p>
12 package main import "fmt" var a = &amp;[]int{1, 2, 3} var i int func f() int { i = 1 a = &amp;[]int{7, 8, 9} return 0 } func main() { // Порядок вычисления a, i // и f() не определен. (*a)[i] = f() fmt.Println(*a) }<p>Иными словами, результатом вызова функции при присвоении значения может стать изменение значений других выражений в этом же операторе. Более подробную информацию о порядке вычисления и инициализации значений см. в<a>этой статье</a>.</p>
12 package main import "fmt" var a = &amp;[]int{1, 2, 3} var i int func f() int { i = 1 a = &amp;[]int{7, 8, 9} return 0 } func main() { // Порядок вычисления a, i // и f() не определен. (*a)[i] = f() fmt.Println(*a) }<p>Иными словами, результатом вызова функции при присвоении значения может стать изменение значений других выражений в этом же операторе. Более подробную информацию о порядке вычисления и инициализации значений см. в<a>этой статье</a>.</p>
13 <h2>4. Варианты реализации оператора for i in 0..N, используемого в других языках</h2>
13 <h2>4. Варианты реализации оператора for i in 0..N, используемого в других языках</h2>
14 <p>Для имитации такого цикла можно осуществить перебор массива с элементами нулевого размера или использовать пустой (nil) указатель на массив.</p>
14 <p>Для имитации такого цикла можно осуществить перебор массива с элементами нулевого размера или использовать пустой (nil) указатель на массив.</p>
15 <p>Пример:</p>
15 <p>Пример:</p>
16 package main import "fmt" func main() { const N = 5 for i := range [N]struct{}{} { fmt.Println(i) } for i := range [N][0]int{} { fmt.Println(i) } for i := range (*[N]int)(nil) { fmt.Println(i) } }<h2>5. Значения некоторых типов стандартных пакетов не предназначены для копирования</h2>
16 package main import "fmt" func main() { const N = 5 for i := range [N]struct{}{} { fmt.Println(i) } for i := range [N][0]int{} { fmt.Println(i) } for i := range (*[N]int)(nil) { fmt.Println(i) } }<h2>5. Значения некоторых типов стандартных пакетов не предназначены для копирования</h2>
17 <p>В частности, не рекомендуется выполнять копирование значений типов<strong>bytes.Buffer</strong>и<strong>strings.Builder</strong>, а также типов пакета<strong>sync</strong>(в некоторых особых случаях безопасное копирование значений данных типов возможно, но лучше их не копировать).</p>
17 <p>В частности, не рекомендуется выполнять копирование значений типов<strong>bytes.Buffer</strong>и<strong>strings.Builder</strong>, а также типов пакета<strong>sync</strong>(в некоторых особых случаях безопасное копирование значений данных типов возможно, но лучше их не копировать).</p>
18 <p>Реализация типа<strong>strings.Builder</strong>отслеживает некорректные копии значений этого типа. При обнаружении такой копии в процессе исполнения программы возникает состояние "паники" (panic).</p>
18 <p>Реализация типа<strong>strings.Builder</strong>отслеживает некорректные копии значений этого типа. При обнаружении такой копии в процессе исполнения программы возникает состояние "паники" (panic).</p>
19 <p>Пример:</p>
19 <p>Пример:</p>
20 package main import "strings" func main() { var b strings.Builder b.WriteString("hello ") var b2 = b b2.WriteString("world!") // паника }<p>При копировании значений типов стандартного пакета<strong>sync</strong>команда<strong>go vet</strong>из комплекта Go SDK выдаст соответствующее предупреждение.</p>
20 package main import "strings" func main() { var b strings.Builder b.WriteString("hello ") var b2 = b b2.WriteString("world!") // паника }<p>При копировании значений типов стандартного пакета<strong>sync</strong>команда<strong>go vet</strong>из комплекта Go SDK выдаст соответствующее предупреждение.</p>
21 // demo.go package demo import "sync" func f(m sync.Mutex) { // warning m.Lock() defer m.Unlock() // do something ... } $ go vet demo.go ./demo.go:5: f passes lock by value: sync.Mutex<p>Попытка копирования значений<strong>bytes.Buffer</strong>не будет обнаружена ни в процессе выполнения, ни командой<strong>go vet</strong>. Так что, будьте внимательны и не копируйте их.</p>
21 // demo.go package demo import "sync" func f(m sync.Mutex) { // warning m.Lock() defer m.Unlock() // do something ... } $ go vet demo.go ./demo.go:5: f passes lock by value: sync.Mutex<p>Попытка копирования значений<strong>bytes.Buffer</strong>не будет обнаружена ни в процессе выполнения, ни командой<strong>go vet</strong>. Так что, будьте внимательны и не копируйте их.</p>
22 <p><em>Это первый блок советов по Go. Продолжение следует, следите за новостями!</em></p>
22 <p><em>Это первый блок советов по Go. Продолжение следует, следите за новостями!</em></p>
23 <p><a>Источник</a></p>
23 <p><a>Источник</a></p>
24  
24