home.

tagged: golang

Golang: Type conversion and type methods

You can convert one basic type to another similar type with possible loss of accuracy using:

            f := 234.234
            i := int64(f) // We're losing the decimals here

This will also work for strings and []byte, etc. They have to be similar types. Converting a string to an int will produce a compilation error.
 
To convert dissimilar types (i.e. interface{} and anything else) we use type assertions. We'll talk about them in the next post.
 
You can convert to and from custom types of the same type.

            type customslice []string
            ...
            realslice := []string(customslice{"one", "two"})    // convert from custom type to a basic type
            cs customslice = customslice([]string{"one", "two"}) // convert from a basic type to a custom type

The customslice(...) was redundant, however, since golang will automatically recognise they're the same type.
 
For example: if you have a function that takes in either a 'customslice' or a []string then you can pass either a customslice or []string to either.

            Thing(customslice{"one", "two"}) // Works
            Thing([]string{"one", "two"})    // Works

            func Thing(s customslice) {
                    fmt.Println(s)
            }

            OtherThing(customslice{"one", "two"}) // Works
            OtherThing([]string{"one", "two"})    // Works

            func OtherThing1(s []string) {
                    fmt.Println(s)
            }
            

You often want to convert to function to a type to gain its methods.

            hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                    //
            })

Your anonymous function is now of the type http.HandlerFunc. This type has the ServeHTTP method (http://golang.org/pkg/net/http/#HandlerFunc).
 
This means your anonymous function can be used anywhere a http.Handler -- http://golang.org/pkg/net/http/#Handler -- is needed. This is because both the HandlerFunc and Handler define the same methods.
 
(You couldn't directly convert to a http.Handler, since http.Handler is of the type interface - not function. More on interfaces later.)
 

golang


Golang regex: Replace and split

You can use the ReplaceAllString methods to replace a string, and manipulate groups if needed.

    rp := regexp.MustCompile("([a-z]+) ([a-z]+)")
    rp.ReplaceAllString("abc def ghi", "$2 $1") // "def abc ghi"

$1 relates to the first group match, and $2 the same. You could just enter text to replace the entireity of the "abc def" string.
 
ReplaceAllLiteralString allows you to interpret the dollar sign literally.
 
You can also use a function to do the replacement. You cannot use a groups here, however, as of 1.1.1 anyway.

    rp.ReplaceAllStringFunc("abc def", func(s string) string {
            if(s=="abc") {
                    return "HA"
            } 
            return s        
    }) // "HA def"

You can split a string using the Split method. The second integer argument is the number of splits to perform. -1 means as many as possible.

    rp = regexp.MustCompile("a")
    i := rp2.Split("zzzzazzzzz", -1) // ["zzzz", "zzzz"]

golang golang-regex


Golang: Maps

A map is a key value store of data. You define it using the map keyword, the key type in brackets, then the value type:
 
var aMap map[string]string

If you attempt to read from this you will get the zero value, "" in this case, of the key. If you try to assign a value to a key, it will crash.
 
You must use make to create a new map. Or use the literal syntax.
 
aMap := make(map[string]string)
anotherMap := map[string]string {"a":"b", "c":"d",}

You can grab values using the key after the map name in square brackets
 
sth := anotherMap["a"] // Will return "b"
sth = anotherMap["z"]  // Will return "", the zero value

Since a map will return the zero value on not found, you can use a map of booleans to implement a set data structure.
 
If you assign to two variables, the second is whether the value is found or not:
 
val, found := anotherMap["a"] // Using the code above, found will be true, and value will be "b"

If your values are slices, you can append an item, even if the value is nil, with the append function (since add something to a nil slice creates the slice):
 
myMap := make(map[string][]string)
// At this point myMap["a"] is nil
myMap["a"] = append(myMap["a"], "z")
// At this point myMap["a"] is ["z"]

Your key be any simple type. In addition, structs (containing only comparable types), interface types, channels and more.
 
You can use struct keys and simple values to simplify adding data to a map. With complex types as values, such as maps or slices, you will need to check they are not there and possibly allocate space.
 
Instead use a key struct, encoding the data in that struct, and have the value as a simple type like a number.
 
aMap[SomeStruct{"hi", 123}]++
// The downside here is your lookup will need to have all that data inside

Maps are not atomic. You will have to use locking if one can be access simultaneously. Or refactor the code so that only one goroutine can access it.

golang


Golang: Slices

A slice is a data structure with three parts: A pointer to a place in an array, the length of the slice, and the capacity of the slice.
 
A slice type looks like an array, but there is no size defintion:
 
var anArray [10]string;
var aSlice []string;

You can initialise a slice either using a literal, the make function, or by using slice syntax (on either arrays or other slices):
 
slice := []string {"a", "b"}     // Literal. Allocated an underlying array for you
slice := make([]string, 5, 5)    // Make args: a type or actual array, the length of slice and the optional capacity of slice (defaults to length)
array := [10]int {1, 2, 3, 4, 5} 
slice := array[0:len(array)]     // [x:y] is slice syntax

In the slice syntax, the first number after the squared bracket is the index of the array to point to, and the second is the length of the slice -- the whole array in this case.
 
You can also say [:] to mean the same thing. [:2] to mean the start of the array to the second element. And [2:] to mean from the second element to the rest of the array.
 
You can append items onto a slice:
 
slice := []string {"a", "b"}
slice = append(slice, "c", "d")

You can copy a slice to another (or two arrays of the same type of size).
 
slice1 := []string {"a", "b", "3"}
slice2 := make([]string, 2)
copy(slice2, slice1)
// slice2 now contains "a", "b" -- not "c" since slice2 is not big enough to hold it

You often want to copy since if you pass around a slice of a large file, since the large file will not be garbage collected until all slice references to it disappear.
 
If you pass around a slice -- as opposed to an array -- the receiving function will be able to change the contents of the underlying array: the slice has a pointer to the underlying array.
 
You can find the capacity of a slice with the cap function:
 
array := [10]int {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := make(array, 5, 10)
fmt.Println(len(slice)) // 5
fmt.Println(cap(slice)) // 10
slice = slice[0:cap(slice)]
fmt.Println(len(slice)) // 10
fmt.Println(cap(slice)) // 10

You can use the range operator as with arrays to achieve a foreach type loop.

golang golang-slices


Golang: Arrays and range

Arrays are not used very much in go since they are inflexible compared to the alternative, a slice.
 
You can define an array by specifying its size in brackets followed by its type. You can make it a literal by using curly brackets afterward.
 
var array [10]string
// Or
arr := [10]string {"Hello"}

Any unspecified values are given the zero value for the type, a "" in this case.
 
You can use [...] to make the compile calculate the size for you.
 
You can use the range operator to iterate through the values.
 
for i, v := range arr {
	fmt.Println(i, v)	
}

Note that the range operator will first return the iteration number and the value.
 
Arrays are passed by value. The following function will not change the first value of the caller's array.
 

...
arr := [10]string {"Hello"}
SomeFunction(arr)
// arr[0] is still "Hello"
...

func SomeFunction(arr [10]string) {
	arr[0] = "Not Changed" 
	// This only changes the array local to this function,
	// not the caller's array.
}

If we had said the parameter was [9]string, for example, the program would not compile. They are different types in go.
 
(If you had said the type was []string then that would be slice. And you would have to pass a slice, not an array. More on that later)
 
If you had passsed an array reference and made the parameter an array pointer, then, of course, the value would be changed. But you would not normally do that in golang code.
 
Instead you use slices.

golang

Page 2 of 5
prev next