Welcome to new things

[Technical] [Electronic work] [Gadget] [Game] memo writing

Notes on things I got stuck on in Go language (classes and inheritance)

I started Golang.

When I started, I found that Golang is designed to be as simple as possible in its syntax and as simple in its code as possible.

And for that reason, Golang has some slightly tricky syntax.

However, without knowing them, I made judgments based on my preconceptions and self-serving assumptions in other languages, and got into a bit of trouble.

Here, I would like to note down some of the things that I personally got into or misunderstood when I started Golang, as a reminder by topic.

In this issue, I would like to make a note about classes and inheritance in Golang.

Golang has no classes.

It is said that Golang has no classes, and indeed it does.

However, there is something close to class.

To begin with, the main things you want to do in class are usually the following.

  • Combine multiple variables into one group (member variables)
  • Define functions that can operate on them (member functions) tied to the summary

Golang achieves what I wanted to do above by using "structs" to group multiple variables into one group, and allowing functions that manipulate the grouped items to be defined as special functions tied to the struct.

For example, a class with member variables "x" and "y" and a member function "test()" to get their total value can be created as follows.

package main

import "fmt"

// Putting variables together in a structure
type myStruct struct {
    x int
    y int
}

// Function to manipulate a structure Structure ". Called by operator
func (p *myStruct) test() int {
    return p.x + p.y
}

func main() {
    var a myStruct
    a.x = 1
    a.y = 2
    fmt.Println(a.test())  // 3
}

The "test()" function is a little unfamiliar, but this function is a member function called from the "." operator in the structure.

Since the elements of a structure can be accessed by anyone from the outside, the same thing can be accomplished by writing a function that takes the structure as an argument and manipulates it, without having to define member functions.

package main

import "fmt"

type myStruct struct {
    x int
    y int
}

// Manipulate a structure by taking a structure as an argument
func test(p *myStruct) int {
    return p.x + p.y
}

func main() {
    var a myStruct
    a.x = 1
    a.y = 2
    fmt.Println(test(&a))  // 3
}

However, even for structures, there is a way to write special functions that can be called with the . operator so that those operation functions can be written with the "." operator, just like classes.

When written like this, it looks at first glance like a member function of a class.

In reality, the function is manipulated by passing a structure (or pointer to a structure) to the function, but it is the class in Golang that allows it to be written as if it were a member function of the structure.

inheritance

As mentioned above, Golang does not have classes, but rather "structure + structure-operated function = class-like function".

There are times when you want to extend an already defined class-like structure by adding variables or operational functions later. This is what is called inheritance in a class.

Golang can also do those inheritance-like things.

If you register a parent structure as an element of a child structure with no element name but only the name of the parent structure, you can access the parent structure with the element name of the parent structure.

It is difficult to understand in writing, so the code is as follows.

package main

import "fmt"

// parent structure
type parentStruct struct {
    x int
    y int
}

// Functions of the parent structure
func (p *parentStruct) testParent() {
    fmt.Println("Parent", p.x, p.y)
}

// child structure
type childStruct struct {
    z int
    parentStruct  // parent structure
}

// Function of child structure
func (p *childStruct) testChild() {
    // Accessing Variables in Parent Structures
    fmt.Println("Child", p.parentStruct.x, p.parentStruct.y, p.z)  
}

func main() {
    var a childStruct
    a.parentStruct.x = 1  // Accessing parent variables
    a.parentStruct.y = 2  // Accessing parent variables
    a.z = 3  // Accessing Child Variables
    a.parentStruct.testParent() // Parent 1 2 Access parent function
    a.testChild()               // Child 1 2 3 Access child functions
}

pseudo-succession

Looking at the aforementioned code, the child structure just has elements of the parent structure rather than inheriting from it, which is, well, what it should be.

But here is the key.

When the above structure is written, member variables and functions of the parent structure can be called by writing member variables and functions directly under the child structure.

