if variable := value; condition
For example:
if err := json.Marshal(&val); err != nil {
// handle error
}
Name the returned values of a function so other developers can see what it returns without having to read the code.
If you are writing a helper function, do NOT return an error from the helper–return ok bool
. This allows you to check the ok
value in the caller and return the error there. For example:
func Parse(rawurl string) (*URL, error) {
scheme, rest, ok := parseScheme(rawurl)
if !ok {
return nil, errors.New("missing scheme")
}
...
}
func parseScheme(rawurl string) (scheme, rest string, ok bool) {
i := strings.Index(rawurl, "://")
if i < 1 {
return "", "", false
}
return rawurl[:i], rawurl[i+3:], true
}
You can return from a function with just the return
keyword. This is called a naked return. A naked return returns the current state of the result values.
Generally, do NOT use naked returns because they impact readability.
You can use blank identifiers in function definitions:
handler := func(_ http.ResponseWriter, _ *http.Request) {
// logic
}
When a type satisfies an interface, you say type X is a Y. For example, URL is a Stringer or Parser is a Reader.
Stringer
prints the string representation of the object. The fmt.Print[x]
packages detect when a type has a Stringer
method, so it calls that method for proper formatting.
The Stringer
interface:
type Stringer interface {
String() string
}
Implementation example:
func (u *URL) String() string {
return fmt.Sprintf("%s://%s/%s", u.Scheme, u.Host, u.Path)
}
Create a testString()
function to return a concise string representation value for tests. For example, the following is the test version of the String()
function in the previous section:
func (u *URL) testString() string {
return fmt.Sprintf("scheme=%q, host=%q, path=%q", u.Scheme, u.Host, u.Path)
}
The Go sort
package has a Slice
method to sort the values in a slice. However, you can implement the sort.Interface
interface to create a custom sort
method.
sort.Interface
has the following methods:
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with index i
// must sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
sort.Interface
operates on collection types, so you should create a custom collection type to implement the interface methods. Name the type in a way that describes the sorting strategy. For example, the following implementation sorts a slice of type Book
by the Author
field:
// Define a custom type whose name describe the sorting strategy.
type byAuthor []Book
// Len returns the length of the collection.
func (b byAuthor) Len() int { return len(b) }
// Swap swaps two books.
func (b byAuthor) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
// Less returns books sorted by Author and then Title.
func (b byAuthor) Less(i, j int) bool {
if b[i].Author != b[j].Author {
return b.LessByAuthor(i, j)
}
return b[i].Title < b[j].Title
}
Go versions prior to 1.18 used the empty interface: interface{}
. This is an interface that did not implement any methods, so any type satisfied it. In Go 1.18 and later, interface{}
was replaced with any
.
Prefer strconv.ParseInt()
over strconv.Atoi()
because the former can parse hex and numbers with underscores (1_000
).
verb | Definition | Usage |
---|---|---|
%q | Wraps the given string in double quotes. | |
%#v | Prints the Go syntax representation of the value. | t.Errorf("%#v.String()\ngot %q\nwant %q", u, got, want) |
%t | Boolean values. |
You can execute a method on a nil
type. A method is a function that takes the receiver as a hidden first parameter. So, when you have a nil
type, Go can find the method function to run, but it does not have anything to execute it on. For example, the Go compiler does the following when calling the String()
method on a nil
typ:
var u *URL
u.String() // (*url.URL).String(u)
Use if found...
to determine if an element exists in a list:
// returs a bool and int
func (hl *HostsList) search(host string) (bool, int) {
...
}
// found is a boolean. You can use a truncated syntax:
func (hl *HostsList) Add(host string) error {
if found, _ := hl.search(host); found {
return fmt.Errorf("%w: %s", ErrExists, host)
}
...
}
You should call Fatal()
and Panic()
from the main
method only. Return errors in other areas of the application.