channel

channel的引出

单纯的将函数并发执行是没有意义的,函数与函数之间必须能够交换数据才能体现并发执行函数的意义。虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题,为了保证数据的正确性,必须使用互斥量对内存进行加锁,这种做法又肯定造成了性能问题。


Go语言反射

引入

先看官方Doc中Rob Pike给出的关于反射的定义:

1
2
3
Reflection in computing is the ability of a program to examine its own structure, particularly through types; it’s a form of metaprogramming. It’s also a great source of confusion.
(在计算机领域,反射是一种让程序——主要是通过类型——理解其自身结构的一种能力。它是元编程的组成之一,同时它也是一大引人困惑的难题。)


接口 interface

接口定义

接口(interface)是调用方和实现方均需要遵守的一种约束,大家按照统一的方法命名、参数类型和数量来协调逻辑处理的过程。实际上,接口就是一组不需实现的方法声明,不能包含任何变量。到某个自定义类型要使用的时候,在根据具体情况把这些方法写出来(实现)。


反射简介

反射是指在程序运行期对程序本身进行访问和修改的能力。即可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind),如果是结构体变量,还可以获取到结构体本身的信息(字段与方法),通过反射,还可以修改变量的值,可以调用关联的方法。


方法与函数的混合使用

Go语言可以将类型的方法与普通函数作为一个概念,从而简化方法和函数混合作为回调类型时的复杂性。该特性与C#中的delegate类似,调用者无须关心谁来支持调用,系统会自动处理是否调用普通函数还是类型方法。


面向对象三大特性

封装

封装就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只有通过被授权的操作(方法),才能对字段进行操作。


面向对象初识

模拟构造函数

Go和传统的面向对象语言如Java有着很大区别。结构体没有构造函数初始化功能,可以通过以下方式模拟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"fmt"
)

type Person struct {
Name string
Age int
}

func NewPersonByName(name string) *Person {
return &Person{
Name: name,
}
}

func NewPersonByAge(age int) *Person {
return &Person{
Age: age,
}
}

func main() {

p := NewPersonByName("zs")
fmt.Println(p) // {zs 0}

}

函数

函数声明

函数声明格式

1
2
3
4
func 函数名字 (参数列表) (返回值列表){
// 函数体
return 返回值列表
}

defer延迟执行

defer延迟执行修饰符

在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等) ,为了在函数执行完 毕后,及时的释放资源,Go设计者提供了defer(延时机制):

1
2
3
4
5
6
func main() {
//当执行到defer语句时,暂不执行,会将defer后的语句压入到独立的栈中,当函数执行完毕后,再从该栈按照先入后出的方式出栈执行
defer fmt.Println("defer1...")
defer fmt.Println("defer2...")
fmt.Println("main...")
}

package与import

在实际的开发中,我们往往需要在不同的文件中,去调用其它文件的定义的函数,比如 main.go 中,需要使用"fmt"包中的Println()函数:

1
2
package main
import "fmt"