go的阻塞,通信,锁,数据类型(interface),gmp的原理,slice的原理怎么扩容,map的原理,性能优化(pprof)
make和new的区别
golang的内存管理
函数传入结构体传值还是传指针 传指针可能会内存逃逸栈上逃逸到堆上
线程模型 goroutine原理
不一样的地方 go
语法
– 变量
– 选择 循环
– 指针,数组,容器
面向接口
– 结构体
– duck typeing
– 组合的思想
函数时编程
– 闭包
工程化
资源管理,错误处理
测试和文档
性能调优
并发编程
goroutine 和channel
理解调度器
多样的例题
2.1 变量定义
println 只能变量
printf 可以和百分号
a,b,i,s1,s2 := true, false, 3, “hello”, “world”
只能在函数内使用
2.2 内建变量类型
– bool,string
– (u)int,(u)int8,(u)int16,(u)int32,(u)int64,uintptr(根据操作系统来)
– byte, rune
– float32, float64, complex64, complex128(实部虚部128)
2.3 常量与枚举
const filename = "abc.txt"
const 数值可作为各种类型使用
const a, b = 3,4
var c int = int(math.Sqrt(a*a + b*b))
2.4 条件语句
if contents, err := ioutil.ReadFile(filename); err==nil{
fmt.Println(string(content))
} else {
fmt.Println("cannot print file contents:", err)
}
不需要break,可以直接switch多个条件
func eval(a, b int, op string) int {
var result int
switch op {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
panic("unsupported operator" + op)
}
return result
}
func grade(score int) string {
grade := ""
switch {
case score<60:
grade = "f"
case score<70:
grade = "b"
case score<100:
grade = "a"
default:
panic(fmt.Sprintf("wrong score %d", score))
}
return grade
}
panic: wrong score 100
goroutine 1 [running]:
main.grade(0x64, 0x4a1bc0, 0xc00006c058)
/mnt/d/go/spider/basic.go:29 +0x105
main.main()
/mnt/d/go/spider/basic.go:36 +0x2a
exit status 2
sum :=0
for i:=1; i<=100; i++{
sum += 1
}
2.6 函数
func eval(a, b int, op string) int {
switch op {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
panic("unsupported operator" + op)
}
}
func div(a, b int) (int, int) {
return a / b, a % b
}
func div(a, b int) (q, r int) {
return a / b, a % b
}
func (a int, b int) int {
return int(math.Pow(float64(a), float64(b)))
}
函数的参数也可以是函数
func apply(op func(int, int) int, a, b int) int {
fmt.Printf("Calling %s with %d, %d\n", runtime.FuncForPC(reflect.ValueOf(op).Pointer().Name(), a, b))
return op(a, b)
}
传入多个参数
func sum(values ...int) int {
sum := 0
for i range values {
sum += value[i]
}
return sum
}
2.7 指针
var a int =2
var pa *int = &a
*pa =3
fmt.Println(a)
go 只有值传递一种方式
var cache Cache
func swap(a, b int) {
b,a = a,b
}
3.1 数组,切片和容器
func main() {
var arr1 = [5]int
arr2 := [3]int{1,3,5}
arr3 := [...]int{2,4,6,8}
var grid [4][5]int
}
数组的遍历
sum :=0
for _,v := range numbers{
sum += v
}
意义明确,美观
数组是值类型。
– [10]int 和[20] int 是不同类型
– 调用func f(arr[10]int) 会拷贝数组
3.2 slice(切片)
arr := […]int{0, 1, 2, 3, 4, 5, 6, 7}
s := arr[2:6]
slice 本身没有数据,是对底层array的一个view
slice的拓展
arr := […]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := s1[3:5]
ptr len cap
slice 可以向后拓展,不可以向前拓展
s[i] 不可超越len(s),向后拓展不可以超越底层数组cap(s)
添加元素
– 添加元素时如果超越cap,系统会重新分配更大的底仓数组
– 由于值传递的关系,必须接受append的返回值
s3 = append(s2, s3[:2]...)
复制元素
copy(c2, c3)
3.4 map
m := map[string]string{
"name": "ccmouse"
}
m1 := make(make[string]int) //m1== empty map
var m2 = map[string]int //m2 ==nil
for _, v := range m{
fmt.Println("key,value,", v)
}
mm, ok:= m["m"]
寻找最长不含有重复字符的子串
3.6 字符和字符串处理
rune 相当于 go的char
– 使用rango遍历pos,rune对
– utf8.RuneCountInString 获得字符数量
– len是字节长度
– []byte获得字节
– Fields ,Split,Join
– Contains, Index
– ToLower, ToUpper
– Trim, TrimRight, TrimLeft
4.1 结构体和方法
面向对象
– go语言仅支持封装,不支持继承和多态
– go语言没有class 只有struct
type point struct {
i, j int
}
结构的创建
func createNode(value int) *treeNode {
return &treeNode{Value:value}
}
root.left.right = createNode(2)
为结构定义方法
func(node TreeNode) print() {
fmt.Print(node.Value)
}
使用指针作为方法接收者
func(node *TreeNode) setValue(value int) {
node.Value = value
}
值接收者 vs 指针接收者
– 要改变内容必须使用指针接收者
– 结构过大也考虑使用指针接收者
– 一致性:如有指针接收者, 最好都是指针接收者
– 值接收者是go语言特有
– 值/指针接收者均可接收值/指针
封装
– 名字一般使用CamelCase
– 首字母大写:public
– 首字母小写:private
包
– 每个目录一个包
– main包包含可执行入口
– 为结构定义的方法必须放在同一个包内
– 可以是不同文件
拓展拓展系统类型或者别人的类型
– 定义别名
– 使用组合
GOPATH环境变量
– 默认在~/go
– 官方推荐:所有项目和第三方库都放在同一个gopath下
– 也可以将每个项目放在不同的gopath
go get 获取第三方库
go build 来编译
go install 产生pkg文件和可执行文件
go run 直接编译运行
接口
type Traversal interface{
Traverse()
}
duck typing
– “像鸭子走路,像鸭子叫, 那么就是鸭子”
– 描述事物的外部行为而非内部结构
– 严格说go属于结构化类型系统,类似duck typing
– 又具有java的类型检查
– 同时具有python,c++的duck typing的灵活性
接口的定义
使用者 -> 实现者
type Retriever interface{
Get(source string) string
}
func download(retriever Retriever) string{
return retriever.Get("www.imooc.com")
}
接口变量里面有什么
实现者的类型
实现者的指针=>实现者
接口变量自带指针
查看接口变量
– 表示任何类型: interface{}
– type assertion
– type switch
特殊接口
– Stringer
– Reader/Writer
函数与闭包
函数式编程vs函数指针
正统的函数式编程
– 不可变性:不能有状态,只有常量和函数
– 函数只能有一个参数
闭包
函数体 包含局部变量和自由变量
python中的闭包
def adder():
sum = 0
def f(value):
nonlocal sum
sum += value
return sum
return f
原生支持闭包 用closure来查看闭包内容
go 语言闭包的应用
– 斐波那契数列
– 为函数实现接口
– 使用函数来遍历二叉树
– 更为自然,不需要修饰如何访问自由变量
– 没有lambda表达式,有匿名函数
7 defer调用
资源管理与出错处理
何时使用defer调用
open/close
lock/unlock
printheader/printfooter
错误处理
file, err := os.Open("abc.txt")
if err != nil {
if pathError, ok := err.(*os.PathError); ok{
fmt.Println(pathError.Err)
} else {
fmt.Println("unknown error", err)
}
}
recover
– 仅在defer调用中使用
– 获取panic的值
– 如果无法处理,可重新panic
error vs panic
– 意料之中的:使用error。 如文件打不开
– 意料之外:使用panic 。如数组越界
错误处理综合示例
– defer+panic+recover
测试