In other words, the preceding code can be written as follows, omitting the parent structure name.

package main

import "fmt"

// parent structure
type parentStruct struct {
    x int
    y int
}

// Functions of the parent structure
func (p *parentStruct) testParent() {
    fmt.Println("Parent", p.x, p.y)
}

// child structure
type childStruct struct {
    z int
    parentStruct
}

// Function of child structure
func (p *childStruct) testChild() {
    // Accessing Variables in Parent Structures
    fmt.Println("Child", p.x, p.y, p.z)  // Parent structure modifications can be omitted.
}

func main() {
    var a childStruct
    a.x = 1  // Access to parent variables Can omit parent structure modifications
    a.y = 2  // Access to parent variables Can omit parent structure modifications
    a.z = 3
    a.testParent() // Parent 1 2 Access to parent function Can omit parent structure modifier
    a.testChild()  // Child 1 2 3
}

If I can write it like this, it looks like a quick succession.

In fact, just having the parent structure as an element is not inheritance, but it is inheritance in Golang that makes it possible to write as if it were inherited.

What if the element and function names are covered?

What happens if a child structure defines an element or function with the same name as the parent structure?

In that case, the element/function of the child structure is used. Access to elements and functions of the parent structure is done by specifying the parent structure name, as described in the first section, in a mature manner, since it is unavoidable.

package main

import "fmt"

type parentStruct struct {
    x int
    y int
}

func (p *parentStruct) test() {
    fmt.Println("Parent", p.x, p.y)
}

type childStruct struct {
    x int
    parentStruct
}

func (p *childStruct) test() {
    // x is duplicated, so to access x in the parent structure, specify the parent structure
    fmt.Println("Child", p.parentStruct.x, p.y, p.x) 
}

func main() {
    var a childStruct
     // x is duplicated, so to access x in the parent structure, specify the parent structure
    a.parentStruct.x = 1
    a.y = 2
    a.x = 3
    // Since test() is a duplicate, to access the parent structure test(), specify the parent structure
    a.parentStruct.test()  // Parent 1 2  
    a.test()              // Child 1 2 3
}

In other words, "the member variables and functions of the parent structure can be called by writing member variables and functions directly under the child structure" because the compiler looks at the code and completes the parent structure names behind the scenes for goodness' sake.

Inheritance Usage

There are times when you want to add elements or functions to a structure that has already been created as an object. In such cases, inheritance is a good way to do so.

For example, suppose we want to extend the http.Clinet structure so that we can do a Google search and retain the results.

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

// Inherit structures with new functionality
type googleSearch struct {
    result string  // result
    *http.Client   // Pointer to the structure from which it is inherited
}

// Add search() function Search results are stored in result
func (p *googleSearch) search(q string) {
    resp, err := p.Get(fmt.Sprintf("https://www.google.com?q=%s", q))
    if err != nil {
        return
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return
    }
    p.result = string(body)
}

func main() {
    c := &http.Client{}
    g := googleSearch{Client: c} // Inherit http.Client and add new elements/functions
    g.search("test")
    fmt.Println(g.result)
}

There are many cases where structures are obtained by pointers, and in those cases, the key is to make sure that the parent structure is received by pointers.

When creating an extended structure, assign the pointer of the parent structure to the pointer that has already been obtained.

Then, elements and functions of the parent structure can be accessed directly from the child structure.

Impressions, etc.

Since structs and their operation functions are defined independently in different places, it is more difficult to find out what operation functions are available for a given struct than for a class.

In fact, structures are structures and functions are functions, and the compiler only ties them together in the coding, and the structure is not involved in what its member functions are.

Inheritance is not inheritance, it is simply a structure with parent structures as elements. I got into this area by misunderstanding. It is easy to get into if you know how to omit the parent structure name first.

Golang's syntax is primitive, but it allows for a variety of writing styles and abbreviations, making it equivalent to a high-performance language.

Hmmm...Golang is a reasonable and quite interesting language.

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com