Функция new()
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 22 из 107.
Go предоставляет встроенную функцию под названием new(), которая выделяет память для типа и возвращает указатель на неё. Выделенная память инициализируется нулевым значением этого типа.
p := new(int) // выделяет память для int
fmt.Println(*p) // 0 (нулевое значение)
fmt.Println(p) // 0xc000018030 (адрес памяти)Функция new() принимает тип в качестве аргумента и возвращает указатель на вновь выделенное нулевое значение этого типа. Это особенно полезно, когда вам нужен указатель, но у вас нет существующей переменной для ссылки.
При работе со структурами new() создает указатель на структуру, в которой всем полям присвоены их нулевые значения.
type Person struct {
Name string
Age int
}
p := new(Person)
fmt.Println(p.Name) // "" (пустая строка)
fmt.Println(p.Age) // 0Вы можете задаться вопросом, когда использовать new() в сравнении с оператором взятия адреса &. Оба подхода ниже эквивалентны:
// Использование new()
p1 := new(Person)
// Использование оператора взятия адреса с литералом
p2 := &Person{}Синтаксис &Person{} более распространен на практике, поскольку он позволяет инициализировать поля одновременно. Используйте new(), когда вам специально нужен экземпляр с нулевыми значениями и вы предпочитаете семантику явного выделения памяти.
Задание
ЛегкоДавайте создадим менеджер конфигурации, который демонстрирует, как new() выделяет память и инициализирует структуры их нулевыми значениями. Вы увидите, чем этот подход отличается от использования оператора взятия адреса со структурным литералом.
Вы организуете свой код в двух файлах:
config.go: Определите структуруServerConfigс полямиHost(string),Port(int),MaxConnections(int) иDebugMode(bool). Создайте две функции:NewServerConfig, которая используетnew()для выделения памяти подServerConfigи возвращает указатель напрямую (со всеми нулевыми значениями)ConfigureServer, которая принимает указатель*ServerConfigвместе со строкой хоста и целым числом порта, а затем устанавливает эти поля в конфигурации через указатель
Displayдля*ServerConfig, который возвращает отформатированную строку, показывающую все значения конфигурации.main.go: Считайте хост и порт из входных данных. Сначала создайте конфигурацию с помощьюNewServerConfig()и отобразите ее, чтобы показать нулевые значения. Затем используйтеConfigureServerдля установки хоста и порта и снова отобразите конфигурацию, чтобы показать обновленные значения.
Будут предоставлены следующие входные данные:
- Строка 1: Имя хоста (string)
- Строка 2: Номер порта (integer)
Ваш метод Display должен возвращать строку именно в таком формате:
Host: [Host]
Port: [Port]
MaxConnections: [MaxConnections]
DebugMode: [DebugMode]Выведите результат отображения дважды — один раз перед настройкой (показывая нулевые значения) и один раз после настройки (показывая обновленные хост и порт).
Например, для localhost и 8080 ваш вывод должен быть следующим:
Host:
Port: 0
MaxConnections: 0
DebugMode: false
Host: localhost
Port: 8080
MaxConnections: 0
DebugMode: falseОбратите внимание, что при первом отображении выводятся все нулевые значения (пустая строка, 0, 0, false), потому что new() инициализирует все нулевыми значениями. После вызова ConfigureServer изменяются только хост и порт, в то время как остальные поля остаются со своими нулевыми значениями.
Шпаргалка
Функция new() выделяет память для типа и возвращает указатель на нее, инициализированный нулевым значением этого типа:
p := new(int) // выделяет память для int
fmt.Println(*p) // 0 (нулевое значение)
fmt.Println(p) // 0xc000018030 (адрес памяти)В случае со структурами new() создает указатель на структуру, все поля которой установлены в их нулевые значения:
type Person struct {
Name string
Age int
}
p := new(Person)
fmt.Println(p.Name) // "" (пустая строка)
fmt.Println(p.Age) // 0Использование new() в сравнении с оператором взятия адреса & — оба варианта эквивалентны:
// Использование new()
p1 := new(Person)
// Использование оператора адреса с литералом
p2 := &Person{}Синтаксис &Person{} встречается чаще, так как он позволяет инициализировать поля во время создания. Используйте new(), когда вам нужен экземпляр с нулевыми значениями и явной семантикой выделения памяти.
Попробуйте сами
package main
import (
"fmt"
)
func main() {
// Чтение входных данных
var host string
var port int
fmt.Scanln(&host)
fmt.Scanln(&port)
// TODO: Создайте конфигурацию с помощью NewServerConfig() и выведите её
// Это покажет нулевые значения
// TODO: Используйте ConfigureServer для установки host и port
// TODO: Снова выведите конфигурацию, чтобы показать обновленные значения
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool