channel
channel的引出
单纯的将函数并发执行是没有意义的,函数与函数之间必须能够交换数据才能体现并发执行函数的意义。虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题,为了保证数据的正确性,必须使用互斥量对内存进行加锁,这种做法又肯定造成了性能问题。
单纯的将函数并发执行是没有意义的,函数与函数之间必须能够交换数据才能体现并发执行函数的意义。虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题,为了保证数据的正确性,必须使用互斥量对内存进行加锁,这种做法又肯定造成了性能问题。
先看官方Doc中Rob Pike给出的关于反射的定义:
1 | 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)是调用方和实现方均需要遵守的一种约束,大家按照统一的方法命名、参数类型和数量来协调逻辑处理的过程。实际上,接口就是一组不需实现的方法声明,不能包含任何变量。到某个自定义类型要使用的时候,在根据具体情况把这些方法写出来(实现)。
反射是指在程序运行期对程序本身进行访问和修改的能力。即可以在运行时动态获取变量的各种信息,比如变量的类型(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
29package 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}
}
在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等) ,为了在函数执行完 毕后,及时的释放资源,Go设计者提供了defer
(延时机制): 1
2
3
4
5
6func main() {
//当执行到defer语句时,暂不执行,会将defer后的语句压入到独立的栈中,当函数执行完毕后,再从该栈按照先入后出的方式出栈执行
defer fmt.Println("defer1...")
defer fmt.Println("defer2...")
fmt.Println("main...")
}