Дополнительное выделение при возврате интерфейса {} вместо int64
У меня есть функция, которая генерирует случайный int64
и возвращает его как interface{}
как это:
func Val1(rnd rand.Source) interface{} {
return rnd.Int63()
}
Теперь рассмотрим эту функцию, которая делает то же самое, но возвращает int64
func Val2(rnd rand.Source) int64 {
return rnd.Int63()
}
Я сравнил две функции с этим (go test -bench=. -benchmem
):
func BenchmarkVal1(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val1(rnd)
}
}
func BenchmarkVal2(b *testing.B) {
var rnd = rand.NewSource(time.Now().UnixNano())
for n := 0; n < b.N; n++ {
Val2(rnd)
}
}
и получил следующие результаты:
BenchmarkVal1-4 50000000 32.4 ns/op 8 B/op 1 allocs/op
BenchmarkVal2-4 200000000 7.47 ns/op 0 B/op 0 allocs/op
Откуда берется дополнительное распределение в Val1()
родом из? Можно ли этого избежать при возврате interface{}
?
1 ответ
Значением интерфейса является обертка под капотом, пара конкретных значений, хранящихся в значении интерфейса, и его дескриптор типа.
Прочитайте это для получения дополнительной информации: Законы Отражения # Представление интерфейса
Так что если вы хотите вернуть значение interface{}
тип, interface{}
значение будет создано неявно (если возвращаемое значение уже не того типа), которое будет содержать целое число и его дескриптор типа, обозначающий int64
тип. Вы не можете избежать этого.
interface{}
это специальный тип интерфейса (имеющий 0 методов). Его значение составляет всего 8 байтов, как вы видите на выходе теста. Другие типы интерфейса имеют больший размер (double), поскольку они также должны идентифицировать статический набор методов типа интерфейса (помимо динамического типа и значения).
Также обязательно ознакомьтесь с этим информативным ответом: Go: Что означает интерфейс {}?
Если вы хотите получить больше информации о реализации / внутренностях, я рекомендую этот пост: как работают интерфейсы в Golang