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\n", 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() }
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} }
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 }
输出是:
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()) }
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 }
输出是:
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 }
运行是: