面向对象
仅支持封装,不支持继承和多态,没有像python的mro操作;继承和多态转化为面向接口编程
go语言没有class 只有struct
struct 结构体
不论地址还是结构本身,一律使用.来访问成员没有构造函数,可以使用工厂函数,注意返回的是局部变量的地址,go是允许的我们不需要知道go的变量是放在堆或者栈上的,因为go语言内部的垃圾回收机制go语言函数在运行结束之后,其中的局部变量不一定会马上销毁
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func createNode(value int) *treeNode { // 工厂函数
return &treeNode{value: value} //这里返回的是一个局部变量的地址,在go里面是允许的不会报错
}
func main() {
var root treeNode
fmt.Println(root)
root = treeNode{value: 3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil}
root.right.left = new(treeNode)
root.left.right = createNode(2)
nodes := []treeNode{
{value: 3},
{},
{6, nil, &root},
}
fmt.Println(nodes)
}
给结构体定义方法
Func (node TreeNode) print(){ fmt.print(node.value)}
显示定义和命名方法接收者
只有使用指针才可以改变结构内容,传入指针
nil指针也可以调用方法,可以使用,安全的
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func (node treeNode) print() {
fmt.Print(node.value, " ")
}
func (node *treeNode) setValue(value int) { //通过传递指针,可以修改外面的变量
if node == nil {
fmt.Println("setting value to nil node. Ignored.")
return
}
node.value = value
}
func createNode(value int) *treeNode { // 工厂函数
return &treeNode{value: value} //这里返回的是一个局部变量的地址,在go里面是允许的不会报错
}
func main() {
var root treeNode
fmt.Println(root)
root = treeNode{value: 3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil}
root.right.left = new(treeNode)
root.left.right = createNode(2)
root.print()
root.right.left.setValue(4)
root.right.left.print()
root.print() // 值接受者,或拷贝一份给函数
root.setValue(100) // 给地址
pRoot := &root
pRoot.print()
pRoot.setValue(200)
pRoot.print()
var rRoot *treeNode
rRoot.setValue(200)
rRoot = &root
rRoot.setValue(300)
rRoot.print()
}
遍历方法
func (node *treeNode) traverse() {
if node == nil {
return
}
node.left.traverse()
node.print()
node.right.traverse()
}
值接收者vs指针接收者
要改变内容需要使用指针接收者结构过大也需要考虑使用指针接收者一致性:如有指针接收者,最好都是指针接收者值接收者是go语言特有的,指针接收者其他都有值/指针接收者均可以接收值或者指针
包和封装
名字使用驼峰命名法首字母大写:pulic首字母小写:privatepublic和private针对包来说的,每个目录只有一个包(一个目录中所有文件的包名称相同)main包包含可执行入口,main包对应mian函数为结构定的方法必须包含在同一个包中,可以是不同的文件包名称和目录名称不一定相同,但是一个目录只能有一个包名称main是入口包,独立于其他功能包goland 定义的gopath需要包含src文件夹,下面的子目录是所有的包
扩展已有类型
扩充系统类型或别人的类型
定义别名使用组合
// 组合的方式
package main
import (
"fmt"
"learngo/tree"
)
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 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)
root.Traverse()
fmt.Println()
myRoot := myTreeNode{&root}
myRoot.postOrder()
fmt.Println()
}
// 使用别名
package queue
type Queue []int //别名
func (q *Queue) Push(v int) {
*q = append(*q, v) // 改变q指向的slice改变了
}
func (q *Queue) Pop() int {
head := (*q)[0]
*q = (*q)[1:]
return head
}
func (q *Queue) IsEmpty() bool {
return len(*q) == 0
}
使用内嵌的方式扩展已有类型
Embedding方式,类似使用组合的方式,可以省下许多代码,但是这种方法是熟练的人看得懂
package main
import (
"fmt"
"learngo/tree"
)
type myTreeNode struct {
*tree.Node // Embedding内嵌,语法糖,省略代码
}
func (myNode *myTreeNode) postOrder() {
if myNode == nil || myNode.Node == nil {
return
}
left := myTreeNode{myNode.Left}
right := myTreeNode{myNode.Right}
left.postOrder()
right.postOrder()
myNode.Print()
}
func (myNode *myTreeNode) Traverse() {
fmt.Printf("this method is shadowed.")
}
func main() {
root := myTreeNode{&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)
root.Traverse() // 本身的traverse
root.Node.Traverse() // 肚子中node的traverse
fmt.Println()
root.postOrder()
fmt.Println()
//var baseRoot *tree.Node
//baseRoot:=$root 会报错,和其他语言中的继承不相同
}
Go的依赖管理
依赖管理
编译程序需要的三方库依赖管理的三个阶段:GOPATH,GOVENDOR,go mod
Gopath/Govendor
默认在~/go(unix, linux)所有的项目都需要放在gopath下面,造成gopath非常的大,会导致gopath非常的大,所有的import都在下面找历史:google将20亿行代码,9百万个文件放在一个repo里gopath下面必须要有个目录为src,source,存放项目的包代码一个目录下面可以创建一个vendor目录,放置本项目需要特定的第三方库大量的第三方依赖管理工具:glide,dep,go dep,…
gopath管理
go env -w 目录 # 将整个系统目录转化为这个
export GOPATH = 具体目录 在gopath下面创建src 必须有一个这个目录,在这个下面放各种的代码,项目目录
采用gopaht的方式而不用gomoduel: GO111MODULE="off"
第三方库的查找和安装:
1.建立的每个目录可以有一个project gopath, 也可以公用一个global gopath
2.第三方库的查找:goroot的src下面,gopath下面的src下面查找
3.每个项目目录下面创建一个vendor目录
引入包的语言: go get
God mod
使用gomod进行文件管理,下载的第三方包在制定的gopath下面的pkg里面,但是有go.mod和其下面的go.sum文件进行管理;
go get -u go.uber.org/zap@1.11 #获取指定版本的库, 在需要使用的目录下面,下载的包在上级目录的pkg中
go mod tidy # 清洁go.sum下面的多余的包
go get -u go.uber.org/zap #升级到最新的版本
go mod init name #创建gomod文件,如果有用其他管理工具,直接用这个就可以,不用下面那个了
go build ./... # build当前目录和所有子目录文件,加载所有需要的包
go命令统一管理,用户不需要关心目录结构初始化:go mod init 项目名称增加依赖:go get 类似pip更新依赖 go get [@v…]清洁go mod文件: go mod tidy;查看go对应包直接在github中项目迁移go mod: go mod init, go build ./…
目录整理
一个目录只有一个main文件,意思是只有一个main包,如果多个main文件,需要放到不同的子目录下
go build ./... # 编译所有目录和子目录文件
go install ./... # 在src同级目录bin下查看编译文件
推荐阅读
发表评论