This is the 28th day of my participation in the August Text Challenge.More challenges in August

Day 1: Basics of go objects. How to create struct, method, constructor (factory function), receiver pattern

Day 2: Packages, how to introduce external packages and system packages (defining aliases or combinations)

Day 3: Define a main method for each directory.


 

Introduction to Object orientation

  1. The GO language only supports encapsulation, not inheritance and polymorphism.

So what inheritance and polymorphism do, how do we do that? Using interfaces, go is interface oriented programming.

  1. Go only supports encapsulation, so go has no classes, only structs

 

The usage of the structure

  1. Struct creation method

 

type TreeNode struct { Value int Left, Right *TreeNode} func main() {var root TreeNode root = TreeNode{Value:4} root.Left = &treenode {} root.right  = &TreeNode{5, nil, nil} root.Left.Right = new(TreeNode) fmt.Println(root) }Copy the code

  • Several ways to create an instance

    • var root TreeNode
    • TreeNode{}
    • Use the built-in function new
  • Use both the address and the structure itself. To access members

    • This sentence is very important, before I have not understood, why the structure is also hit can access it
  1. Method of instantiating a structure in slice

Func main() {var root TreeNode root = TreeNode{Value:4} root.Left = &treenode {} root.Right = &treenode {5, nil, nil} root.Left.Right = new(TreeNode) fmt.Println(root) nodes : = []TreeNode{ {4, nil,nil}, {}, {Value:3}, {5, nil, &root}, } fmt.Println(nodes) }Copy the code

When constructing a structure in Slice, you can omit the structure name

nodes := []TreeNode{
        {4, nil,nil},
        {},
        {Value:3},
        {5, nil, &root},
}
Copy the code

 

3. Go language constructor?

root = TreeNode{Value:4}
root.Left = &TreeNode{}
root.Right = &TreeNode{5, nil, nil}
root.Left.Right = new(TreeNode)
Copy the code
  • The GO language has no constructor. But as you can see from the example above, he has given a variety of constructors, no arguments, one argument, multiple arguments
  • What if we still want to define our own constructor? We can process the function.

  

type TreeNode struct {
    Value int
    Left, Right *TreeNode
}

func  NewTreeNode(value int) *TreeNode {
    return &TreeNode{Value:value}
} 
Copy the code

  • If you look at the constructor, the input parameter is a value and the output parameter is the address of a TreeNode. The return value is new a local variable. That’s the factory function.
  • The factory function returns an address

Problem: NewTreeNode returns the address of a local variable. This is not allowed in Java. But it is allowed in GO.

Is the local TreeNode in the heap or on the stack?

C language, local variables are placed on the stack, if you want to be accessed by others must be placed on the heap, after the completion of manual recycling.

Java language, classes are placed on the heap, when the use of a new, will be automatically garbage collection

With GO, we don’t need to know if it’s created on the heap or on the stack. This is determined by the go language’s compiler and runtime environment. He’s going to decide, if the TreeNode doesn’t take the address, it doesn’t need to be used by anyone else, it’s going to be allocated on the stack, and if the TreeNode returns the address, it’s going to be used by someone else, it’s going to be allocated on the heap. Once it’s allocated on the heap, it’s recycled

As above: we define a structure like this

