Существует несколько ответов/методов для следующего вопроса:
- Как установить значения по умолчанию для golang structs?
- Как инициализировать структуры в golang
У меня есть несколько ответов, но требуется дальнейшее обсуждение.
Существует несколько ответов/методов для следующего вопроса:
У меня есть несколько ответов, но требуется дальнейшее обсуждение.
Вынудите метод получить структуру (путь конструктора).
Хороший дизайн - сделать ваш тип неэкспортированным, но предоставьте экспортированную функцию конструктора, такую как NewMyType(), в которой вы можете правильно инициализировать вашу структуру/тип. Также возвращайте тип интерфейса, а не конкретный тип, и интерфейс должен содержать все, что другие хотят сделать с вашим значением. И ваш конкретный тип должен реализовывать этот интерфейс, конечно.
Это можно сделать, просто сделав сам тип неэкспортированным. Вы можете экспортировать функцию NewSomething и даже поля Text и DefaultText, но просто не экспортируйте что-то типа структуры
Другой способ настроить его для собственного модуля - использовать структуру Config для установки значений по умолчанию (опция 5 в ссылке). Однако это не очень хороший способ.
Одна из возможных идей - написать отдельную функцию конструктора.
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
Одна проблема с вариантом 1 в ответ от Виктор Заманян: если тип не экспортируется, то пользователи вашего пакета не могут объявить его как тип параметров функции и т.д. Один из способов - экспортировать интерфейс вместо структуры, например.
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes unit32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
Что позволяет нам объявлять типы параметров функции с помощью экспортированного интерфейса кандидата. Единственный недостаток, который я вижу из этого решения, заключается в том, что все наши методы должны быть объявлены в определении интерфейса, но вы можете утверждать, что это хорошая практика в любом случае.
С https://golang.org/doc/effective_go.html#composite_literals:
Иногда нулевое значение недостаточно, и необходим инициализирующий конструктор, как в этом примере, полученном из пакета os.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
Есть способ сделать это с тегами, который допускает несколько значений по умолчанию.
Предположим, у вас есть следующая структура с 2 тегами по умолчанию default0 и default1.
type A struct {
I int 'default0:"3" default1:"42"'
S string 'default0:"Some String..." default1:"Some Other String..."'
}
Теперь можно установить значения по умолчанию.
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
Здесь полная программа на детской площадке.
Если вы заинтересованы в более сложном примере, скажем, с кусочками и картами, посмотрите на creasty/defaultse
type Config struct {
AWSRegion string 'default:"us-west-2"'
}