Q: pointers vs values (in general) ?
A:
Don't pass pointers as function arguments just to save a few bytes.
Don't pass a pointer to a string (*string) or a pointer to an interface value (*io.Reader). In both cases the value itself is a fixed size and can be passed directly.
Use pointes on large structs, or even small structs that might grow.
Q: Return the zero value vs validate and return a confirmation var ?
A:
Avoid returning values like -1 or null to signal errors or missing results
Instead require client to check an in-band error value.
A function should return an additional value to indicate whether its other return values are valid. This return value may be an error, or a boolean when no explanation is needed. It should be the final return value.
// Lookup returns the value for key or ok=false if there is no mapping for key.
func Lookup(key string) (value string, ok bool)
/* ---- */
value, ok := Lookup(key)
if !ok {
return fmt.Errorf("no value for %q", key)
}
return Parse(value)
Q: Where to put interfaces ? A:
Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values.
The implementing package should return a concrete (usually pointer or struct) type:
That way, new methods can be added to implementations without requiring extensive refactoring.
Q: Small vs descritive variabels?
A:
Variable names in Go should be short rather than long. This is especially true for local variables with limited scope.
Prefer c to lineCount. Prefer i to sliceIndex.
More unusual things and global variables need more descriptive names.
Q: Do switch cases have fall through?
A: No but cases can be presented in comma-separated lists.
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
Q: new vs make
A:
new:
It's a built-in function that allocates memory
new(T) allocates zeroed storage for a new item of type T and returns its address, a value of type *T
In Go terminology, it returns a pointer to a newly allocated zero value of type T.
p := new(SyncedBuffer) // type *SyncedBuffer
var v SyncedBuffer // type SyncedBuffer
make:
Creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T)
Under the covers, references to data structures that must be initialized before use
make([]int, 10, 100)
Allocates an array of 100 ints and then creates a slice structure with length 10 and a capacity of 100 pointing at the first 10 elements of the array