Saturday, June 4, 2011

Formatting Go code with gofmt


Good code should also be maintainable. If code follows a standard format for writing it becomes easier for maintaining it and also enhancing it. Especially when there are different developers looking at the code in the present and the future, a standard is helpful. Though Go standards do not insist on a coding style, it does strongly suggest certain styles. The go fmt tool is an implementation of those styles, so that code could be reformatted to fit the standard.

It’s simple to use and we shall go over a few examples. Let’s work with this piece of code to start with.

Full file: hello.go
package             main

import     "fmt"

func main() {
        i := 5
            fmt.Println((i))
    fmt.Printf(           "hello, world\n"   )   
}


Not very beautiful, or readable. Let’s get go fmt to work on it. On the command line use go fmt as shown below.

go fmt hello.go

package main

import "fmt"

func main() {
 i := 5
 fmt.Println((i))
 fmt.Printf("hello, world\n")
}


It ain’t Rembrandt, but it looks much better, doesn’t it? Notice though that the output is only on the screen and if you want it redirected to a file, you will need to do it like so:

go fmt hello.go > hello_fmtd.go

That will give you a new file. If you want to just save the formatted code back into the same file, use the -w option.

go fmt -w hello.go


You can go a bit further with formatting code. If you notice in the code, the extra parentheses while printing the integer is redundant. You could provide certain rules to go fmt so that it replaces certain expressions with others. Here, we shall remove the unnecessary brackets by using the -r option and requiring that code of the form (a) be replaced by a.

go fmt -r "(a) -> a" hello.go

package main

import "fmt"

func main() {
 i := 5
 fmt.Println(i)
 fmt.Printf("hello, world\n")
}


You can see that fmt.Println((i)) was replaced by fmt.Println(i). But what about the existing set of brackets - will it go away too if we run it again? You can try it - it won’t.

go fmt -r "(a) -> a" hello_fmtd.go | go fmt -r "(a) -> a"

One more example where when using slices you might be tempted to give the length of the array when specifying that the slice should extend to the end, which however is unnecessary.

package main

import "fmt"

func main() {
 ar := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 a := ar[5:len(ar)]
 fmt.Println(a)
}

On this input, we apply a rule to change code in the form a[n:len(a)] to simply a[n:].

go fmt -r "a[n:len(a)] -> a[n:]" hello.go

package main

import "fmt"

func main() {
 ar := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
 a := ar[5:]
 fmt.Println(a)
}


2 comments:

  1. I can only get this to work by running gofmt -r. If I try to run go fmt -r it doesn't recognize the option.

    ReplyDelete
    Replies
    1. Use gofmt instead of go fmt. Made the exact same mistake as you.

      Delete

If you think others also will find these tutorials useful, kindly "+1" it above and mention the link in your own blogs, responses, and entries on the net so that others also may reach here. Thank you.