Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Composite Data Types in Go: Arrays, Slices, Maps, and Structs

Tech 3

Arrays

An array is a fixed-length sequence of zero or more elements of the same type.

Declaring an array:

var numbers [3]int // Elements are initialized to the zero value of the type (0 for int).
fmt.Println(numbers[0]) // Prints 0

Initializing an array:

var primes = [3]int{2, 3, 5} // Array literal initialization.

var values [3]int // Declare first.
values[0] = 10    // Initialize later.
values[1] = 20

sequence := [...]int{10, 20, 30} // Length determined by the number of initializers.

largeArray := [...]int{99: -1} // Defines a 100-element array with the last element as -1, others 0.

Using arrays:

fmt.Println(sequence[0]) // Access the first element.

// Iterate with index and value.
for index, val := range sequence {
    fmt.Printf("Index: %d, Value: %d\n", index, val)
}

// Iterate for values only.
for _, val := range sequence {
    fmt.Printf("Value: %d\n", val)
}

// Get array length.
fmt.Printf("Length: %d\n", len(sequence))

Slices

A slice is a variable-length sequence of elements of a single type, written as []T. It provides a view into an underlying array. A slice has three components: a pointer to the first accessible element, a length (number of elements), and a capacity (number of elements from the slice start to the end of the array). The zero value of a slice is nil.

Creating slices:

// Create an underlying array.
daysOfWeek := [...]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}

// Create a slice from the array.
weekend := daysOfWeek[5:7] // Contains elements at indices 5 and 6.
// Syntax: [i:j] -> elements i through j-1.
// [:j] -> start to j-1.
// [i:] -> i to end.
// [:] -> all elements.

// Slice literals.
numbers := []int{1, 2, 3}

// Using make.
slice := make([]int, 3, 5) // Length 3, capacity 5.

Using slices:

// Appending elements.
numbers = append(numbers, 4) // Appends 4 to the slice.

// Copying slices.
var newSlice []int
copy(newSlice, numbers) // Copies elements from numbers to newSlice.

Maps

A map is an unordered collection of key-value pairs, written as map[KeyType]ValueType. Its zero value is nil.

Creating maps:

// Using make.
ageMap := make(map[string]int)
ageMap["Alice"] = 30
ageMap["Bob"] = 25

// Using a literal.
ageMap = map[string]int{
    "Alice": 30,
    "Bob":   25,
}

Iterating over maps:

for name, age := range ageMap {
    fmt.Printf("%s is %d years old.\n", name, age)
}

Structs

A struct is an aggregate data type that groups zero or more named fields of possibly different types. Each field is called a member. If a member's name starts with an uppercase letter, its exported; otherwise, it is unexported. A struct cannot contain a field of its own type but can contain a pointer to its own type. The zero value of a struct consists of the zero values of its fields.

Defining a struct:

type Person struct {
    ID      int
    Name    string
    Address string
}

// An empty struct.
var empty struct{}

// Empty struct as a map value (e.g., for a set).
set := make(map[string]struct{})

Creating and using struct variables:

var employee Person

// Assigning and accessing fields.
employee.Name = "Charlie"
fmt.Println(employee.Name)

// Using a pointer.
ptr := &employee.Name
fmt.Println(*ptr)

var empPtr *Person = &employee
empPtr.Address = "123 Main St" // Equivalent to (*empPtr).Address = ...

// Initializing with a struct literal.
p := Point{X: 1, Y: 2}
emp := Person{ID: 1, Name: "David"} // Uninitialized fields are set to zero values.

// Getting a pointer to a new struct.
pp := &Point{3, 4}
// Equivalent to:
// pp := new(Point)
// *pp = Point{3, 4}

Struct embedding (anonymous fields):

type Point struct{ X, Y int }

type Circle struct {
    Point   // Anonymous field (embedding).
    Radius int
}

type Wheel struct {
    Circle // Embedding Circle.
    Spokes int
}

// Accessing promoted fields.
var w Wheel
w.X = 10      // Promoted from Point.
w.Y = 20      // Promoted from Point.
w.Radius = 5  // From Circle.
w.Spokes = 36

// Initialization.
w = Wheel{
    Circle: Circle{
        Point:  Point{X: 10, Y: 20},
        Radius: 5,
    },
    Spokes: 36,
}

Methods on structs:

A method is a function with a special receiver argument that binds it to a type.

// Method with a value receiver.
func (p Point) DistanceTo(q Point) float64 {
    dx := q.X - p.X
    dy := q.Y - p.Y
    return math.Sqrt(dx*dx + dy*dy)
}

// Usage.
p1 := Point{1, 2}
p2 := Point{4, 6}
dist := p1.DistanceTo(p2)

// Method with a pointer receiver.
func (p *Point) Scale(factor float64) {
    p.X = int(float64(p.X) * factor)
    p.Y = int(float64(p.Y) * factor)
}

// Calling a pointer receiver method.
pt := &Point{5, 10}
pt.Scale(2.0)
// Also valid with a value; Go automatically takes the address.
pt2 := Point{5, 10}
pt2.Scale(2.0)

JSON Marshaling

The encoding/json package provides support for JSON encoding and decoding.

import "encoding/json"

var team []Person
jsonData, err := json.Marshal(team)           // Compact JSON.
jsonData, err := json.MarshalIndent(team, "", "  ") // Formatted JSON.

Interfaces

An interface type defines a set of method signatures. A type implements an interface implicitly by implementing its methods.

Defining an interface:

type Reader interface {
    Read(data []byte) (n int, err error)
}

Embedding interfaces:

type Writer interface {
    Write(data []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

Implementing an interface:

type Document struct {
    content string
}

func (d *Document) Read(buf []byte) (int, error) {
    copy(buf, []byte(d.content))
    return len(d.content), nil
}
// Document now implements the Reader interface.

The empty interface:

var anything interface{} // Can hold a value of any type.

An interface value holds a pair: a concrete type and a value of that type (dynamic type and dynamic value).

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.