Spe c: Составные литералы только заявляют, что когда вы берете адрес составного литерала, он будет указывать на безымянную переменную, поэтому требуется выделение:
Принятие адреса составного литерала генерирует указатель на уникальную переменную , инициализированную значением литерала.
Когда вы не принимаете адрес литерала просто назначьте его, выделение не требуется, значение структуры можно присвоить переменной, для которой уже выделена память.
Для проверки мы можем использовать среду тестирования Go. Создайте тестовый файл:
package main
import (
"testing"
)
type Request struct {
Field string
}
var r = Request{Field: "a"}
func BenchmarkStruct(b *testing.B) {
for i := 0; i < b.N; i++ {
r = Request{Field: "b"}
}
}
var p = &Request{Field: "a"}
func BenchmarkStructPtr(b *testing.B) {
for i := 0; i < b.N; i++ {
p = &Request{Field: "b"}
}
}
Запустите его с:
go test -bench . -benchmem
Вывод:
BenchmarkStruct-4 1000000000 0.948 ns/op 0 B/op 0 allocs/op
BenchmarkStructPtr-4 32160099 37.3 ns/op 16 B/op 1 allocs/op
Как видите, присвоив значение Request
структура, использующая составной литерал, не требует выделения. Взяв его адрес и назначив, для которого требуется выделение 16 байтов (в моей 64-битной архитектуре), это размер вашей структуры Request
, которая содержит одно поле типа string
, и заголовок строки - указатель (8 байтов) и длина (8 байтов).
Присвоение значений в Go всегда делает копию. Поэтому, когда вы присваиваете какое-либо значение (включая значение структуры), значение будет скопировано, и на исходное значение не будет ссылаться переменная, которой вы его присвоили.