GOOGLE ADS

четверг, 14 апреля 2022 г.

Как сделать литерал *int64 в Go?

У меня есть тип структуры с *int64полем.

type SomeType struct {
SomeField *int64
}

В какой-то момент в моем коде я хочу объявить литерал этого (скажем, когда я знаю, что указанное значение должно быть 0 или указывать на 0, вы понимаете, что я имею в виду)

instance:= SomeType{
SomeField: &0,
}

... кроме того, что это не работает

./main.go:xx: cannot use &0 (type *int) as type *int64 in field value

Так что я пробую это

instance:= SomeType{
SomeField: &int64(0),
}

... но это тоже не работает

./main.go:xx: cannot take the address of int64(0)

Как мне это сделать? Единственное решение, которое я могу придумать, это использовать переменную-заполнитель

var placeholder int64
placeholder = 0
instance:= SomeType{
SomeField: &placeholder,
}

Примечание: &0синтаксис работает нормально, если это *int вместо *int64. Редактировать: нет, это не так. Извини за это.

Редактировать:

Очевидно, в моем вопросе было слишком много двусмысленности. Я ищу способ буквально заявить. *int64Это может быть использовано внутри конструктора или для указания литеральных значений структуры или даже в качестве аргументов для других функций. Но вспомогательные функции или использование другого типа не являются решениями, которые я ищу.


Решение проблемы


Спецификация языка Go ( адресные операторы ) не позволяет брать адрес числовой константы (ни нетипизированной, ни типизированной константы).

Операнд должен быть адресуемым, то есть либо переменной, либо косвенным указателем, либо операцией индексации среза; или селектор поля операнда адресуемой структуры; или операция индексации массива адресуемого массива. В качестве исключения из требования адресации x[в выражении &x] также может быть составным литералом (возможно, заключенным в скобки).

Чтобы понять, почему это не разрешено, см. связанный вопрос: Найти адрес константы в go. Аналогичный вопрос (аналогично не разрешено брать его адрес): Как мне хранить ссылку на результат операции в Go?

Ваши варианты (попробуйте все на Go Playground ):

1) Сnew()

Вы можете просто использовать встроенную new()функцию для выделения нового нулевого значения int64и получения его адреса:

instance:= SomeType{
SomeField: new(int64),
}

Но обратите внимание, что это можно использовать только для выделения и получения указателя на нулевое значение любого типа.

2) С помощью вспомогательной переменной

Простейшим и рекомендуемым для ненулевых элементов является использование вспомогательной переменной, адрес которой можно взять:

helper:= int64(2)
instance2:= SomeType{
SomeField: &helper,
}

3) С вспомогательной функцией

Примечание. Вспомогательные функции для получения указателя на ненулевое значение доступны в моей github.com/icza/goxбиблиотеке в goxпакете, поэтому вам не нужно добавлять их во все свои проекты, где они вам нужны.

Или, если вам это нужно много раз, вы можете создать вспомогательную функцию, которая выделяет и возвращает *int64:

func create(x int64) *int64 {
return &x
}

И используя его:

instance3:= SomeType{
SomeField: create(3),
}

Обратите внимание, что мы на самом деле ничего не выделяли, это сделал компилятор Go, когда мы вернули адрес аргумента функции. Компилятор Go выполняет escape-анализ и размещает локальные переменные в куче (вместо стека), если они могут выйти из функции. Подробнее см. в разделе Безопасно ли возвращать фрагмент локального массива в функцию Go?

Обновление дженериков Go 1.18: дженерики добавлены в Go 1.18. Это означает, что мы можем создать единую общую create()функцию, которую можно использовать для всех типов. Надеюсь, он будет добавлен в стандартную библиотеку.

Вот как это может выглядеть:

func Ptr[T any](t T) *T {
return &t
}

Тестирование:

i:= Ptr(2)
log.Printf("%T %v", i, *i)
s:= Ptr("abc")
log.Printf("%T %v", s, *s)
x:= Ptr[any](nil)
log.Printf("%T %v", x, *x)

Что выведет (попробуйте на Go Playground ):

2009/11/10 23:00:00 *int 2
2009/11/10 23:00:00 *string abc
2009/11/10 23:00:00 *interface {} <nil>

4) С однострочной анонимной функцией

instance4:= SomeType{
SomeField: func() *int64 { i:= int64(4); return &i }(),
}

Или как (более короткая) альтернатива:

instance4:= SomeType{
SomeField: func(i int64) *int64 { return &i }(4),
}

5) С литералом среза, индексированием и получением адреса

Если вы хотите *SomeFieldбыть другим, чем 0, вам нужно что-то адресуемое.

Вы все еще можете сделать это, но это некрасиво:

instance5:= SomeType{
SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5

Здесь происходит создание []int64среза с литералом, имеющим один элемент ( 5). И он индексируется (0-й элемент) и берется адрес 0-го элемента. В фоновом режиме массив [1]int64также будет выделен и использован в качестве резервного массива для среза. Так что здесь много шаблонов.

6) С литералом вспомогательной структуры

Давайте рассмотрим исключение из требований адресации:

В качестве исключения из требования адресации x[в выражении &x] также может быть составным литералом (возможно, заключенным в скобки).

Это означает, что прием адреса составного литерала, например, литерала структуры, допустим. Если мы это сделаем, у нас будет выделено значение структуры и получен указатель на него. Но если это так, нам станет доступно еще одно требование: «селектор поля адресуемого структурного операнда». Таким образом, если структурный литерал содержит поле типа int64, мы также можем взять адрес этого поля!

Давайте посмотрим этот вариант в действии. Мы будем использовать этот тип структуры оболочки:

type intwrapper struct {
x int64
}

И теперь мы можем сделать:

instance6:= SomeType{
SomeField: &(&intwrapper{6}).x,
}

Обратите внимание, что это

&(&intwrapper{6}).x

означает следующее:

& ( (&intwrapper{6}).x )

Но мы можем опустить «внешнюю» скобку, поскольку оператор адреса &применяется к результату выражения селектора.

Также обратите внимание, что в фоновом режиме будет происходить следующее (это также допустимый синтаксис):

&(*(&intwrapper{6})).x

7) С литералом вспомогательной анонимной структуры

Принцип тот же, что и в случае № 6, но мы также можем использовать литерал анонимной структуры, поэтому определение типа вспомогательной/оболочки не требуется:

instance7:= SomeType{
SomeField: &(&struct{ x int64 }{7}).x,
}

Комментариев нет:

Отправить комментарий

Laravel Datatable addColumn returns ID of one record only

Я пытаюсь использовать Yajra Datatable для интеграции DataTable на свой веб-сайт. Я смог отобразить таблицу, но столкнулся с проблемой. В по...