话接上文

如果各位童鞋想要获得下面的源码,请搜索gzh:隔壁王小猿,关注后回复“Go语言基本语法”即可获得

面向对象

结构体与方法

  • Go语言仅支持封装,不支持多态和继承
  • Go语言没有class,只有struct

结构体的创建

  • 不论地址还是结构本身,一律使用 . 来访问
  • Root:=treeNode{value:3}
  • Root.left=&treeNode{}
  • Root.right=&treeNode{5,nil,nil}
  • Root.right.left=new(treeNode)
  • 示例
        var root treeNode
	fmt.Println(root)
	root = treeNode{
		value: 3,
		right: &treeNode{},
		left:  &treeNode{}}
	fmt.Println(root)
	root.left = &treeNode{5, nil, nil}
	fmt.Println(root)
	root.right.left = &treeNode{}
	fmt.Println(root)
	fmt.Println(root.left)
	fmt.Println(root.right)
	nodes := []treeNode{
		{value: 3},
		{right: &treeNode{}},
		{value: 5, left: &treeNode{5, nil, nil}},
		{3, nil, new(treeNode)}}
	fmt.Println(nodes)

输出

{0 <nil> <nil>}
{3 0xc000004500 0xc0000044e0}
{3 0xc000004540 0xc0000044e0}
{3 0xc000004540 0xc0000044e0}
&{5 <nil> <nil>}
&{0 0xc000004580 <nil>}
[{3 <nil> <nil>} {0 <nil> 0xc000004620} {5 0xc000004640 <nil>} {3 <nil> 0xc000004600}]

工厂函数-模拟构造函数

  • 返回的局部地址
func createNode(value int) *treeNode {
 return &treeNode{value: value}
}

给结构体定义方法

  • 显示定义和命名方法的接收者
  • 使用指针作为方法接收者
    • 只有使用指针才可以改变结构内容
    • nil指针也可以调用方法
  • 示例
type treeNode struct {
	value       int
	left, right *treeNode
}
func (node treeNode) printValue() {
	fmt.Println(node.value)
}
//值传递  不会更改值
func (node treeNode) setValue(value int) {
	node.value = value
}
//指针传递  会更改值
func (node *treeNode) setValuePointer(value int) {
	node.value = value;
}
func createNode(value int) *treeNode {
	return &treeNode{value: value}
}

	var root treeNode
	root.value = 3
	root.left = &treeNode{}
	root.right = &treeNode{5, nil, nil}
	root.right.left = new(treeNode)
	root.left.right = createNode(2)

	fmt.Println("root value:")
	root.printValue()

	root.right.left.setValue(4)
	fmt.Println("root.right.left  value:")
	root.right.left.printValue()

	root.right.left.setValuePointer(4)
	fmt.Println("root.right.left  value:")
	root.right.left.printValue()

输出

root value:
3
root.right.left  value:
0
root.right.left  value:
4

值接收者vs指针接收者

  • 要改变内容必须使用指针接收者
  • 结构过大也考虑使用指针接收者
  • 一致性,如果有指针接收者,最好都是指针接收者
  • 值接收者是go语言特有的
  • 值、指针接收者均可接收值、指针

包&封装

  • Go语言通过名字来区分public和private
  • 名字一般使用CamelCase
  • 首字母大写 public
  • 首字母小写 private

  • 每个目录一个包
  • mian包包含可执行入口
  • main函数所在目录只能有一个main包
  • 为结构定义的方法必须在同一个包内,可以是不同文件

包-扩充系统类型或者别人的类型

  • 定义别名
    • 使用别名myTreeNode封装TreeNode
type myTreeNode struct {
	node *tree.TreeNode
}

