Введение
Потратьте всего 12 минут, чтобы писать эффективный код на Go.
№ 1: правильный отступ
С хорошим отступом код удобнее для восприятия. Используйте символы табуляции или пробелы последовательно, отдавая предпочтение символам табуляции, и следуйте стандартному соглашению Go по применению отступов.
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println("Hello, World!")
}
}
Форматируйте код автоматически с отступом по стандарту Go, запуская gofmt
:
$ gofmt -w your_file.go
№ 2: правильный импорт пакетов
Импортируйте только нужные пакеты и форматируйте раздел импорта, разделяя их по группам: пакеты стандартной библиотеки, сторонние и собственные.
package main
import (
"fmt"
"math/rand"
"time"
)
№ 3: информативные названия переменных и функций
- Используйте содержательные названия, передающие назначение переменной.
- CamelCase: начинайте со строчной буквы, а первую букву каждого последующего слова в названии делайте заглавной.
- Для временных переменных с небольшой областью действия допустимы короткие, лаконичные названия.
- Избегайте непонятных аббревиатур и акронимов в пользу информативных названий.
- Сохраняйте единообразие именования во всей кодовой базе.
package main
import "fmt"
func main() {
// Объявляем переменные с содержательными названиями
userName := "John Doe" // CamelCase: начинаем со строчной буквы, а последующие слова с заглавной.
itemCount := 10 // Короткие, лаконичные названия для переменных с небольшой областью действия.
isReady := true // Избегаем непонятных аббревиатур и акронимов.
// Отображаем значения переменных
fmt.Println("User Name:", userName)
fmt.Println("Item Count:", itemCount)
fmt.Println("Is Ready:", isReady)
}
// Для переменных, описанных в спецификации пакета, используем mixedCase: начинаем со строчной буквы, а следующее слово с заглавной.
var exportedVariable int = 42
// Названия функций должны быть информативными
func calculateSumOfNumbers(a, b int) int {
return a + b
}
// Сохраняем единообразие именования во всей кодовой базе.
№ 4: ограничение длины строки
Чтобы повысить удобство восприятия, по возможности ограничивайте длину строк кода 80 символами.
package main
import (
"fmt"
"math"
)
func main() {
result := calculateHypotenuse(3, 4)
fmt.Println("Hypotenuse:", result)
}
func calculateHypotenuse(a, b float64) float64 {
return math.Sqrt(a*a + b*b)
}
Примечание: есть мнение о необходимости ограничивать строки кода 120, 150 и даже 180 символами.
№ 5: константы для магических значений
Избегайте магических значений в коде. Это жестко заданные числа или строки, разбросанные по всему коду, из-за нехватки контекста трудно понять их назначение. Чтобы повысить сопровождаемость кода, определяйте для них константы:
package main
import "fmt"
const (
// Определяем константу для максимального числа повторных попыток
MaxRetries = 3
// Определяем константу для времени ожидания по умолчанию в секундах
DefaultTimeout = 30
)
func main() {
retries := 0
timeout := DefaultTimeout
for retries < MaxRetries {
fmt.Printf("Attempting operation (Retry %d) with timeout: %d seconds\n", retries+1, timeout)
// ... Логика кода здесь ...
retries++
}
}
№ 6: обработка ошибок
В Go разработчикам рекомендуется обрабатывать ошибки явно. И вот причины:
- Безопасность: при обработке ошибок гарантируется, что неожиданные проблемы не приведут к панике или внезапному аварийному завершению программы.
- Четкость: с явной обработкой ошибок код удобнее для восприятия, проще определить места возникновения ошибок.
- Отладка: при обработке ошибок получается ценная информация для отладки и устранения проблем.
Создадим простую программу для корректного считывания файла и обработки ошибок:
package main
import (
"fmt"
"os"
)
func main() {
// Открываем файл
file, err := os.Open("example.txt")
if err != nil {
// Обрабатываем ошибку
fmt.Println("Error opening the file:", err)
return
}
defer file.Close() // По завершении файл закрываем
// Считываем из файла
buffer := make([]byte, 1024)
_, err = file.Read(buffer)
if err != nil {
// Обрабатываем ошибку
fmt.Println("Error reading the file:", err)
return
}
// Выводим содержимое файла
fmt.Println("File content:", string(buffer))
}
Примечание: пример совершенствуется добавлением обработки ошибок в функцию defer
при вызове file.Close()
— имеется возможность возвращения ошибки.
№ 7: глобальные переменные
Избегайте глобальных переменных. Их применение чревато непредсказуемым поведением, усложнением отладки и переиспользования кода, появлением ненужных зависимостей между различными частями программы. Отдавайте предпочтение передаче данных через параметры функций и возвращению значений.
Как избегать глобальных переменных, проиллюстрируем простой программой на Go:
package main
import (
"fmt"
)
func main() {
// Объявляем и инициализируем переменную в функции «main»
message := "Hello, Go!"
// Вызываем функцию, использующую локальную переменную
printMessage(message)
}
// «printMessage» — это функция, принимающая параметр
func printMessage(msg string) {
fmt.Println(msg)
}
№ 8: структуры для сложных данных
Объединяйте поля и методы связанных данных в структуры. Так объединяются соответствующие переменные, а код становится организованнее и удобнее для восприятия.
Вот полный пример программы с применением структур в Go:
package main
import (
"fmt"
)
// Определяем структуру «Person» для представления информации о человеке.
type Person struct {
FirstName string // Имя
LastName string // Фамилия
Age int // Возраст
}
func main() {
// Создаем экземпляр структуры «Person» и инициализируем ее поля.
person := Person{
FirstName: "John",
LastName: "Doe",
Age: 30,
}
// Получаем доступ к значениям полей структуры и выводим их.
fmt.Println("First Name:", person.FirstName) // Выводим имя
fmt.Println("Last Name:", person.LastName) // Выводим фамилию
fmt.Println("Age:", person.Age) // Выводим возраст
}
№ 9: комментарии
Для объяснения функциональности кода, особенно сложных или неочевидных частей, добавляйте комментарии.
Однострочные комментарии начинаются с //
, комментируйте ими конкретные строки кода:
package main
import "fmt"
func main() {
// Это однострочный комментарий
fmt.Println("Hello, World!") // Выводим приветствие
}
Многострочные комментарии помещаются между символами /*
и */
, эти комментарии длиннее или занимают несколько строк:
package main
import "fmt"
func main() {
/*
Это многострочный комментарий.
Он может занимать несколько строк.
*/
fmt.Println("Hello, World!") // Выводим приветствие
}
Комментарии к функциям добавляются для объяснения их назначения, параметров и возвращаемых значений, для этих комментариев используйте стиль godoc:
package main
import "fmt"
// «greetUser» приветствует пользователя по имени.
// Параметры:
// имя (строка): имя приветствуемого пользователя.
// Возвращается:
// строка: приветственное сообщение.
func greetUser(name string) string {
return "Hello, " + name + "!"
}
func main() {
userName := "Alice"
greeting := greetUser(userName)
fmt.Println(greeting)
}
Комментарии к пакету добавляются в верхней части файлов Go для описания назначения пакета, используйте тот же стиль godoc:
package main
import "fmt"
// Это пакет «main» программы Go.
// Он содержит функцию точки входа «main».
func main() {
fmt.Println("Hello, World!")
}
№ 10: горутины для параллельного выполнения
Чтобы параллельные операции выполнялись эффективно, используйте горутины. Это легкие, параллельно выполняемые потоки на Go, благодаря которым функции запускаются одновременно. И без накладных расходов, характерных для традиционных потоков. С горутинами пишутся эффективные программы с высокой степенью параллелизма.
Вот простой пример:
package main
import (
"fmt"
"time"
)
// Функция, запускаемая параллельно
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Printf("%d ", i)
time.Sleep(100 * time.Millisecond)
}
}
// Функция, запускаемая в горутине «main»
func main() {
// Запускаем горутину
go printNumbers()
// Продолжаем выполнение «main»
for i := 0; i < 2; i++ {
fmt.Println("Hello")
time.Sleep(200 * time.Millisecond)
}
// Выполнение горутины обязательно завершается перед выходом
time.Sleep(1 * time.Second)
}
Читайте также:
Читайте нас в Telegram, VK и Дзен
Перевод статьи Golang Da: Golang Best Practices (Top 20)