# #go
Вопрос:
Я пытаюсь присвоить значение по умолчанию с помощью структуры, но как мне отличить, является ли оно нулевым значением или фактическим входным значением без использования указателя?
type Options struct {
a bool `default:"true"`
// other options
}
func processOptions(options *Options) {
if !options.a { // zero value - false
options.a = true // what if the user actually input false?
}
}
func test(options Options) {
processOptions(amp;options)
// ...
}
подход с указателем будет
type Options struct ...
func processOptions(options *Options) {
if options.a == nil {
aDefault := true
options.a = amp;aDefault
}
}
func test(options Options) ...
a := false
options := Options{amp;a}
test(options)
функциональные опции, упомянутые @maja, используют преимущества вариативных функций и типа структуры, чтобы «конструктор» безопасно инициализировал параметры в отношении типов каждой опции.
type Options struct {
a bool
// other options
}
type Option func(*Options)
func WithA(a bool) Option {
return func(options *Options) {
options.a = a
}
}
func NewOptions(opts ...Option) *Options {
options := amp;Options{
a: true // default value
}
for _, opt := range opts {
opt(options)
}
return options
}
func test(options Options) {
// ...
}
options := NewOptions(
WithA(false),
)
test(*options)
Комментарии:
1. Вы не можете сделать это с помощью простого
bool
и без указателя. Единственный способ сделать то, что вы хотите, без использования указателя,-это использовать пользовательский тип, который может представлять эти 3 различных состояния (установить «ненулевое», установить «ноль» и снять). Что-то похожее на то, какdatabase/sql
пакет в стандартной библиотеке работает со значениями NULL, например, pkg.go.dev/база данных/sql#NullBool . Указатель или пользовательский тип-это ваши единственные 2 варианта.2. Я думаю, что я пойду с указателем, но это кажется немного неуклюжим, потому что я должен инициализировать свой вариант с помощью»amp;», и это также причина, по которой я его избегаю.
3. Зачем вам вообще нужно различать? Ваш аргумент уже является указателем:
*Option
. Пользователь уже может передать ноль. Общий подход состоит в том, чтобы хранить каждую «опцию» в своем собственном типе структуры и использовать аргумент variadic в processOption (), чтобы вызывающий абонент мог передавать нужные ему параметры. Или нет, если значения по умолчанию достаточно хороши.4. @maja вы имеете в виду, что каждый отдельный «вариант» имеет свой собственный тип структуры и использует вариативный аргумент как в processOption (), так и в test()? Поскольку test() может принимать несколько вариантов, это похоже на конфигурацию.
5. @ААРон, Да. Смотрите здесь пример: sohamkamani.com/golang/options-pattern
Ответ №1:
Во многих случаях нет необходимости проводить различие между значением по умолчанию или значением, явно равным нулю.
В противном случае вы можете использовать указатель или другое поле в качестве флага присутствия
type Option struct {
a bool
aProvided bool
}
func processOption(option *Option) {
if !option.aProvided
option.a = true
}
}
Для этого потребуется, чтобы вызывающие абоненты инициализировали это дополнительное поле, а также a. Чтобы повторить мой вышеприведенный совет, часто бывает проще, если вам не нужно различать.
Комментарии:
1. я пытаюсь избежать использования указателя в основных типах данных, но подход с флагом присутствия требует большой работы, если у меня есть несколько аргументов
2. Пожалуйста, подробно опишите, в чем заключается ваш вопрос и каков ваш ожидаемый результат
Ответ №2:
Похоже, вы уже решили эту проблему самостоятельно, используя *string. Но вы хотите избежать этого …
Почему бы вам не сделать так, чтобы все ваши опции были по умолчанию, как есть. например, у вас есть варианты auto
= true
и repeat
= false
. Вы можете переименовать свои параметры для значения auto
по умолчанию, например disableAuto
type Option struct {
Repeat bool // because repeat by default false
DisableAuto bool // because auto by default true, this options purpose is to disabled auto
}
Обновленный:
или, может быть, вам нужны шаблоны функциональных опций, вот мой пример https://play.golang.org/p/4DsSaQQkWg0
для получения дополнительной информации вы можете ознакомиться здесь https://golang.cafe/blog/golang-functional-options-pattern.html
Комментарии:
1. Не все нулевые значения подходят для значений по умолчанию, например, строка по умолчанию «somevalue» в этом случае не будет работать
2. Ах… может быть, вам нужны функциональные варианты, такие как golang.cafe/blog/golang-functional-options-pattern.html