opened
SilenceHVK
username_0
## Go 语言的面向对象

&ensp;&ensp;Go 语言的面向对象非常简单，**仅支持封装，不支持继承和多态。继承和多态是在接口中实现的。**

&ensp;&ensp;因此 Go 语言中没有 ```class```，而是通过 ```struct（结构体）``` 对相同类型或不同类型的数据进行封装。

- 通过 ```type <structName> struct {}``` 格式定义结构体；

```golang
type User struct {
	Name     string
	Age      int
	IsActive bool
}
```

- 定义后的结构体就可以作为类型使用；

```golang
hvkcoder := User{Name: "hvkcoder", Age: 18, IsActive: true}
fmt.Println(hvkcoder) // {hvkcoder 18 true}
```
或
```golang
hvkcoder := User{"hvkcoder", 18, true}
fmt.Println(hvkcoder) // {hvkcoder 18 true}
```

- 通过 ```结构体.成员名称``` 访问结构体中的对象；

```golang
fmt.Println(hvkcoder.Name) // hvkcoder
```

- 结构体是值类型，因此支持比较运算符的使用；

```golang
hvkcoder := User{Name: "hvkcoder", Age: 18, IsActive: true}
jason := User{Name: "jason", Age: 20, IsActive: true}
    
fmt.Println(hvkcoder == jason) // false
```


- 由于结构体是值类型，因此需要向函数传递 **结构体指针**，才能去改变结构体中的值；

```go
package main

import "fmt"

type User struct {
	Name     string
	Age      int
	IsActive bool
}

func setName(user *User,name string){
	user.Name = name
}

func main(){
	test := User{Name: "jason", Age: 18, IsActive: true}
	fmt.Println(test.Name) // jason
	setName(&test, "hvkcoder")
	fmt.Println(test.Name) // hvkcoder
}
```

- 结构体也可以嵌套

```go
package main

import "fmt"

type Address struct {
	city, town string
}

type User struct {
	Name     string
	Age      int
	IsActive bool
	UAddress Address
}

func main() {
	user := User{
		Name:     "hvkcoder",
		Age:      18,
		IsActive: false,
		UAddress: Address{"北京", "海淀"},
	}

	fmt.Println(user) // {hvkcoder 18 false {北京 海淀}}
}
```

### Go 语言中的方法

&ensp;&ensp;Go 语言中的方法从某种意义上来说就是函数的语法糖，```receiver``` 作为方法的第一个强制类型参数传入，这也就是 ```Method Value``` 与 ```Method Expression``` 的区别。

```go
package main

import "fmt"

type Student struct {
	Name string
}

// receiver 定义结构方法
func (student Student) SayHi(){
	fmt.Println("Hello! My name's", student.Name)
}

func main(){

	student := Student{"hvkcoder"}

	// 使用 Method Value 方式调用方法
	student.SayHi() // Hello! My name's hvkcoder
	
	// 使用 Method Expression 方法调用方法
	(Student).SayHi(student) // Hello! My name's hvkcoder
}
```

- 既然说了 Go 语言中的方法实际上就是函数的语法糖，因此想通过方法去改变结构体的值，仍然需要传递指针；

```go
package main

import "fmt"

type User struct {
	Name     string
	Age      int
	IsActive bool
}

func (user *User) setName(name string){
	user.Name = name
}

func main(){
	test := User{Name: "jason", Age: 18, IsActive: true}
	fmt.Println(test.Name) // jason
	
	test.setName("hvkcoder")
	fmt.Println(test.Name) // hvkcoder
}
```

- Go 中不存在方法重载；
- 如果外部结构和内嵌结构存在同名方法，则优先调用外部结构的方法；

### 使用 Go 实现一个二叉排序树

```go
package algorithm

import "fmt"

// 二叉树节点结构
type Node struct {
	Value       int
	Left, Right *Node
}

// 添加二叉排序树节点
func (node *Node) Insert(newNode *Node) {

	// 根据二叉排序树的特点，左子树的所有节点均小于根节点，右子树的所有节点均大于根节点
	if node.Value > newNode.Value {
		// 判断左子树是否有值
		if node.Left == nil {
			node.Left = newNode
		} else {
			node.Left.Insert(newNode)
		}
	} else {
		// 判断右子树是否有值
		if node.Right == nil {
			node.Right = newNode
		} else {
			node.Right.Insert(newNode)
		}
	}
}

// 前序遍历二叉排序树节点
func (node *Node) PreorderTraversal(){
	if node != nil{
		fmt.Printf("%d ", node.Value)
		node.Left.PreorderTraversal()
		node.Right.PreorderTraversal()
	}
}

// 中序遍历二叉排序树节点
func (node *Node) InorderTraversal(){
	if node != nil{
		node.Left.InorderTraversal()
		fmt.Printf("%d ", node.Value)
		node.Right.InorderTraversal()
	}
}

// 后序遍历二叉排序树节点
func (node *Node) PostorderTraversal(){
	if node != nil{
		node.Left.PostorderTraversal()
		node.Right.PostorderTraversal()
		fmt.Printf("%d ", node.Value)
	}
}


// 创建二叉排序树
func NewBinarySortTree(treeNode []int) *Node{
	var root *Node
	if len(treeNode) > 0 {
		for _,value := range treeNode {
			node := Node{Value:value}
			if root == nil {
				root = &node
			}else {
				root.Insert(&node)
			}
		}
	}
	return root
}
```

```go
package main

import (
	"./algorithm"
	"fmt"
)

func main() {
	// 声明一个二叉树节点 Slice
	treeNode := []int{8, 3, 10, 1, 4, 13, 16, 14}
	// 创建二叉排序树
	binarySortTree := algorithm.NewBinarySortTree(treeNode)
	// 使用 前序方式遍历 二叉树
	binarySortTree.PreorderTraversal() // 8 3 1 4 10 13 16 14
	fmt.Println()

	// 使用 中序方式遍历 二叉树
	binarySortTree.InorderTraversal() // 1 3 4 8 10 13 14 16
	fmt.Println()

	// 使用 后序方式遍历 二叉树
	binarySortTree.PostorderTraversal() // 1 4 3 14 16 13 10 8
}
```
【Golang 基础】Go 语言 面向对象
issue