A Programmer's Guide To Go With LiteIDE
Written by Mike James   
Thursday, 14 November 2013
Article Index
A Programmer's Guide To Go With LiteIDE
Date Structures and Types
Functions
Go Control

Another surprise is that when you declare a variable you put the type at the end not the beginning, i.e var a int and not int a as you would in C or Java. 

You don't have to specify a type if you make an assignment within the declaration and if you don't assign an initial value the variable is set to its zero value.  This means you can write things like:

var i=0
var x,y float32=1.0,2.0

As well as numeric types you also have a Boolean type bool.

These are Go's built in types.

A short-cut to  initializing and declaring variables is provided using

x,y:=1,2

You can also define and use constants. 

Data Structures

When it comes to data structures you have the usual strings, arrays and structs and one welcome extra the map. 

Strings work with Unicode and are immutable but otherwise much as what you would expect:

s="Hello"

You can find the length of string using the len function and you can access individual bytes of a string using indexing s[0].  Strings in Go are fairly primitive but with the addition of the string package you can do everything that you can do in other languages. 

Arrays are declared using square brackets and start from zero index. For example:

var buff [32]byte
fmt.Println(buff[10])

Mutlidimensional arrays are build up as arrays of arrays/

var buff [32][32]byte
fmt.Println(buff[10][0])

Arrays are not dynamic and cannot be resized. However you can use a slice to get the same effect. A slice wraps a portion of an array and can change its size by changing the area of the array it gives you access to. 

Stucts are constructed much like in other languages. For example:

func main() {

    type point struct {
      x, y int
    }

    var p = point{10, 10}
    fmt.Println(p.x)
}

This declares a new struct type with two int fields x, and y. In the main function an new instance of the type is created and initialized. Go doesn't use the term "instance" but prefers the term "value" and you create a value of the type. 

A struct definition can also include a struct as a field. The initializer {10,10} is  struct literal. You can also use struct literals with named fields e.g {X:10}.

This is our first encounter with the idea of a Go type - more on this important topic later.

The final data structure available for your use is the Map. This is the Go equivalent of the hash map, associative array or dictionary in other languages. 

You can set up a map with a given type of key and a given type of value. If you have never used an associative array then think of it like an array where you can retrieve the value using a general key rather than just an index. For example:

var m = make( map[string]int) 
m["mike"] = 10
m["lucy"] = 30
fmt.Println(m["lucy"])

displays the result 30. 

The make function is one of the two functions which create values from types - and to make any sense of it we next have to find out more about types. 

Types

In Go a Type is just specifies a set of values and operations. Types in Go serve a very different purpose to types in well known object oriented languages such as Java and C++. There is no type hierarchy, there is no notion of class and there is no inheritance.  Types are also inferred, i.e. Go uses duck typing. 

You can define a type on the fly using a type literal or you can assign a type to an identifier for reuse. 

Custom types are built up out of a small number of composite types - array, struct, pointer, function, interface, slice, map and channel. Each of these has its own way of being used to define a type but when you see it in action it is fairly obvious.  You can also use all of the predefined types like int, string and so on in type definitions.

To define a type you use:

type typename typespecification

So for example:

type myint int

defines myint to be a new type of int. Redefining the predefined types is useful if you plan to create an extended version of the type - see functions and methods later.

More usually you make use of the composite types to build custom types. For example:

 type point struct {
    x, y int
}

Is a new struct type.

You can also create array types 

type myarray [20]int

You can use custom types in type definitions:

type point struct {
        x, y int    
}
    
type arrayPoints [10]point

and this does create an array of point structs. 

You can spend a few happy hours or more discovering all the different ways of creating new types but the next important thing to discover is what does Go use types for? 

Types are used for two main things in Go

  • type checking

and

  • creating values.

Type checking works much as you might expect - you can only assign to a variable a value of the same type it is declared to be. That is types are used for static type checking at compile time. 

For example:

var c myint    
c = "string"

will fail.  However

var c myint    
c = 1

will work because even though 1 is an int and c is a myint they are both of the same underlying type. 

The second thing that types do is that they construct values of the type when you use them in a variable declaration. For example:

var i int

or 

var p point

The exceptions to this rule are the slice, map and channel types which have to be used with the make function to create a value of the type.  For example:

var m = make( map[string]int) 

Make is one of the two allocation functions that Go supports the other being new. This creates a value of the type and returns a pointer to it. Go has pointers that are used much in the same way C pointers are.

That is you can de-reference a pointer using * and take the address of a value using &. However, there is a very big difference between Go pointers and C pointers. There is no pointer arithmetic. In Go the main purpose pointers serve is to allow you to pass by reference - more of which in the section on functions. 

If you have a type T then the type *T is a pointer to type T. 

As an example of new in action consider:

var add= new(int)

This creates a new integer value and returns its address which is stored in add. The variable add is of type *int.

If you use

fmt.Print(add)

you will see the address of the value. To see the value you have to use

fmt.Print(*add)

As mentioned earlier you don't have to give a type a name you can use use a type specification directly. For example:

var p struct {
        x, y int
    }

If you don't want to reuse a type then this is a reasonable way to do things. 

goruns



Last Updated ( Thursday, 04 July 2019 )