A Programmer's Guide To Go With Visual Studio Code
Written by Mike James   
Monday, 08 July 2019
Article Index
A Programmer's Guide To Go With Visual Studio Code
Variables & Structs
Types
Parameters
Go Control

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

Functions

Go isn't a class based hierarchically typed language and it doesn't do objects in the usual way. If you want to just write a function and ignore anything to do with objects you can. Functions are just values and in this sense they are what in other languages would be referred to as "first class objects". 

A function is declared using something like:

var myFunc = func(a, b int) int {
    return a + b
}

You can declare the type of the parameters and the return type. If you declare a return type then the function has to have a return statement. 

Notice the way the function value is assigned to the variable myFunc. You can use a more conventional form of function definition where the variable is specified as the function name:

func myFunc(a, b int) int {
    return a + b
}

In either case you could call the function using something like:

fmt.Println(myFunc(1, 2))

You can return multiple results in a return statement and name the variables to be returned in the function header. 

For example:

func myFunc(a, b int) (sum int) {
    sum = a + b
    return
}

In this case sum is named as an integer return value and it is automatically the value of the function when it returns. 

Returning multiple values is also easy:

func myFunc(a, b int) (int, int) {
    return a + b, a - b
}

In this case you have to accept both of the integer results:

   x,y := myFunc2(1, 4)
   fmt.Println(x,y)

You cannot opt to just have one of the two return values, which you can in some other languages. 



Last Updated ( Monday, 08 July 2019 )