Go面向对象篇

结构体、方法、扩展已有类型、GOPAT和以及目录结构

前言

Go语言不是纯面向对象的编程语言,Go的面向对象中,接口体替代了类。

Go没提供类class,其提供struct结构体,method方法可在结构体上添加,提供捆绑数据和方法的行为与类类似。

Go不支持构造函数,提供NewT(parameters)函数初始化类型T和所需的值,若包只定义一个类型命名为 New(parameters) 

组成Composition替代继承Inheritance,通过嵌入结构体实现(将一个struct类型嵌入到另一个结构中实现)

Go利用接口帮助实现多态性,因为Go中接口可隐式实现,若类型为接口声明中所有方法提供了定义,则实现了一个接口。

结构体

特点:只支持封装、不支持继承和多态(其余用面向接口编程实现) 故Go无class只有struct

定义

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}

使用: variable_name := structure_variable_type {value1, value2...valuen} 

初始化

 P := person{"Tom", 25}  按照顺序提供初始值

 P := person{age:24, name:"Tom"} 通过field:value方式初始化

 p := new(person)然后初始化p.age=24 new方式如果未设置初始值会赋予类型的默认初始值

访问:

通过点.操作符用于访问结构的各个字段。例子: Book1.title = "Go 语言" 

注意:

type Books struct {
}

func (s Books) String() string {
    return "data"
}
func main() {
    fmt.Printf("%v
", Books{})
}

结构体指针

指针指向一个结构体 也可以创建指向结构的指针。

结构体指针: var struct_pointer *Books 以此定义的指针变量可以存储结构体变量的地址。

查看结构体变量地址,可以将 & 符号放置于结构体变量前,例子: struct_pointer = &Book1; 

使用结构体指针访问结构体成员,使用.操作符: struct_pointer.title; 

结构体匿名字段

匿名字段:用字段来创建数据结构,这些字段只包含一个没有字段名的类型,称为匿名字段。

例子:

type Human struct {
    name string
    age int
    weight int
}
type Student struct {
    Human // 匿名字段,那么默认Student就包含了Human的所有字段
    speciality string
}
使用:
 mark := Student{Human{"Mark", 25, 120}, "Computer Science"}

方法

Go中同时有函数和方法,一个方法就是一个包含了接收者的函数,接收者可以是命名类型或者结构体类型的一个值或者一个指针,所有给定类型的方法属于该类型的方法集。

概念:只是一个函数,带有一个特殊接收器类型,接收器可以是struct类型或非struct类型,接收方可在内部访问。

语法

定义 

func (t Type) methodName(parameter list) {
}

例子

type Employee struct {
    name     string
    salary   int
    currency string
}

/*
 displaySalary() method has Employee as the receiver type
*/
func (e Employee) displaySalary() {
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
使用
 emp1.displaySalary() //Calling displaySalary() method of Employee type

特点

可定义相同的方法名,但接收者不同,方法就不同。

方法里可以访问接受者的字段。调用方法通过.访问,类似struct里访问字段一样。

存在意义

Go不支持类,不是存粹面向对象语言,类型的方法其实就是一种实现类似于类的行为的方法。

之所以有函数还需要方法,有一点则是相同名称的方法可在不同类型上定义,但具有相同名称的函数是不允许的。

方法可以继承和重写的,存在继承关系时,按照就近原则,进行调用。

本节重点

1)GO安装路径为为GOROOT  如何设置GOPATH  在PATH中添加GOPATH/bin目录

2)GOPATH目录(这里为/home/admin/go)下有三个文件夹bin  pkg  src但是一般是src是我自己创建,其余不是

如果非要创建这几个文件夹,比如创建了pkg就涉及到IDEA中go run 时候可能go install会被拒绝写入由我自己创建的pkg

3)IDEA工程保存路径(这里为 /home/admin/go/src/learngo)我自己注意:最好下次保存为 /home/admin/go/src/ycx/learngo

4)无法直接获取golang的包因此使用工作gopm(获取时候采用go get命令 但是一定要记得安装了git)

5)IDEA中运行某个程序时候如果报错(请自行查看是否到该包目录下go install了,如果没有会报错关于linux_amd64的)

6)GPATH下:go build来编译  go install产生pkg文件和可执行文件  go run直接编译运行

 GOPATH

[admin@localhost ~]$ cd /opt/go
[admin@localhost go]$ pwd
/opt/go
[admin@localhost go]$ echo $GOPATH
/home/admin/go
[admin@localhost go]$ gedit /etc/profile

GOPATH

重点关注:GOPATH以及设置PATH关于GOPATH的

go get

在配置的GOPATH目录下执行命令:go get -v github.com/gpmgo/gopm 

注意1:如果不能执行请查看自己是否安装了git

