3 ms·
Go has two mechanisms for initializing structs, name based and position based. type Sample struct { A int B int } can be initialized a
by jerf 7y ago
Go has two mechanisms for initializing structs, name based and position based.
type Sample struct {
A int
B int
}
can be initialized as Sample{A: 1, B: 2}, or Sample{1, 2}.
The name-based method allows arbitrary elision of fields, which will be initialized to their zero value. This includes Sample{}, which will be interpreted as a name-based initialization that specified no fields.
The position-based method requires all fields to be specified, in order, with the correct type, or it's a compile-time fail.
So if the author of the article could have gotten the latter behavior with a slight syntax tweak.
This would not necessarily entirely satisfy, though, since you can't do any mix-and-match, and in particular, it can be nice to have names on the larger structs even if you want them to be fully initialized, but there is no in-between. But, nevertheless, if you are willing to pay for the behavior that the compiler will complain on any type-changes to the struct, including growing or shrinking, Go has that.
It seems to be the Go community's "best practice", above my objections, to claim that all struct initializations MUST use the name-based initialization and that positional-based inits is a mistake, on the theory that if structs change and add fields it's important for all uses of structs to continue compiling without changes. If the author's introduction to Go came from a tutorial from someone who believed that, they could easily have picked that up mistakenly as a characteristic of the language itself.
My objection is that there's a time and a place for each behavior, and there have been plenty of times I've been grateful for the compiler pointing out every place I need to change my struct to include a new member because I could tell it was a "tuple-like" struct that should always be initialized with all the fields. You can argue with the putative "best practice" or agree with it, but fortunately it doesn't really matter because you can do the one you want regardless of what the community thinks. There is no chance either method is ever going to be removed.
- rifung 7y agoThe problem with using the positional method is that 1) It's much more difficult to read since you have to know the position of elements of the struct 2) You swap one compile time error for another: in the case you add and remove a field of the same type, it's entirely possible the program will compile fine if you use the positional initialization instead of the named one. #2 makes me think that the author would still be unsatisfied
- throwaway34241 7y ago> It's much more difficult to read since you have to know the position of elements of the struct At least the Go editor I use (GoLand by JetBrains, one of the more popular ones) will display the names of all the fields in positional initializers inline with the code (just as they would be in a named initializer), so it's pretty much the same readability-wise. There's a special color for these automatic labels that indicates they aren't actually part of the document. > in the case you add and remove a field of the same type, it's entirely possible the program will compile fine True although I think it's easier to work around this (by fixing the compile errors from removing the old field before adding the new one).
- throwaway34241 7y agoI agree, I use positional initializers pretty often to get behavior you describe. Not sure about VSCode but if you use GoLand it will even prefix the field names right in the editor, so there isn't really any readability difference. One other reasonable alternative for OP in Go might be to simply use initialization functions (NewSample() or sample.InitWithX()) for certain structs. It's a bit more flexible with the ability to have multiple initializers and non-zero default field values (and of course also solves the issue of generating compile errors in the rest of the code when new fields/parameters are added).
- selljamhere 7y agoInitializing through explicit constructors e.g. `func NewSample(a, b int) Sample {...}` can also add a compile-time check. Of course the onus is once again on the developer to remember to use the `New` funcs instead of instantiating directly. Edit: spelling