Значение функции Golang по умолчанию

# #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