//后续遍历
func (myNode *myTreeNode) postOrder() {
	if myNode == nil || myNode.node == nil {
		return
	}

	//指针不能作为接收者, 需要需要定义变量来接送地址
	//myTreeNode{myNode.node.Left}.postOrder();

	left := myTreeNode{myNode.node.Left}
	left.postOrder()
	right := myTreeNode{myNode.node.Right}
	right.postOrder()
	myNode.node.PrintValue()
}

	var root tree.TreeNode
	root.Value = 3
	root.Left = &tree.TreeNode{}
	root.Right = &tree.TreeNode{5, nil, nil}
	root.Right.Left = new(tree.TreeNode)
	root.Left.Right = tree.CreateNode(2)

	//root.Traverse()
	pRoot := myTreeNode{&root}
	pRoot.postOrder()

输出

2
0
0
5
3
  • 使用组合
    • 使用int组合实现queue
package queue
type Queue []int
func (q *Queue) Push(v int) {
	*q = append(*q, v)
}
func (q *Queue) Pop() int {
	if q == nil {
		panic("error.")
	}
	head := (*q)[0]
	*q = (*q)[1:]
	return head
}
func IsEmpty(q *Queue) bool {
	return len(*q) == 0
}

GOPATH环境变量

  • 默认~/go(linux,unix), %USERPROFILE%\go(windows)
  • 官方推荐:所有项目和第三方库都放在一个GOPATH下
  • 也可以将每个项目放在不同的GOPATH
  • Go get 命令获取包,也可以用gopm获取
  • GOPATH下目录结构
    • Src
      • Git rep1
      • Git rep2
    • Pkg
      • Git rep1
      • Git rep2
    • Bin
      • 可执行文件

面向接口

duck typing

先问一个比较考三观的问题:图片中的大黄鸭,它是不是一只鸭子呢?

Duck Typing 的原话是,走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么它就是一只鸭子。

这个原话是可以灵活理解的,就看我们怎么定义鸭子的行为,我们可以说,能浮在水上游的,黄色的,可爱的就是鸭子,那么,图片中的大黄鸭,它就是一只鸭子!

这就是所谓的 Duck Typing,它只关心事物的外部行为而非内部结构。它并不关心你这只鸭子是长肉的还是充气的。

Python中duck typing

 Def download(retriever):
      Return retriever.get(“www.baidu.com”)
  • 运行时才知道传入的retriever有没有get
  • 需要注释来说明接口

C++中的duck typing

	Template<class R>
	Def download(const R& retriever){
		Return retriever.get(“www.baidu.com”);
}
  • 编译时才知道传入的retriever有没有get
  • 需要注释来说明接口

Java中类似代码

<R extends Retriever >
String download(R r){
	Return r.get(“www.baidu.com”);
}
  • 传入的参数必须实现Retriever接口,编写代码过程中就知道必须包含get方法
  • 不是duck typing

Go语言中的duck typing

  • 同时可以实现多个接口
  • 具有python和c++ 的duck typing的灵活性
  • 又具有Java的类型检查
  • 类似duck typing

接口

  • Go语言接口是由使用者定义的

接口的定义

type Retriever interface {
 Get(url string) string
}

接口的实现

  • 接口的实现是隐式的
type Retriever struct {
	Context string
}

func (r Retriever) Get(url string) string {
	return r.Context
}

接口变量里面有什么

  • 接口变量自带指针
  • 接口变量同样采用值传递,几乎不需要使用接口的指针
  • 指针接收者实现只能以指针方式使用,值接收者都可

查看接口变量

  • 表示任何类型:interface{}
  • Type Assertion
  • Type Switch

接口组合

type getItf interface {
	Get(url string) string
}

type postItf interface {
	Post(url string, from map[string]string) string
}
type getAndPostI interface {
	getItf
	postItf
}

面向函数

闭包


func adder() func(int) int {
	sum := 0
	return func(v int) int {
		sum += v
		return sum
	}
}

func main() {
	a := adder();
	for i := 0; i < 10; i++ {
		fmt.Println(a(i))
	}
}

adder函数返回的是一个闭包,不仅仅是一个函数,还包含sum的引用等