Sage-Code Laboratory
index<--

Go Objects

Go is object oriented language and has support for creation of objects that have methods and properties. However Go do not have classes like Java does. It has only types like Ada language.

Struct

In Golang, a struct is a user-defined data type that allows you to group related fields into a single unit. Struct fields can be of any type, including other structs, functions, and variables.

To declare a struct, you use the struct keyword followed by the name of the struct and a list of fields. Each field is declared with a name and a type. For example, the following code declares a struct called Person with two fields:


package main

type Person struct {
  Name string
  Age int
}

Once you have declared a struct, you can create instances of it using the new keyword. For example, the following code creates an instance of the Person struct and assigns it the values "John Doe" and 30:


p := new(Person)
p.Name = "John Doe"
p.Age = 30

You can then access the fields of a struct using the dot operator. For example, the following code prints the name and age of the Person struct:


fmt.Println(p.Name, p.Age)

Struct types are a powerful tool for organizing data in Golang. They can be used to create objects that represent real-world entities, such as people, places, and things.

Instance

In Java we use keyword "new" to create an instance of a class. In Go we do not have keyword new and there are no classes, but there is instance of a struct type that is an object.

Example:

In this code, we define a struct called "Person" with fields for "name" and "age". We also define a constructor function called "NewPerson" that takes the "name" and "age" as arguments and returns a new instance of "Person".


package main

import "fmt"

// Define a struct called Person with fields for name and age.
type Person struct {
    name string
    age  int
}

// Define a constructor function for Person
// that returns a new instance of the struct.
func NewPerson(name string, age int) *Person {
    p := Person{name: name, age: age}
    return &p
}

func main() {
    // Create a new Person object using the constructor.
    p := NewPerson("John Doe", 30)

    // Use dot notation to access fields of the Person object.
    fmt.Println(p.name, "is", p.age, "years old.")
}

In the "main" function, we create a new "Person" object using the "NewPerson" constructor and assign it to the variable "p". We then use dot notation to access the "name" and "age" fields of the "Person" object and print them to the console.

I hope this helps! Let me know if you have any other questions.

Methods

A method is a function with a special receiver argument. This argument has the role of "this" or "self" that you can use in Java or Python. The receiver appears in its own argument list between the func keyword and the method name.

You can define methods on user defined types by using receiver argument. Types with methods can be based on collections, structures or simple types. In this way a type becomes like class.

Example:

In next example, the Abs method has a receiver of type Vertex.The method Abs() can be called using dot notation with the type name used as a qualifier like this v.Abs().

//file class.go
package main

import (
    "fmt"
    "math"
)

type Vertex struct {
    X, Y float64
}

func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
    v := Vertex{3, 4}
    fmt.Println(v.Abs())
}

Interfaces

An interface is an abstract data type. It define of a set of methods that must be implemented for a type that implement the interface. A value of interface type can hold any value that implements those methods.

//file interface.go
package main

import (
    "fmt"
    "math"
)

//define an interface
type Abser interface {
    Abs() float64
}

func main() {
    var a Abser

    //define a function f
    f := MyFloat(-math.Sqrt2)
    v := Vertex{3, 4}

    a = f  // a MyFloat implements Abser
    a = &v // a *Vertex implements Abser

    // In the following line, v is a Vertex (not *Vertex)
    // therefore does NOT implement Abser.
    a = v

    fmt.Println(a.Abs())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
    if f < 0 {
        return float64(-f)
    }
    return float64(f)
}

type Vertex struct {
    X, Y float64
}

func (v *Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

Note: There is an error in the example code on line 22. Vertex (the value type) doesn't implement Abser because the Abs method is defined only on *Vertex (the pointer type).

Empty Interface

The interface type that specifies zero methods is known as the empty interface: interface{}

An empty interface may hold values of any type. (Every type implements at least zero methods.)

Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}.

//file empty_interface.go
package main

import "fmt"

func main() {
    var i interface{}
    describe(i)

    i = 42
    describe(i)

    i = "hello"
    describe(i)
}

func describe(i interface{}) {
    fmt.Printf("(%v, %T)\n", i, i)
}

Interface Values

Under the covers, interface values can be thought of as a tuple of a value and a concrete type (value, type). An interface value holds a value of a specific underlying concrete type. Calling a method on an interface value executes the method of the same name on its underlying type.

package main

import (
    "fmt"
    "math"
)

type I interface {
    M()
}

type T struct {
    S string
}

func (t *T) M() {
    fmt.Println(t.S)
}

type F float64

func (f F) M() {
    fmt.Println(f)
}

func main() {
    var i I

    i = &T{"Hello"}
    describe(i)
    i.M()

    i = F(math.Pi)
    describe(i)
    i.M()
}

func describe(i I) {
    fmt.Printf("(%v, %T)\n", i, i)
}

Read next: Error handling