type TreeNode struct { Value int Left, Right *TreeNode} func NewTreeNode(value int) *TreeNode {return &TreeNode{value :value}} func main() {// create structure method var root TreeNode root = TreeNode{Value:3} root.Left = &TreeNode{} root.Right = &TreeNode{5, nil, nil} root.Left.Left = new(TreeNode) root.Left.Right = NewTreeNode(2) }Copy the code

 

 

 

4. How to define a method for a structure

type TreeNode struct { Value int Left, Right *TreeNode } func NewTreeNode(value int) *TreeNode { return &TreeNode{Value:value} } func (node TreeNode) Print() {  fmt.Println(node.Value) }Copy the code

We defined a Print method,

  • There is a receiver (node TreeNode), equivalent to this in other languages. In fact, the go language defines methods in the same way as normal method definitions

    func Print(node TreeNode) {
        fmt.Println(node.Value)
    } 
    Copy the code

    The function is the same, but it’s the method of the structure that’s written up front. There are slight differences in use

    Print (root); print(root)Copy the code

    Question: Since node TreeNode is written like a normal function, does it pass a value or a reference? The answer is pass. Let’s verify that

    type TreeNode struct { Value int Left, Right *TreeNode } func NewTreeNode(value int) *TreeNode { return &TreeNode{Value:value} } func (node TreeNode) Print() { Println(node.value)} func (node TreeNode) setValue() {node.value = 200} func main() {var root TreeNode root = TreeNode{Value:3} root.Left = &TreeNode{} root.Right = &TreeNode{5, nil, nil} root.Left.Left = new(TreeNode) root.Left.Right = NewTreeNode(2) root.Print() root.setValue() root.Print() }Copy the code

     

    Output result:

    33
    Copy the code

    The setValue() method has changed its Value to 200, but it still prints 3. Receiver method method definition is the value of the way copy, internal modification, does not affect the outside

    So, how do we get him to set, we send him an address

    func (node *TreeNode) setValue() {
        node.Value = 200
    }
    Copy the code

    The difference with the previous method is that the receiver passes an address. The usage is the same as before. This enables address copying, internal modification, and external validity.

Conclusion:

1. The print() method is called to print a copy of the value

2. Call setValue() to copy the address and assign values to the object in the address.

4. Nil Pointers can also call methods

Note: The emphasis here is on nil Pointers. Not a nil object

Why do you write it out here? It’s because he’s different from what I’ve learned in Java: null objects call methods, property calls give an error, whereas nil can call methods.

So let’s look at this demo

  

type TreeNode struct { Value int Left, Right *TreeNode } func NewTreeNode(value int) *TreeNode { return &TreeNode{Value:value} } func (node TreeNode) Print() {  fmt.Println(node.Value) } func (node *TreeNode) setValue() { node.Value = 200 } func main() { var node TreeNode fmt .Println(node) node.Print() node.setValue() node.Print() }Copy the code

 

Output result:

{0 <nil> <nil>}
0
200
Copy the code

Here the treeNode in Main is an object, not an address. It will give a default value if there is no value at initialization. So, using it to call, it’s definitely okay. We’re talking about null Pointers here. Let’s look at the null pointer case

type TreeNode struct { Value int Left, Right *TreeNode} func (node *TreeNode) Print() {if node == nil {ftt.println ("node is null ") return} fmt.Println(node.Value) } func main() { var node *TreeNode fmt.Println(node) node.Print() }Copy the code

 

The difference here is that the TreeNode is a pointer.

Let’s see what happens

A <nil> node is a null pointerCopy the code

Indeed, the Print method is successfully called and the Node object is caught as empty

But it’s important to note that calling a property on a nil object is still an error.

type TreeNode struct { Value int Left, Right *TreeNode} func (node *TreeNode) Print() {if node == nil {FMT.Println("node is null ") // return} fmt.Println(node.Value) } func main() { var node *TreeNode fmt.Println(node) node.Print() }Copy the code

Comment out return. Look at the results

A panic exception was reported.

So does the pointer receiver come up and say is this pointer nil? It doesn’t have to be. It depends on the usage scenario.

 

  1. Traversal of structure functions

func(node *TreeNode) traveres() {
    if node == nil{
        return
    }
    node.Left.traveres()
    node.Print()
    node.Right.traveres()
}
Copy the code

Iterate over the left subtree, print it out, iterate over the second subtree, print it out

Results:

0, 0, 3, 5, 4Copy the code

Note how node.left.traveres () is written here. We only check if node is nil. In Java, we also check if Node. Left is null. Otherwise it throws an exception, but go doesn’t, and a nil pointer can call a method

 

Should I use a value receiver or a pointer receiver?

  • To change the content, you must use the pointer receiver

  • Using pointer receivers is also considered for large structures: large structures consume a lot of memory

  • Consistency: If pointer receivers are available, it is best to use pointer receivers (recommended)

  • Value receivers are specific to the GO language. Pointer receivers are also found in other languages, c has a pointer to this, Java’s this is not a pointer, it is a reference to an object, python has self.

  • The value/pointer receiver can receive the value/pointer: this means that I can call Print on either an object or a pointer object

    Func main() {var root TreeNode root = TreeNode{Value:3} root.Left = &treenode {} root.Right = &treenode {5, nil, nil} root.Left.Left = new(TreeNode) root.Right.Right = NewTreeNode(4) root.traveres() var node * TreeNode node.traveres() }Copy the code

    Root is a value, node is a pointer, both can call pointer receiver traveres. Similarly, root and Node can both invoke a value receiver

Three.

The main point in the bag is

  1. The uppercase letter stands for public and the lowercase letter stands for private

  2. Package definition: a directory can have only one package. For example, if you define a folder named tree. Then all files in it will be named tree. Or both main(which is also allowed). You can’t have both tree and main.

How to extend system packages or packages defined by others?

Suppose there’s a structure written by someone else that I want to use, but it doesn’t meet my needs, and I want to extend it, how do I extend it?

In other languages, such as c++ and Java, inheritance is inherited, but there are many disadvantages to inheritance. So go cancels inheritance. This is implemented in two ways

  • Define an alias
  • Using the combination
  1. Define aliases: such as the treeNode example above. If I want to extend in another package, how do I do that by defining an alias?

Package main import ("aaa/tree" "FMT") Now you want to extend a back-order traversal. What to do? The first step is to define a type and then refer to an external type. Use a pointer when referencing a structure, or else make a value copy of the original structure. Expand your method type myTreeNode struct {node * tree. TreeNode} func (myNode * myTreeNode) postorder () {if myNode = = nil | | myNode.node == nil{ return } left := myTreeNode{myNode.node.Left} left.postorder() right := MyTreeNode {mynode.node.right} right.postorder() fmt.print (mynode.node.value)} func main(){var root tree.TreeNode root = tree.TreeNode{Value:3} root.Left = &tree.TreeNode{} root.Right = &tree.TreeNode{5, nil, nil} root.Left.Left = new(tree.TreeNode) root.Right.Right = tree.NewTreeNode(4) root.Traveres() var node *tree.TreeNode node.Traveres() treeNode := myTreeNode{&root} treeNode.postorder() }Copy the code

Step 1: Define a type of your own, and then introduce an external structure. This grouping introduces pointer types, otherwise a value copy of the external structure must be made

type myTreeNode struct {
    node *tree.TreeNode
}
Copy the code

By doing so, the object now has the TreeNode structure that was originally defined. Imagine using it and passing in a structure of type TreeNode. We then operate on the TreeNode structure

 

Step 2: implement your own method, sequential traversal

Func (myNode * myTreeNode) postorder () {/ / to note here is that the myNode node may be empty nodes. If myNode = = nil | |. MyNode node = = nil {return } left := myTreeNode{myNode.node.Left} left.postorder() right := myTreeNode{myNode.node.Right} right.postorder() fmt.Print(myNode.node.Value) }Copy the code

Gets the external structure, and then gets the left subtree of the structure. After obtaining the right subtree of the structure, print it out, and then realize the call to the original structure.

 

Step 3: Invoke

Func main(){var root tree.treenode root = tree.treenode {Value:3} root.left = &tree.treenode {} root.right = &tree.TreeNode{5, nil, nil} root.Left.Left = new(tree.TreeNode) root.Right.Right = tree.NewTreeNode(4) root.Traveres() var node *tree.TreeNode node.Traveres() treeNode : = myTreeNode{& root} treeNode.postorder() }Copy the code

The call is simple: root passes in the address and calls the method

 

  1. An alias is defined to implement calls to external or system constructs

Now let’s define an alias for the slice

package main import "fmt" type Queue []int func(q *Queue) add(v int){ *q = append(*q, v) } func(q *Queue) pop() int{ tail := (*q)[len(*q)-1] *q = (*q)[:len(*q)-1] return tail } func(q *Queue) isEmpty() bool  { return len(*q) == 0 } func main() { q := Queue{1} q.add(2) q.add(3) fmt.Println(q.pop()) fmt.Println(q.pop()) fmt.Println(q.isEmpty()) fmt.Println(q.pop()) fmt.Println(q.isEmpty()) }Copy the code

Step 1: Define an alias for the slice

type Queue []int
Copy the code

Then operate on the slice and add an element

func(q *Queue) add(v int){
    *q = append(*q, v)
}
Copy the code

Note here: in the add method. We said the receiver is written like this, but in this method, *q modifies the address. So after add, it’s not the same address anymore.

It’s not going to be the same address

Func main () {q: Queue = {1} FMT) Printf (" address: 0 x % x \ n ", & q [0]) q.a dd FMT. (2) Printf (" address: 0x%x \n", &q[1]) q.add(3) fmt.Println(q.pop()) fmt.Println(q.pop()) fmt.Println(q.isEmpty()) fmt.Println(q.pop()) fmt.Println(q.isEmpty()) }Copy the code

Address: 0xC000096008 Address: 0xC000096028 3 2 False 1 TrueCopy the code

The two printed addresses are different. Which means his address has changed

 

5. Definition of package name, each folder can only have one main

Let’s use the system package as an example

 

So, when we define files, we define a main function under each folder