Object oriented programming in Go language

Posted by injh85 on Mon, 17 Jan 2022 15:05:54 +0100

1, Object oriented features in Golang

  • Object oriented programming (OOP) is also supported in Golang, but it is different from traditional object-oriented programming. It is not a pure object-oriented language.
  • There are no classes in Golang. The structure of Go language has the same status as the classes of other programming languages. It can be understood that Golang implements OOP features based on struct.
  • Golang object-oriented programming is very concise, removing the inheritance, method overloading, constructor and destructor, hidden this pointer and so on of the traditional OOP language.
  • Golang still has the characteristics of inheritance, encapsulation and polymorphism of object-oriented programming, but the implementation method is different from other OOP languages. For example, golang does not have the extends keyword, and inheritance is realized through anonymous fields.
  • Golang object-oriented (OOP) is very elegant. OOP itself is a part of the language type system. It is associated through the interface. It has low coupling and is very flexible.

2, Creation and attributes of structure variables

(1) Structural variable basis

1. What are structs and struct variables

Structure represents the abstraction of the same kind of things and is a user-defined data type. Structure variable (instance) is the concrete expression of structure. Structures in Golang can be compared to classes in other languages, and structure variables can be compared to objects in other language classes.

2. Declaration of structure

  • Basic grammar
type Structure name struct {

  field1 type

  field2 type

}

For example:

type User struct {

  UserName string

  Age int

}

3. Four ways to create structure variables

  • Mode 1: var p1 Person
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    // Mode 1 
    var p1 Person
    fmt.Println(p1)
}
  • Mode 2 var p1 Person = Person {}
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    // Mode II/1
    var p1 Person = Person{
        "lily",
        20,
    }
    fmt.Println(p1)

    // Mode II/2
    p2 := Person{
        "harry",
        30,
    }
    fmt.Println(p2)

    //Mode II/3
    p3 := Person{}
    p3.Name = "alice"
    p3.Age = 36
    fmt.Print(p3)

}
  • Mode 3 var p1 *Person = new(Person)
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    // Mode III var p1 *Person = new(Person)
    var p1 *Person = new(Person)
    /*
        At this time, p1 is a pointer type. If assignment is required:
        (*p1).Name = "igon"
        (*p1).Age = 25
        However, for ease of use, the go designer has handled it at the bottom, which can be written as follows:
        p1.Name = "igon"
        p1.Age = 25
    */
    p1.Name = "igon"
    p1.Age = 25

    fmt.Print(*p1) // Dereferencing Pointers  {igon 25}

}
  • Mode 4: P1 * person = & person
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    // Method 4 var p1 *Person = &Person
    var p1 *Person = &Person{}
    /*
        p1 Is a pointer. The standard way to access a field is (* P1) Name = "egg",
        However, the designer of go has processed it at the bottom for convenience, so it can be written as follows:
        p1.Name = "egg",The actual bottom layer will become (* p1) for p1
    */
    p1.Name = "egg"
    fmt.Println(*p1)

}

(2) Deep understanding of structural variables

  • Structures are numerical types, so different structures do not affect each other
  • Existence form of structure in memory
  • All fields in the structure are contiguous in memory
  • Structure type conversion
  • tag in structure

1. Structures are numerical types, so different structures do not affect each other

Structure fields are attributes, generally basic data types, arrays, reference types, etc. After creating a structure variable, if no value is assigned to the field, the field is the default value of the corresponding type.

Boolean type:false,
Value type:0,
character string:"",
Array (related to element type): a [3]int,  Then[0, 0, 0]
Pointer slice,map: nil,Indicates unallocated space

For example:

package main

import "fmt"

type User struct {
    Name string
    Age  int
}

func main() {
    // Create structure variable
    var user User
    fmt.Println(user) // { 0} Empty string and 0, respectively
}

How is it reflected that different structures do not affect each other?

package main

import "fmt"

type User struct {
    Name string
    Age  int
}

