# Go语言的面向对象

* Go语言只支持封装，不支持继承和多态
* 没有Class，只有Struct，也没有构造函数。

假设有一个结构体。

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

下面的类似构造函数，但是返回的是一个私有变量的地址给外面用，如果是其他语言，如何函数结束之后，私有变量也无法使用，导致程序报错。但是在go语言中下面这样写是没有问题的。同时，我们也不需要担心堆和栈的问题，这些垃圾回收机制都由go内部处理。

> 1. 栈区(stack)--由编译器自动分配和释放，存放函数的参数值，局部变量的值等。其操作方式类似于数据结构中的栈。
> 2. 堆区(heap)--一般由程序员分配和释放，若程序员不释放，程序结束时可能由OS回收，注意它与数据结构中的堆是两回事，分配方式倒是类似于链表。

```go
func CreateNode(value int) *Node {
	return &Node{Value: value}
}
```

## 为结构体定义方法

### **值接受者和指针接受者**

* 值接受者会拷贝一份给函数
* 指针接受者会直接把指针地址里的值给函数
* **值接受者**是GO语言特有
* 值/指针接受者均可接受值/指针

考虑

* 结构过大也要考虑使用指针接受者
* 所以只有使用指针才可以改变结构体内容！

**nil指针也可以调用指针**

```go
func (node Node) Print() {
	fmt.Print(node.Value, " ")
}
//nil指针也可以调用指针
func (node *Node) SetValue(value int) {
	if node == nil {
		fmt.Println("Setting Value to nil " +
			"node. Ignored.")
		return
	}
```

## 封装

* 名字一般使用CamelCase
* 首字母大写：public
* 首字母小写：private

### 包

* 每个目录一个包
* main包包含可执行的入口
* 为结构定义的方法必须放在同一个包
* 可以是不同文件

## 扩展

* Go语言里没有继承

如果要扩充类型可以：

* 定义别名
* 使用组合

别名

```go
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()
}
```

组合

```go
// 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
}

```
