Go 语言最主要的特性:
自动垃圾回收
更丰富的内置类型
函数多返回值
错误处理
匿名函数和闭包
类型和接口
并发编程
反射
语言交互性
当一个变量被声明之后,系统自动赋予它该类型的零值:int 为 0,float 为 0.0,bool 为 false,string 为空字符串,指针为 nil
var(声明变量), const(声明常量), type(声明类型) ,func(声明函数)。
变量的最基本信息就是类型和值
同一个目录中所有的go文件的package声明必须相同
传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return 返回,或者 使用数组的切片
传值、传引用
传指针 可改变值
s 是一个字符串(本质上是一个字节数组)
切片(slice)是对数组一个连续片段的引用,运行时可变,长度可变的数组。不需要使用额外的内存并且比使用数组更有效率
字符串是纯粹不可变的字节数组,它们也可以被切分成切片。
- 切片、映射和通道,使用 make-------------slice、map、chan
- 数组、结构体和所有的值类型,使用 new------------------array、struct……
指针数组 [n]*T,数组指针 *[n]T
s1 := []int{0,1,2,3,8:100} 索引8是100
s2 := make([]int,6,8) // 使用 make 创建,指定 len 和 cap 值。
data := [...]int{0,1,2,3,4,10:0}
s := data[:2:3]
s[low:high:max] 从索引位置 low到high 得到 len = high-low 、cap = max - low 前闭后开
常规slice , data[6:8],从第6位到第8位(返回6, 7),长度len为2, 最大可扩充长度cap为4(6-9)
另一种写法: data[:6:8] 每个数字前都有个冒号, slice内容为data从0到第6位,长度len为6,最大扩充项cap设置为8
a[x:y:z] 切片内容 [x:y] 切片长度: y-x 切片容量:z-x
切片拷贝、切片遍历、切片resize
切片通常以 2 倍容量重新分配底层数组
指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。
new、make 都是用于在堆上分配内存,make只用于slice/map/chan的内存创建
但是它们的行为不同,适用于不同的类型。
1.new 函数分配内存,make 函数初始化
2.new(T) 为每个新的类型 T 分配一片内存,初始化为 0 并且返回类型为 *T 的内存地址 make(T) 返回一个类型为 T 的初始值
每个实例4~5KB的栈内存占用和由于实现机制而大幅减少的创建和销毁开销是go高并发的根本原因。
goroutine 奉行通过通信来共享内存,而不是共享内存来通信。
Go语言的并发是基于 goroutine 的,goroutine 类似于线程,但并非线程。可以将 goroutine 理解为一种虚拟线程。
Go 语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用CPU性能。开启一个goroutine的消耗非常小(大约2KB的内存),你可以轻松创建数百万个goroutine。
1.`goroutine`具有可增长的分段堆栈。这意味着它们只在需要时才会使用更多内存。
2.`goroutine`的启动时间比线程快。
3.`goroutine`原生支持利用channel安全地进行通信。
4.`goroutine`共享数据结构时无需使用互斥锁。
将函数作为返回值、将函数作为参数 可以返回其它函数的函数和接受其它函数作为参数的函数均被称之为高阶函数,是函数式语言的特点
同一种类型在不同的实例上似乎表现出不同的行为。
接口是一种契约,实现类型必须满足它,它描述了类型的行为,规定类型可以做什么。接口彻底将类型能做什么,以及如何做分离开来,使得相同接口的变量在不同的时刻表现出不同的行为,这就是多态的本质。
OO 语言最重要的三个方面分别是:封装,继承和多态
1.封装(数据隐藏):和别的 OO 语言有 4 个或更多的访问层次相比,Go 把它简化为了 2 层
2.继承:用组合实现:内嵌一个(或多个)包含想要的行为(字段和方法)的类型;多重继承可以通过内嵌多个类型实现
3.多态:用接口实现:某个类型的实例可以赋给它所实现的任意接口类型的变量。类型和接口是松耦合的,并且多重继承可以通过实现多个接口实现。Go 接口不是 Java 和 C# 接口的变体,而且接口间是不相关的,并且是大规模编程和可适应的演进型设计的关键。