func main() {
    // Create the first structure variable
    var u1 User = User{
        "alily",
        20,
    }
    fmt.Println(u1) // {alily 20}

    // Second structure variable,The default value of structure is copy, so u1 And u2 Are two different data spaces
    u2 := u1
    fmt.Println(u2) // {alily 20}

    u2.Name = "tomi"
    fmt.Println(u1, u2) // {alily 20} {tomi 20}
}

2. Existence form of structure in memory

See the above example, how does it exist in memory?


This can also well explain that the structure is a value type, and different structures do not interfere with each other, but what if you want to change the Name of u2 and affect u1 at the same time?

package main

import "fmt"

type User struct {
    Name string
    Age  int
}

func main() {
    // Create the first structure variable
    var u1 User = User{
        "alily",
        20,
    }
    fmt.Println(u1) // {alily 20}

    // The second structure variable is declared as a pointer variable
    var u2 *User = &u1
    fmt.Println(*u2) // {alily 20}

    u2.Name = "tomi"
    fmt.Println(u1, *u2) // {tomi 20} {tomi 20}
}

This is completely different from the memory diagram above:

Therefore, changing the value of u2 will change the value of u1, because u2 is a pointer and stores the address of u1.

3. All fields in the structure are contiguous in memory

package main

import "fmt"

type Point struct {
    x int
    y int
}

type Rect struct {
    leftUp, rightDown Point
}

type Rect1 struct {
    leftUp, rightDown *Point
}

func main() {

    r1 := Rect{
        Point{1, 2},
        Point{3, 4},
    }

    r2 := Rect1{
        &Point{1, 2},
        &Point{3, 4},
    }

    // r1 There are four int,It is continuously distributed in memory
    fmt.Printf("r1.leftUp.x The address is:%p r1.leftUp.y The address is:%p r1.rightDown.x The address is:%p r1.rightDown.y Address:%p \n",
        &r1.leftUp.x, &r1.leftUp.y, &r1.rightDown.x, &r1.rightDown.y)
    /*
        r1.leftUp.x Address: 0xc000000e200
        r1.leftUp.y Address: 0xc000000e208
        r1.rightDown.x Address: 0xc000000e210
        r1.rightDown.y Address: 0xc000000e218
    */

    // r2 There are two*Point Types, their own addresses are also continuous
    fmt.Printf("r2.leftUp The address is:%p r2.rightDown The address is:%p \n", &r2.leftUp, &r2.rightDown)
    /*
        r2.leftUp Address: 0xc000050240
        r2.rightDown Address: 0xc000050248
    */

    // But two*Point The address pointed to by the type is not necessarily continuous
    fmt.Printf("r2.leftUp The address is:%p r2.rightDown The address is:%p", r2.leftUp, r2.rightDown)
    /*
        r2.leftUp Address: 0xc000140b0
        r2.rightDown Address: 0xc00000144c0
    */

}

The continuity of field addresses helps to get values quickly in memory.

4. Structure type conversion

Structure is a user-defined type. It needs to have exactly the same fields (name, number and type) when converting with other types.

package main

import "fmt"

type A struct {
    n1 string
}

type B struct {
    n1 string
}

func main() {
    // Type conversion
    var a A
    var b B
    a = A(b)

    fmt.Println(a, b)

}

The structure uses type to get the alias again. It is also considered a new data type in golang, but it can be cast through type.

5. tag in structure

Each field in the structure can be written with a tag, which is obtained through the reflection mechanism. The common scenarios are serialization and deserialization.

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {

    // Create a structure variable
    user := User{
        "kity",
        23,
    }
    fmt.Println(user)

    // Serialize structure variables
    jsonStr, err := json.Marshal(user)
    if err != nil {
        fmt.Print(err)
    } else {
        fmt.Println(string(jsonStr)) // {"name":"kity","age":23}
    }

}

If the field name in go is capitalized, it can only be used in this package. Therefore, if it needs to be serialized in other packages encoding/json, it needs to be capitalized, but the fields returned to the front end are generally lowercase fields. Therefore, in order to solve this problem, tag is used.

 

Topics: Go