一、结构体
结构体是一个可以存储不同数据类型的数据类型,因为在声明完以后,它可以和数据类型一样使用, 也有指针、值等等
go 语言仅支持封装,不支持继承和多态
go 语言没有 class,只有 struct
声明和使用
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
}
func main() {
var human Human
human.Name = "lulu"
human.Age = 18
human.Sex = true
human.Hobby = []string{"踢球", "玩游戏"}
fmt.Println(human)
human2 := Human{
Name: "lulu",
Age: 18,
Sex: true,
Hobby: []string{"踢球", "玩游戏"},
}
fmt.Println(human2)
human3 := Human{"lulu", 18, true, []string{"踢球", "玩游戏"}}
fmt.Println(human3)
var human4 Human
fmt.Println(human4)
human5 := new(Human)
fmt.Println(human5)
}
访问参数
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
}
func main() {
var human Human
human.Name = "lulu"
human.Age = 18
human.Sex = true
human.Hobby = []string{"踢球", "玩游戏"}
fmt.Println(human.Name)
}
作为方法参数
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
}
func main() {
human := Human{
Name: "lulu",
Age: 18,
Sex: true,
Hobby: []string{"踢球", "玩游戏"},
}
humanFunc(human)
}
func humanFunc(hm Human) {
fmt.Println(hm)
}
结构体指针
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
}
func main() {
human := Human{
Name: "lulu",
Age: 18,
Sex: true,
Hobby: []string{"踢球", "玩游戏"},
}
fmt.Println(human.Age)
var humanP *Human
fmt.Println(humanP)
humanP = &human
fmt.Println(humanP)
humanP.Age = 20
fmt.Println(human.Age)
(*humanP).Age = 21
fmt.Println(human.Age)
}
结构体方法
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
}
func (hm *Human) play(name string) (res string) {
res = "他是国服鲁班"
fmt.Printf("%v玩%v很厉害", hm.Name, name)
return res
}
func main() {
human := Human{
Name: "lulu",
Age: 18,
Sex: true,
Hobby: []string{"踢球", "玩游戏"},
}
res := human.play("王者荣耀")
fmt.Println("\n", res)
}
结构体嵌套结构体
package main
import "fmt"
type Human struct {
Name string
Age int
Sex bool
Hobby []string
Address
Address2 Address
}
type Address struct {
City string
}
func main() {
human := Human{
Name: "lulu",
Age: 18,
Sex: true,
Hobby: []string{"踢球", "玩游戏"},
}
human.Address.City = "深圳"
human.Address2.City = "广州"
fmt.Println(human)
fmt.Println(human.City)
fmt.Println(human.Address2.City)
}
二叉树
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 (node *treeNode) traverse() {
if node == nil {
return
}
node.left.traverse()
node.print()
node.right.traverse()
}
func createTreeNode(value int) *treeNode {
return &treeNode{value: value}
}
func main() {
var root treeNode
root = treeNode{value: 3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil}
root.right.left = new(treeNode)
root.left.right = createTreeNode(2)
//遍历树
root.traverse()
fmt.Println()
//为结构定义方法
root.right.left.print()
root.right.left.setValue(4)
root.right.left.print()
fmt.Println()
root.print()
root.setValue(100)
root.print()
fmt.Println()
pRoot := &root
pRoot.print()
pRoot.setValue(200)
pRoot.print()
fmt.Println()
//nil 指针也可以调用方法!
var qRoot *treeNode
qRoot.setValue(200)
qRoot = &root
qRoot.setValue(300)
qRoot.print()
fmt.Println()
}
值接收者 vs 指针接收者
要改变内容必须使用指针接收者
结构过大也考虑使用指针接收者
一致性︰如有指针接收者,最好都是指针接收者
值接收者是 go 语言特有
值/指针接收者均可接收值/指针
二、包和封装
2.1、封装
名字一般使用 CamelCase
首字母大写:public
首字母小写:private
2.2、包
2.2.1、注意事项
每个目录一个包
main 包包含可执行入口
为结构定义的方法必须放在同一个包内
可以是不同文件
2.2.2、示例
文件目录
tree.go
package tree
import "fmt"
type Node struct {
Value int
Left, Right *Node
}
func CreateNode(value int) *Node {
return &Node{Value: value}
}
func (node *Node) SetValue(value int) {
if node == nil {
fmt.Println("Setting value to nil node. Ignored. ")
return
}
node.Value = value
}
func (node Node) Print() {
fmt.Print(node.Value, " ")
}
traverse.go
package tree
func (node *Node) Traverse( ) {
if node == nil{
return
}
node.Left.Traverse( )
node.Print( )
node.Right.Traverse( )
}
entry.go
package main
import (
"fmt"
"learn/tree"
)
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.SetValue(100)
root.Traverse()
fmt.Println()
}
执行
go run /mnt/go/src/learn/tree/entry/entry.go
执行结果
0 2 100 0 5
三、扩展已有类型
3.1、定义别名
entry.go
package main
import (
"fmt"
"learn/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.SetValue(100)
root.Traverse()
fmt.Println()
myRoot := myTreeNode{&root}
myRoot.postOrder()
fmt.Println()
}
3.2、使用组合
queue.go
package queue
type Queue []int
func (q *Queue) Push(v int) {
*q = append(*q, v)
}
func (q *Queue) Pop() int {
head := (*q)[0]
*q = (*q)[1:]
return head
}
func (q *Queue) IsEmpty() bool {
return len(*q) == 0
}
entry.go
package main
import (
"fmt"
"learn/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())
}
代码目录
运行结果
1
2
false
3
true
四、GOPATH以及目录结构
4.1、注意事项
默认在~/go(unix, linux),%USERPROFILE%\go (windows)
官方推荐∶所有项目和第三方库都放在同一个 GOPATH 下
也可以将每个项目放在不同的 GOPATH
获取 GOPATH 目录
echo $GOPATH
设置 GOPATH
vim /etc/profile
export GOROOT=/usr/local/go #设置为go安装的路径
export GOPATH=/mnt/go #go项目路径
export PATH=$PATH:$GOPATH/bin:$GOROOT/bin #以冒号分隔
source /etc/profile
GOPATH 下的目录结构
4.2、go get 获取第三方库
使用 gopm 来获取无法下载的包
go get -v github.com/gpmgo/gopm
执行后之后会在 GOPATH 目录生成如下文件
gopm 帮助
gopm help get
安装 goimports
gopm get -g -v -u golang.org/x/tools/cmd/goimports
go build来编译
go install 产生pkg 文件和可执行文件
cd /mnt/go/src/learn/tree
go intsall
go run 直接编译运行