Экспорт идентификаторов и соглашения об аббревиатурах
Краткое описание
В этом уроке изучаем систему видимости идентификаторов в Go через регистр первой буквы: заглавная делает сущность публичной (экспортируемой), строчная — приватной. Разбираем, как это работает с переменными, функциями и структурами, и учимся правильно писать аббревиатуры согласно Go conventions.
Ключевые концепции
Экспорт через регистр
В Go нет ключевых слов public/private. Видимость определяется регистром первой буквы идентификатора:
Заглавная буква → экспортируемый (публичный):
var PublicVariable int = 100 // доступна вне пакета
func ExportedFunction() { } // доступна вне пакета
type ExportedStruct struct { } // доступна вне пакета
Строчная буква → неэкспортируемый (приватный):
var privateVariable int = 200 // только внутри пакета
func internalFunction() { } // только внутри пакета
type internalStruct struct { } // только внутри пакета
Область применения
Правило регистра работает для всех сущностей:
- Переменные:
PublicVarvsprivateVar - Функции:
ExportedFunc()vsinternalFunc() - Структуры:
PublicStructvsprivateStruct - Поля структур:
User.Name(public) vsUser.password(private) - Методы:
obj.PublicMethod()vsobj.privateMethod() - Константы:
MaxValuevsmaxValue - Интерфейсы:
Readervsreader
Работа с пакетами
Создание пакета с экспортируемыми сущностями
Файл: testmodule/models.go
package testmodule
// Экспортируемая переменная (доступна вне пакета)
var PublicVariable int = 100
// Неэкспортируемая переменная (только внутри testmodule)
var privateVariable int = 200
Использование в другом пакете
Файл: main.go
package main
import (
"ex06namingconventions/testmodule"
"fmt"
)
func main() {
// OK - PublicVariable экспортируется
fmt.Println(testmodule.PublicVariable) // 100
// ОШИБКА - privateVariable не экспортируется
// fmt.Println(testmodule.privateVariable)
// cannot refer to unexported name testmodule.privateVariable
}
Go автоматически подчёркивает попытки обращения к неэкспортируемым идентификаторам в IDE.
Структуры с разными уровнями видимости
package models
// Экспортируемая структура
type User struct {
Name string // экспортируемое поле
Age int // экспортируемое поле
password string // приватное поле
}
// Приватная структура
type session struct {
token string
}
Использование:
package main
import "myapp/models"
func main() {
user := models.User{
Name: "Иван", // OK
Age: 25, // OK
// password: "123" // ОШИБКА - поле приватное
}
// var s models.session // ОШИБКА - тип приватный
}
Соглашения об аббревиатурах
Правило: все заглавные или все строчные
В Go аббревиатуры пишутся либо полностью заглавными, либо полностью строчными — но не смешанно:
Правильно:
var userID int = 123 // ID (не userId)
var HTTPServer string = "nginx" // HTTP (не HttpServer)
var urlPath string = "/api" // url (не uRLPath)
var xmlData string = "<root/>" // xml (не xMLData)
var apiKey string = "secret" // api (не aPIKey)
Неправильно (но часто встречается в других языках):
// var userId int = 123 // ❌ C#/Java стиль
// var HttpServer string = "..." // ❌ смешанный регистр
// var uRLPath string = "..." // ❌ частично заглавные
Распространённые аббревиатуры
| Аббревиатура | Правильно (экспорт) | Правильно (приват) | Неправильно |
|---|---|---|---|
| ID | UserID |
userID |
UserId, userId |
| HTTP | HTTPServer |
httpServer |
HttpServer |
| URL | URLPath |
urlPath |
UrlPath |
| XML | XMLData |
xmlData |
XmlData |
| API | APIKey |
apiKey |
ApiKey |
| JSON | JSONResponse |
jsonResponse |
JsonResponse |
| HTML | HTMLTemplate |
htmlTemplate |
HtmlTemplate |
| SQL | SQLQuery |
sqlQuery |
SqlQuery |
| DB | DBConnection |
dbConnection |
DbConnection |
Best Practices именования
1. camelCase для локальных переменных
var userName string = "Сергей"
var userAge int = 25
var totalStudentsCount int = 150
2. Префикс is/has для булевых переменных
var isActive bool = true
var isSuccess bool = true
var hasAccess bool = false
var canEdit bool = true
Это делает код читаемым как естественный язык:
if isActive && hasAccess {
// разрешить действие
}
3. Описательные имена для больших scope
Чем шире область видимости, тем подробнее должно быть имя:
// Глобальная/экспортируемая
var MaxConnectionTimeout int = 3000
var DefaultDatabaseConnectionString string = "..."
// Локальная в функции
var timeout int = 30
var conn *sql.DB
4. Избегайте бессмысленных имён
Плохо:
var foo int
var bar string
var temp float64
var x User
Хорошо:
var studentScore int
var errorMessage string
var averagePrice float64
var currentUser User
5. Контекст определяет длину
В глобальной области:
var CurrentUserAuthenticationToken string = "abc123"
В узком контексте:
func ProcessUser(id int) {
// id понятно из контекста функции
}
for i := 0; i < len(items); i++ {
// i стандартно для счётчика
}
Практика
Полный пример из урока
testmodule/models.go:
package testmodule
// Экспортируемые (публичные) идентификаторы
var PublicVariable int = 100
// Неэкспортируемые (приватные) идентификаторы
var privateVariable int = 200
main.go:
package main
import (
"ex06namingconventions/testmodule"
"fmt"
)
func main() {
// Локальные переменные (camelCase)
var userName string = "Сергей"
var userAge int = 25
var totalStudentsCount int = 150
var isActive bool = true
var maxConnectionTimeout int = 3000
fmt.Printf("userName: %s\n", userName)
fmt.Printf("userAge: %d\n", userAge)
fmt.Printf("totalStudentsCount: %d\n", totalStudentsCount)
fmt.Printf("isActive: %t\n", isActive)
fmt.Printf("maxConnectionTimeout: %d\n", maxConnectionTimeout)
// Использование экспортируемых идентификаторов
fmt.Printf("PublicVariable: %d\n", testmodule.PublicVariable)
// fmt.Printf("privateVariable: %d\n", testmodule.privateVariable) // ОШИБКА!
// Описательные имена
var currentUserAuthenticationToken string = "abc123xyz"
fmt.Println(currentUserAuthenticationToken)
// Осмысленные имена
var studentScore int = 95
var errorMessage string = "Failed"
fmt.Println(studentScore, errorMessage)
// Правильное написание аббревиатур
var userID int = 123 // не userId
var HTTPServer string = "nginx" // не HttpServer
var urlPath string = "/api" // не uRLPath
fmt.Println(userID, HTTPServer, urlPath)
}
Примеры структур
package models
// Публичная структура с разными полями
type User struct {
ID int // экспортируемое
Name string // экспортируемое
Email string // экспортируемое
password string // приватное
}
// Публичная функция
func (u *User) GetID() int {
return u.ID
}
// Приватная функция
func (u *User) validatePassword() bool {
return len(u.password) > 8
}
// Приватная структура
type session struct {
userID int
token string
}
Важные моменты
1. IDE подсвечивает ошибки экспорта Современные IDE (VS Code, GoLand) автоматически показывают, когда вы пытаетесь обратиться к неэкспортируемому идентификатору.
2. Экспорт — на уровне пакета Внутри одного пакета все идентификаторы видны, независимо от регистра. Экспорт работает только между пакетами.
3. Поля структур тоже экспортируются
type User struct {
Name string // видно вне пакета
age int // только внутри пакета
}
4. Методы подчиняются тем же правилам
func (u *User) Export() { } // публичный метод
func (u *User) internal() { } // приватный метод
5. Аббревиатуры — это convention, не правило
Компилятор не заставит писать HTTPServer вместо HttpServer, но Go community ожидает первого варианта.
6. Go vet и linters проверяют
Инструменты вроде golint, staticcheck предупредят о нарушениях naming conventions.
7. Приватные поля требуют геттеров/сеттеров
type User struct {
name string // приватное
}
// Публичный геттер
func (u *User) Name() string {
return u.name
}
// Публичный сеттер
func (u *User) SetName(name string) {
u.name = name
}
8. Константы подчиняются тем же правилам
const MaxConnections = 100 // экспортируемая
const defaultTimeout = 30 // приватная
Что запомнить
- Заглавная буква = public, строчная = private
- Нет ключевых слов
public/private— всё через регистр - Работает для всех сущностей: переменных, функций, структур, полей, методов
- Внутри пакета всё видно, экспорт работает между пакетами
- Аббревиатуры: все заглавные или все строчные
UserID,HTTPServer,URLPath(экспорт)userID,httpServer,urlPath(приват)- Не
userId,HttpServer,UrlPath
- camelCase для локальных переменных
- Префикс
is/hasдля булевых значений - Длинные имена для широкого scope, короткие для узкого
- Осмысленные имена всегда лучше коротких
- IDE подсвечивает ошибки доступа к приватным идентификаторам
- Linters (golint, staticcheck) проверяют naming conventions