golang – some constructs part 1

      No Comments on golang – some constructs part 1

Since starting to play with golang I’ve run into a couple of interesting items I thought worth writing about.  For those of you that are seasoned developers, I assure you, this wont be interesting.  But for us that are getting started this might be worth reading. 

Pointers
Nothing super exciting here if you’ve used them in other languages but it’s worth talking about since it can be confusing.  Pointers are really just a way for us to gain access to the ‘real’ variable when you aren’t in the function that defines it.  Put another way, when you call a function that takes a variable, you are only giving that function a copy of the variable, not the real variable.  Pointers  allow us to reference the actual location in memory where the value is stored rather than the value itself.  Examples always make this more clear.  Take for instance this example of code…

package main

import "fmt"

func main() {
        //Define myname and set it to 'jonlangemak'
        myname := "jonlangemak"
        //Rename without using pointers
        rename(myname)
        fmt.Println(myname)
        //Rename using pointers
        pointerrename(&myname)
        fmt.Println(myname)
}

//Function without pointers
func rename(myname string) {
        myname = "reallycooldude"
}

//Function with pointers
func pointerrename(myname *string) {
        *myname = "reallycooldude"
}

If we run this sample code, the output we’ll get will look like this…

jonlangemak
reallycooldude

I define two functions, one called ‘rename’ that takes a variable called ‘myname’ as a type of string.  The ‘pointerrename’ function takes a variable called ‘myname’ which is a type int pointer.  We denote the pointer by using a ‘*’.  Note that in the main function when I want to pass the pointer to the function I use a ‘&’.  The ‘&’ tells golang to find the location of the variable and pass the pointer to the function which is expecting to receive a pointer of type int. 

Structs
Structs allow you to sort of create you own variable type.  And when I say your own variable type, I mean more like a combination of multiple variables into on.  Take for instance this example…

package main

import "fmt"

//Define a struct of type indexcard
type indexcard struct {
        name string
        age  int
}

func main() {
	//Create a var of type indexcard
        var jon indexcard
	//Set the name
        jon.name = "Jon Langemak"
        fmt.Println(jon)
	//Create a var of type indexcard and populate it immediately
        bob := indexcard{"Bob Bobster", 55}
        fmt.Println(bob)

}

The output from this program will be…

{Jon Langemak 0}
{Bob Bobster 55}

So they’re sort of nice way to keep track of data that falls into key/value pairs. 

Methods
Once you have a struct, you can define a method associated with it.  What distinguishes methods from functions is the addition of defining the method type in the function.  Take this example for instance…

package main

import "fmt"

type indexcard struct {
        name string
        age  int
}

func main() {
        bob := indexcard{"Bob Bobster", 55}
        fmt.Println("Bob is currently ", bob.age, " years old")
        fmt.Println(bob.age)
        fmt.Println("If we make Bob older he is  ", bob.makeolder(), " years old")
        bob.makeyounger()
        fmt.Println("If we make Bob younger he is  ", bob.age, " years old")
}

//Method to make Bob younger without a return
func (person *indexcard) makeyounger() {
        person.age -= 15
}

//Method to make Bob older with a return
func (person *indexcard) makeolder() int {
        person.age += 5
        return person.age
}

Here we have the same struct called ‘indexcard’ but we also have a couple of methods related to the construct.  Notice that these methods define the type of struct they are receiving, a variable named person of type ‘indexcard’.  Notice that the ‘person’ variable is a pointer reference.  Also note that we aren’t using the ‘&’ when we call the function from the main function.  Golang is smart enough to know to do the pointer magic when calling methods. 

So what does the output of this look like?…

Bob is currently  55  years old
If we make Bob older he is   60  years old
If we make Bob younger he is   45  years old

As you can see, we called the methods in two different manners from the main function.  To make Bob older we called the method and the function call returns an integer based on adding 5 to Bob’s existing age.   To make Bob younger we call the method directly.  The method ‘makeyounger’ is not a return function and instead updates the pointer directly.  When back in the main function we print Bob’s age again we get his much younger age of 45.

Slices
Slices are sort of the array of golang.  I mean – they’re really sort of a wrapper around an array.  The only difference between an array and a slice in golang is you define the size of an array whereas a slice you don’t define the size.  There’s tons of info out there on the differences but from what I can discern, that’s really it.  So that being said, here’s a quick example…

package main

import "fmt"

func main() {
	//Define and populate a slice called slice1
        slice1 := []string{"jon", "bob", "bill", "ted", "mark"}
        fmt.Println(slice1)
	//Initialize a slice called slice 2 of type string
        slice2 := []string{}
	//Add data to the slice
        slice2 = append(slice2, "jon", "bob")
        fmt.Println(slice2)
	//Add more data to the slice
        slice2 = append(slice2, "bill", "ted", "mark")
        fmt.Println(slice2)
	//Return a specific value of the slice
        fmt.Println(slice2[:1])
}

Slices work much like arrays do but ,in my opinion, are easier to work with. 

Embedded Types
Embedded types are a way to embed a struct within another struct.  When you do this, you can reference values of the embedded struct directly.  An example will clear up any remaining confusion…

package main

import "fmt"

//Create a struct that's composed of 2 other structs
type indexcard struct {
        person
        house
}

//Create the embedded struct person
type person struct {
        name string
        age  int
}

//Create the embedded struct house
type house struct {
        address string
        state   string
        zipcode string
}

func main() {
        //Create a var of type indexcard
        var me indexcard
        me.name = "Bob"
        //Items for either of the embedded structs can be set directly
        me.age = 21
        //Methods can be created against the struct just like normal methods
        me.sethouse("1111 Berry Lane", "Minnesota", "55555")
        me.printall()

}

//Method that receives input and sets data in the indexcard struct, no return
func (input *indexcard) sethouse(newaddress string, newstate string, newzip string) {
        input.address = newaddress
        input.state = newstate
        input.zipcode = newzip
}

//Method that prints data from the indexcard passed to the method
func (input *indexcard) printall() {
        fmt.Println("The whole address card")
        fmt.Println("Name:", input.name)
        fmt.Println("Age:", input.age)
        fmt.Println("Address:", input.address)
        fmt.Println("State:", input.state)
        fmt.Println("Zip:", input.zipcode)
}

So not too much new here, just showing that we can create structs that are composed of other structs.

That’s all for tonight, more this weekend hopefully. 

Leave a Reply

Your email address will not be published.