Golang datatypes

From wikinotes
Revision as of 21:01, 29 May 2022 by Will (talk | contribs) (→‎Slices)

Literal Types

"foo"       // string
123         // int (cpu-arch dependent bitsize)
3.14        // float64
6.2e25      // float64
true, false // bool

Boolean

var condition bool = true

Text

String

Go's strings are bytestrings by default.
The are treated as arrays of bytes.

  • Strings are immutable.
  • Strings are UTF-8

TODO:

write some best pratices for handling multi-byte characters

var name string = "will"                 // string
name := "will"                           // string

// slices
var ascii_code uint8 = name[1]           // 2nd char from string
var char string = string(ascii_code)     // get string from ASCII code

bytestring := []byte("hi") == [104, 105] // string as bytes (uint8)

// operators
msg := "hello " + "world"                // concatenation

Rune

Runes are UTF-32 strings.
(Each character is a uint32)

Numeric

Integers

Integer sizes are expressed by their bit-size.

signed

int     //  (however many bits your CPU word-size is)
int8    //                       128 - 127
int16   //                    32,768 - 32,767
int32   //             2,147,483,648 - 2,147,483,647
int64   // 9,223,372,036,854,775,808 - 9,223,372,036,854,775,807

unsigned

uint     // (however many bits your CPU word-size is)
uint8    // 0 - 255
uint16   // 0 - 65,535
uint32   // 0 - 4,294,967,295
// uint64 does not exist

Bytes

Same as uint8.

math/big

Slow, but handles numbers of any size.

Complex Numbers

Go lets you represent complex/imaginary numbers.

var num complex64 = 1 + 2i
var num complex128 = 1 + 2i

var num complex64 = 2i            // alternative for 1 + 2i
var num complex64 = complex(1, 2) // alternative for 1 + 2i

You can also extract the complex/imaginary part of the number.

var num complex64 = 1 + 2i
real(num) // the real number component
imag(num) // the imaginary number component

Pointers

uintptr  // a pointer of however many bits your CPU word-size is

Collections

Arrays

Arrays are statically-sized, homogenous collections of items,
stored contiguously in memory.

family := [2]string{"will", "alex"}    // create 2-item array with these elements
family := [...]string{"will", "alex"}  // create array whose size matches provided elements

var family [2]string                   // create 2-item array, then assign elements
family[0] = "will"
family[1] = "alex"

var families string[3][2]              // create an empty nested array

families := [...]string{               // create nested array using literals
  [...]string{"will", "alex"},
  [...]string{"tom", "fiona"},
  [...]string{"alex", "morgan"},
}

len(family) == 2

While arrays are mutable, when assigning an array to a new variable,
you're actually duplicating the array.

numbers := [...]int{1, 2, 3}
copy_of_numbers := numbers
copy_of_numbers[1] = 9        // <-- does not change 'numbers'

fmt.Println(numbers)          // [1 2 3]
fmt.Println(copy_of_numbers)  // [1 9 3]

Rather than passing array-data to a function, in most cases, you probably want to pass a pointer to it.

numbers := [...]int{1, 2, 3}
ref_to_numbers := &numbers   // <-- get pointer to 'numbers'
ref_to_numbers[1] = 9

fmt.Println(numbers)          // [1 9 3]
fmt.Println(ref_to_numbers)   // &[1 9 3]

Slices

The Slice datastructure is a resizable abstraction built overtop of an array.
see https://go.dev/blog/slices-intro

A slice's datastructure is composed of:

  • pointer to array element
  • length of slice
  • capacity (length) of underlying array

Some properties:

  • Assigning a slice to another variable will not duplicate the data
  • Changing a slice will change the underlying array
  • The slice itself isn't technically resizable, but there are methods to help manage duplicating a slice into a larger one if required.


building slices

numbers := []int{1, 2, 3}

// build an empty slice
numbers = make([]int, 3, 3)  // `make(type, length, [capacity])`
numbers = make([]int, 3)     // if not specified, capacity matches lenth

// build slices from arrays, or other slices
numbers := [...]{1, 2, 3, 4, 5}     // array {1, 2, 3, 4, 5}
mySlice := numbers[:2]              // slice {1, 2, 3}

slice functions

len(numbers) == 3 // length
cap(numbers) == 3 // capacity

// growing a slcie manually
numbers := [...]{1, 2, 3, 4, 5}     // array {1, 2, 3, 4, 5}
mySlice := numbers[:2]              // slice {1, 2, 3}
myLargerSlice([]int, 4, 5)          // create a larger slie of 4 items
copy(mySlice, myLargerSlice)        // copy data from original slice to larger slice

// append to slice, growing array if necessary
numbers := []int{1, 2, 3}
append(numbers, 4, 5)

// extend/concatenate slices
otherSlice = []int{6, 7, 8}
append(numbers, ...otherSlice)

Compound Types