Friday, January 03, 2014

Few handy things to know in Go Library (Command line arguments, Reflection, Setting Bits, Hash functions)

Command line arguments in Go

In order to access the command line arguments passed to a Go executable, we work with the "flag" package from the standard Go library. Shown below is an example of passing command line arguments.
go run cla.go Krishna
Or if you have an executable obtained from go build, you can run it as
./cla Krishna 
Shown below is an example go snippet that accesses the first argument passed & prints it.
package main

import (
    "fmt"
    "flag"
)

func main() {
 //Without the call to Parse(), arguments may not be accessed
 flag.Parse()
 fmt.Printf("%s\n",flag.Arg(0))
}
Notice that you will have to invoke the call to flag.Parse() without which you will not be able to access the arguments.

Reflection support in Go

We take the previous example, add some code for reflection which will help us understand how reflection library may be used. Just some simple example without having to go deep. For that, read this post from the official Go blog.

So what is the type returned by flag.Arg(0) ? We will start from there and go use some functions.
package main

import (
 "fmt" //regular format package
 "flag" //package from command line arguments
 "reflect" //package for reflection
)

func main() {
 //Without the call to Parse(), arguments may not be accessed
 flag.Parse()
 fmt.Printf("%s\n",flag.Arg(0))

 passed := flag.Arg(0)
 //TypeOf actually returns a Type type
 fmt.Println("typeof : ",reflect.TypeOf(passed))

 //ValueOf actually returns a Value
 fmt.Println("valueof : ",reflect.ValueOf(passed))

 //Example functions from the Value type
 fmt.Println("type: ",reflect.ValueOf(passed).Type())
 fmt.Println("kind: ", reflect.ValueOf(passed).Kind())
 fmt.Println("interface:", reflect.ValueOf(passed).Interface())
}

Big Integer & Set Bits

In the future post, I would like to implement a Bloom filter in Go but for that I will need to know how to do the following:
- Create a big number and set some bit "x" to 1 or 0.
- Accept a string, convert it to byte array, then hash the byte array.

To support the above, I wanted to see how simple big numbers would work. I am only looking enough to support my purpose. 

Big Numbers (multi-precision numbers) are supported using "math/big" package in Go library. Shown below is an example code that does that.
package main

import ( 
   "fmt"
   "math/big"
   "unsafe"
)

func main() {
 
 //create a new big integer
 filter := big.NewInt(0)

 fmt.Println("filter value: ",filter)
 
 //accessing the sizeof from unsafe package
 fmt.Println("size of : ",unsafe.Sizeof(filter))
 
 //example of how to cast uintptr to int
 filter.SetBit(filter,int(unsafe.Sizeof(filter)*8)-1,1)
 
 fmt.Println("filter after setbit last to 1 : ",filter)
}

The above example shows a few things:
- Creating an instance of big.Int using the NewInt() call.
- Accessing the size of the big.Int using unsafe package exported SizeOf() function
- SizeOf() returns uintptr and we convert that to integer - that is a good example of casting
- How to set bit on the big.Int using SetBit

Working with Hash functions

Example below demonstrates the following
  • how to convert a string to a byte array
  • how to use FNV Hash from the standard Go library
package main

import (
 "fmt"
 "hash/fnv"
)

func main() {
        //Create a hash fnv function
 hash := fnv.New32()
 
 name := "Krishna"

 //converting string to byte array
 namebytes := []byte(name)

 fmt.Println("hash reset : ",hash.Sum32())
 
 hash.Write(namebytes)

 fmt.Println("hash of Krishna : ",hash.Sum32())

 hash.Reset() //resets the hash

 fmt.Println("hash reset : ",hash.Sum32())

 //write again
 hash.Write(namebytes)
 
 fmt.Println("hash of Krishna : ", hash.Sum32())
}
Hash libraries in the Go "hash" package implements the Hash interface. The implementations in the standard Go library as of this time are adler32, crc32, crc64, fnv-1/fnv-1a. The above example creates an instance of FNV hash, writes a byte array to it and then gets the value through Sum32() call. You can "forget" what is written to it by Reset() function which will allow you to reuse the hash instance.

I am newly learning Go and along the way sharing some things that I learnt. If you know of a better way to accomplish what I have shared here, please feel free to comment.

No comments: