DEV Community

loading...

Things Golang do differently

dev117uday profile image Uday Yadav ・4 min read
weird at first but makes sense

Formatting

  • use gofmt to format packages

Commentary

  • Go uses c like comments // or /* */
  • Every Function/Struct/Variable that you have to export, name it so that first letter is capital
  • Package name
    • short, concise, evocative
    • the package in src/encoding/base64 is imported as "encoding/base64" but has name base64, not encoding_base64 and not encodingBase64.

Getters & Setters

  • Go doesn't provide automatic support for getters and setters. There's nothing wrong with providing getters and setters yourself, and it's often appropriate to do so.
owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}
Enter fullscreen mode Exit fullscreen mode

Naming

Interface Naming
By convention, one-method interfaces are named by the method name plus an -er suffix or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.

Variable Naming

  • Finally, the convention in Go is to use MixedCaps or mixedCaps rather than underscores to write multi word names
  • In a := declaration a variable v may appear even if it has already been declared, provided: this declaration is in the same scope as the existing declaration of v (if v is already declared in an outer scope, the declaration will create a new variable §),
  • The corresponding value in the initialisation is assignable to v, and there is at least one other variable that is created by the declaration

Indentation

if i < f() {
    g()
}

if i < f()  // wrong!
{           // wrong!
    g()
}
Enter fullscreen mode Exit fullscreen mode

Control Structure

  • There is no do or while loop, only a slightly generalised for; switch is much better If. In Go a simple if looks like this:
if x > 0 {
    return y
}
Enter fullscreen mode Exit fullscreen mode
  • Mandatory braces encourage writing simple if statements on multiple lines. It's good style to do so anyway, especially when the body contains a control statement such as a return or break. Since if and switch accept an initialisation statement, it's common to see one used to set up a local variable.
if err := file.Chmod(0664); err != nil {
    log.Print(err)
    return err
}
Enter fullscreen mode Exit fullscreen mode

Re-declaration and Re-assignment

The last example in the previous section demonstrates a detail of how the := short declaration form works. The declaration that calls os.Open reads,

f, err := os.Open(name)
Enter fullscreen mode Exit fullscreen mode
  • This statement declares two variables, f and err. A few lines later, the call to f.Stat reads,
d, err := f.Stat()
Enter fullscreen mode Exit fullscreen mode

-​ which looks as if it declares d and err. Notice, though, that err appears in both statements. This duplication is legal: err is declared by the first statement, but only re-assigned in the second. This means that the call to f.Stat uses the existing err variable declared above, and just gives it a new value.

Range

  • If you're looping over an array, slice, string, or map, or reading from a channel, a range clause can manage the loop.
for key, value := range oldMap {
    newMap[key] = value
}
Enter fullscreen mode Exit fullscreen mode
  • If you only need the first item in the range (the key or index), drop the second:
for key := range m {
    if key.expired() {
        delete(m, key)
    }
}
Enter fullscreen mode Exit fullscreen mode
  • If you only need the second item in the range (the value), use the blank identifier, an underscore, to discard the first:
sum := 0
for _, value := range array {
    sum += value
}
Enter fullscreen mode Exit fullscreen mode

Switch in Golang

  • Go's switch is more general than C's.
  • It's therefore possible—and idiomatic—to write an if-else-if-else chain as a switch.
func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}
Enter fullscreen mode Exit fullscreen mode
  • There is no automatic fall through, but cases can be presented in comma-separated lists.
func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+', '%':
        return true
    }
    return false
}
Enter fullscreen mode Exit fullscreen mode

Type Switch

  • A switch can also be used to discover the dynamic type of an interface variable
var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}
Enter fullscreen mode Exit fullscreen mode

Functions

  • Multiple return values
func squareRoot (num int) (n float, err error)
// or
func squareRoot (num int) (float, error)
// to return error if num < 0
// named return
Enter fullscreen mode Exit fullscreen mode

Defer

  • Go's defer statement schedules a function call (the deferred function) to be run immediately before the function exits.
func fileContent (filename string) (string, error) {
    f, err := os.Open(filename)
    if err != nil {
        return "", err
    }
    // defer will run the function just before exiting the function fileContents
    defer f.Close()
    // something with return   
}
Enter fullscreen mode Exit fullscreen mode
  • Deferring a call to a function such as Close has two advantages.
    • First, it guarantees that you will never forget to close the file, a mistake that's easy to make if you later edit the function to add a new return path.
    • Second, it means that the close sits near the open, which is much clearer than placing it at the end of the function.

For Example :

for i := 0; i < 5; i++ {
    defer fmt.Printf("%d ", i)
}
Enter fullscreen mode Exit fullscreen mode

Deferred functions are executed in LIFO order, so this code will cause 4 3 2 1 0 to be printed when the function returns
A more plausible example is a simple way to trace function execution through the program. We could write a couple of simple tracing routines like this:

func trace(s string)   { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }

// Use them like this:
func a() {
    trace("a")
    defer untrace("a")
    // do something....
}
Enter fullscreen mode Exit fullscreen mode

Discussion (3)

pic
Editor guide
Collapse
cmelgarejo profile image
Collapse
ndiecodes profile image
Ndifreke Friday

I love this!

Collapse
aalphaindia profile image
Pawan Pawar

Keep sharing!