Есть несколько ответов / методов на следующий вопрос:
- Как установить значения по умолчанию для структур Голанга?
- Как инициализировать структуры в Голанге
У меня есть пара ответов, но требуется дальнейшее обсуждение.
Есть несколько ответов / методов на следующий вопрос:
У меня есть пара ответов, но требуется дальнейшее обсуждение.
Ответы:
Одна из возможных идей - написать отдельную функцию конструктора.
//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
}
NewSomething
и даже поля Text
и DefaultText
, но только не экспортируйте тип структуры something
.
reflect.New()
), нельзя ожидать, что она будет знать о вашей специально названной фабричной функции. В этом случае, если не считать самого языка, думаю, подойдет только интерфейс (который может проверять библиотека).
Вынудите метод получить структуру (путь конструктора).
Из этого поста :
Хороший дизайн - сделать ваш тип неэкспортированным, но предоставить экспортированную функцию конструктора,
NewMyType()
в которой вы можете правильно инициализировать свою структуру / тип. Также возвращайте тип интерфейса, а не конкретный тип, и интерфейс должен содержать все, что другие хотят сделать с вашим значением. И ваш конкретный тип должен реализовывать этот интерфейс, конечно.
Это можно сделать, просто сделав сам тип неэкспортированным. Вы можете экспортировать функцию NewSomething и даже поля Text и DefaultText, но просто не экспортируйте что-нибудь типа структуры.
Другой способ настроить его для собственного модуля - использовать структуру Config для установки значений по умолчанию (опция 5 в ссылке). Не очень хороший способ.
Одна из проблем с вариантом 1 в ответе Виктора Заманяна состоит в том, что если тип не экспортируется, то пользователи вашего пакета не могут объявить его как тип для параметров функции и т. Д. Одним из способов решения этой проблемы является экспорт интерфейса вместо структура например
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // 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
}
Что позволяет нам объявлять типы параметров функции, используя экспортированный интерфейс кандидата. Единственный недостаток, который я вижу в этом решении, заключается в том, что все наши методы должны быть объявлены в определении интерфейса, но вы можете утверждать, что в любом случае это хорошая практика.
Есть способ сделать это с тегами, который допускает несколько значений по умолчанию.
Предположим, у вас есть следующая структура с 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
С 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
}
type Config struct {
AWSRegion string `default:"us-west-2"`
}