Go-фича: new(expr)

Часть серии Принято! В ней простыми словами объясняются новые фичи Go.

Использовать встроенную функцию new для выражений.

Версия 1.26 • Язык • Важно

Что

Раньше new можно было использовать только с типами:

p1 := new(int)
fmt.Println(*p1)
// 0

А теперь можно и с выражениями:

// Указатель на переменную типа int со значением 42.
p := new(42)
fmt.Println(*p)
// 42

Если аргумент expr — это выражение типа T, то new(expr) аллоцирует переменную типа T (то есть выделяет под нее память), инициализирует ее значением expr и возвращает ее адрес, то есть значение типа *T.

Зачем

Есть простой способ создать указатель на составной литерал:

type Person struct { name string }
p := &Person{name: "alice"}

Но нет простого способа создать указатель на значение простого типа:

n := 42
p := &n

Теперь это исправят.

Подробности

Обновить раздел Allocation в спецификации языка следующим образом (далее перевод с английского):

Выделение памяти

Встроенная функция new создает новую переменную, инициализирует ее и возвращает указатель на нее. Она принимает один аргумент — это может быть выражение или тип.

➀ Если аргумент expr — это выражение типа T или нетипизированная константа, у которой тип по умолчанию — T, то new(expr) выделяет переменную типа T, инициализирует ее значением expr и возвращает ее адрес, то есть значение типа *T.

➁ Если аргумент — это тип T, то new(T) выделяет переменную, инициализированную нулевым значением типа T.

Например, new(123) и new(int) оба возвращают указатель на новую переменную типа int. Значение первой переменной — 123, второй — 0.

➀ — это новая фича, ➁ уже работает как описано.

Примеры

Указатель на простой тип:

// go 1.25
n := 42
p1 := &n
fmt.Println(*p1)

s := "go"
p2 := &s
fmt.Println(*p2)
42
go
// go 1.26
p1 := new(42)
fmt.Println(*p1)

s := "go"
p2 := new(s)
fmt.Println(*p2)
42
go

Указатель на составное значение:

// go 1.25
s := []int{11, 12, 13}
p1 := &s
fmt.Println(*p1)

type Person struct{ name string }
p2 := &Person{name: "alice"}
fmt.Println(*p2)
[11 12 13]
{alice}
// go 1.26
p1 := new([]int{11, 12, 13})
fmt.Println(*p1)

type Person struct{ name string }
p2 := new(Person{name: "alice"})
fmt.Println(*p2)
[11 12 13]
{alice}

Указатель на результат вызова функции:

// go 1.25
f := func() string { return "go" }
v := f()
p := &v
fmt.Println(*p)
go
// go 1.26
f := func() string { return "go" }
p := new(f())
fmt.Println(*p)
go

Передавать nil по-прежнему нельзя:

// go 1.25 and go 1.26
p := new(nil)
// compilation error

Ссылки

𝗣 45624 • 𝗖𝗟 704935, 704737, 704955, 705157

★ Подписывайтесь на канал и проходите курсы.