注意:如果出现错误提示如下(请将src目录下的github.com文件夹删除使用命令为:rm -rf  文件夹名字

 安装gopm完毕查看目录下一些文件:(此时说明gopm安装完毕,可以通过查看gopm的help来运行了)

[root@localhost go]# gopm help

[root@localhost go]# gopm help get

使用gopm

使用一下命令第一次不会出现一下问题

 

打开IDEA可以查看GOPATH已经出现:

运行go build命令来build需要的goimports将其装在bin目录下面去

注:这里它会做两件事情(第一件:将IDEA里的import两个空行 第二件:是在golang.org 的x目录下多很多东西)

使用示例

我们可以来使用一下:使用intsets.Sparse{}   下面是tree的总代码

注意:运行程序treeentry.go运行程序出错:(这是由于自己认为创建了pkg,如果不是则不会报这个错误)

解决办法:

 tree

目录结构:

package main

import (
    "fmt"

    "learngo/tree"

    "golang.org/x/tools/container/intsets"
)

type myTreeNode struct {
    node *tree.Node
}

func (myNode *myTreeNode) postOrder() {
    if myNode == nil || myNode.node == nil {
        return
    }

    left := myTreeNode{myNode.node.Left}
    right := myTreeNode{myNode.node.Right}

    left.postOrder()
    right.postOrder()
    myNode.node.Print()
}

func testSparse() {
    s := intsets.Sparse{}

    s.Insert(1)
    s.Insert(1000)
    s.Insert(1000000)
    fmt.Println(s.Has(1000))
    fmt.Println(s.Has(10000000))
}

func main() {
    var root tree.Node

    root = tree.Node{Value: 3}
    root.Left = &tree.Node{}
    root.Right = &tree.Node{5, nil, nil}
    root.Right.Left = new(tree.Node)
    root.Left.Right = tree.CreateNode(2)
    root.Right.Left.SetValue(4)

    fmt.Print("In-order traversal: ")
    root.Traverse()

    fmt.Print("My own post-order traversal: ")
    myRoot := myTreeNode{&root}
    myRoot.postOrder()
    fmt.Println()

    nodeCount := 0
    root.TraverseFunc(func(node *tree.Node) {
        nodeCount++
    })
    fmt.Println("Node count:", nodeCount)

    c := root.TraverseWithChannel()
    maxNodeValue := 0
    for node := range c {
        if node.Value > maxNodeValue {
            maxNodeValue = node.Value
        }
    }
    fmt.Println("Max node value:", maxNodeValue)

    testSparse()
}
entry.go
package tree

import "fmt"

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

func (node Node) Print() {
    fmt.Print(node.Value, " ")
}

func (node *Node) SetValue(value int) {
    if node == nil {
        fmt.Println("Setting Value to nil " +
            "node. Ignored.")
        return
    }
    node.Value = value
}

func CreateNode(value int) *Node {
    return &Node{Value: value}
}
node.go
package tree

import "fmt"

func (node *Node) Traverse() {
    node.TraverseFunc(func(n *Node) {
        n.Print()
    })
    fmt.Println()
}

func (node *Node) TraverseFunc(f func(*Node)) {
    if node == nil {
        return
    }

    node.Left.TraverseFunc(f)
    f(node)
    node.Right.TraverseFunc(f)
}

func (node *Node) TraverseWithChannel() chan *Node {
    out := make(chan *Node)
    go func() {
        node.TraverseFunc(func(node *Node) {
            out <- node
        })
        close(out)
    }()
    return out
}
traversal.go

输出是:

In-order traversal: 0 2 3 4 5 
My own post-order traversal: 2 0 4 5 3 
Node count: 5
Max node value: 5
true
false

Process finished with exit code 0

 queue

先做准备工作

代码结构如下:

package main

import (
    "fmt"
    "learngo/queue"
)

func main() {
    q := queue.Queue{1}

    q.Push(2)
    q.Push(3)
    fmt.Println(q.Pop())
    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())
    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())
}
main.go
package queue

// A FIFO queue.
type Queue []int

// Pushes the element into the queue.
//         e.g. q.Push(123)
func (q *Queue) Push(v int) {
    *q = append(*q, v)
}

// Pops element from head.
func (q *Queue) Pop() int {
    head := (*q)[0]
    *q = (*q)[1:]
    return head
}

// Returns if the queue is empty or not.
func (q *Queue) IsEmpty() bool {
    return len(*q) == 0
}
queue.go

 输出是:

1
2
false
3
true

Process finished with exit code 0
package queue

import "fmt"

func ExampleQueue_Pop() {
    q := Queue{1}
    q.Push(2)
    q.Push(3)
    fmt.Println(q.Pop())
    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())

    fmt.Println(q.Pop())
    fmt.Println(q.IsEmpty())

    // Output:
    // 1
    // 2
    // false
    // 3
    // true
}
queue_test.go

 运行是:

 

原文地址:https://www.cnblogs.com/ycx95/p/9361122.html