3.12-3.15
go语言学习
s == s[:i]+s[i:]
z := 37//z为int类型
pi := &z//pi为*int类型
ppi :=&pi//ppi为**int类型
**ppi++
z=38 *pi=38 **ppi=38
1.go语言的(点)操作符能够自动地将指针解引用,因为它所指向的是结构体
2.go语言中有些类型是引用类型:映射。切片。通道。函数和方法
3.指针也可以指向一个引用类型,虽然它只对切片管用,但是有时这个用法也很关键
4.如果定义了一个变量来保存函数,该变量实际上是保存了该函数的应用,
函数引用知道他们所引用的函数签名,因此不能传递一个签名不匹配的函数
go语言中的数组是一个定长的序列,其中的元素类型相同
.(点)操作符绝大多数情况下是足够的,对于不满足的情况可以使用*操作符进行显式解引用
s[n]切片中索引位置为n的项
s[n:m]切片中从n到m-1处所得的切片
s[n:]切片中从n到len-1处所得的切片
s[:m]切片中从0到m-1处所得的切片
s[:]切片中从0到len-1处所得的切片
cap(s) 切片s的容量,总是>=len(s)
len(s) 切片s中所包含项的个数,总是<=cap(s)
s[:cap(s)]增加切片s的长度到其容量,如果两者不同
make([]Type,length,capacity)
make([]Type,length)
[]Type{}
[]Type{value1,value2,...,valueN}
[]Type{}
内置的append()函数接受一个切片和一个或者更多个值,返回一个(可能为新的)切片,
其中包括原始切片的内容,并将给定的值作为其后续项
append(s,"h","j")添加单一的值
append(s,t...)添加切片中的所有值
append(s,u[2:5])添加一个子切片
append(b,letter...)将一个字符串字节添加到一个字节切片中
append()函数会隐式地创建一个新切片,将其原始的切片的项复制进去
内置的copy()函数接受两个相同类型的切片,如果目标切片的长度够容纳目标切片的项,否则将被忽视
s=s[2:] 从开始删除s[:2]的切片 ;删除前面":"在后
s=s[:4] 从末尾处删除s[4:]的切片;删除后面":"在前
s=append(s[:1],s[5:]...) 从中间删除s[1:5]
sort.searchFloat64s(fs,f)返回有序的[]float64切片fs中类型为Float64的值f的索引
例子:
f:=[]Float64{12,21,45,...}
ret :=sort.searchFloat64s(fs,12) 得到的是fs值为12的下标
映射(map)是一种内置的数据结构,保存键-值的无序集合,容量只受到机器内存的限制
映射里所有键值都是唯一的并且必须支持==和!=操作符
go语言的切片不能用于比较切片和结构体
由于映射属于引用类型,所以不管映射保存了多少数据,传递都是很廉价的
make(map[keyType]valueType,initialCapacity)
make(map[keyType]valueTYpe)
map[keyType]valueTYpe{}
map[keyType]valueTYpe{key1:value1,key2:value2,...,keyN:valueN}
go语言内置的make()函数可以用来创建切片。映射和通道
映射查询
city:="aaa"
_,present :=population[city] 找到后present=true,没找到present=false
delete()删除
delete(map名称,key值)
只需插入既可
映射的反转 for range 循环,改变key,value的位置即可
类型断言
在处理从外部源接收到的数据,想创建一个通用的函数以及在进行面向对象编程时,我们会需要使用interface{}类型(或自定义接口类型)。为了访问底层值,有一种方法是使用下面中提到的一种语法进行类型断言
ResultOfType,Boolean :=expression.(Type) 安全类型断言
ResultOfType :=expression.(Type) 不安全类型断言
Go语言通道是一个双向或者单向的通信管道,他们可用于在两个或者多个gorotine之间通信数据
Channel <-value 阻塞发送
<-channel 接收并将其丢弃
X :=<-channel 接收并将其保存
X,ok :=<-channel 功能同上,同时检查通道是否已关闭或者是否为空
gofunction(arguments)
gofunc(parameter){block} arguments
必须调用一个已有的函数,要么调用一个临时创建的匿名函数
defer 语句用于延迟一个函数或者方法的(或者当前所创建的匿名函数)执行,它会在外围函数或者方法返回前但是其返回值(如果有的话)计算之后执行
如果一个函数或者方法中有个defer语句,它们会议LIFO(后进先出)的方式执行
错误是指可能出错的东西,程序需以优雅的方式将其出来
异常是指“不可能”发生的事情“
对于“不可能发生”的情况,我们可以调用内置的panic()函数
Panic函数中断程序的执行以强制发生错误
如果调用了panic函数或者调用了发生了异常的函数或者方法,我们应该使用recover()以保证将异常转化为错误
可变参数函数就是指函数的最后一个参数可以接受任意个参数。这类函数在最后一个参数的类型前面添加一个省略号
所谓闭包就是一个函数“捕获”了和它在同一作用域的其他常量和变量
不论在什么地方调用,闭包能够使用这些常量或者变量、
递归函数通常有相同的结构:一个跳出条件和一个递归体
纯函数就是对同一组输入总是产生相同的结果,不存在任何副作用。如果一个纯函数执行时开销很大而且频繁地使用相同的参数进行调用,我们可以利用记忆功能来降低处理的开销。记忆技术就是保存计算的结果,当执行下一个相同的计算时,我们能够返回保存的结果而不是重复执行一次计算过程
go 语言不支持继承,只支持聚合(组合)和嵌入
type coloredPoint struct{
color.Color 匿名字段(嵌入)
x,y int 具名字段(聚合)
}
Color.Color字段是匿名的(因为它没有变量名),因此是嵌入字段。x ,y 字段是聚合字段
由于没有继承,因此也就没有虚函数
接口用于声明方法签名
结构体用于声明聚合或者嵌入的值
方法用于声明在自定义类型(通常为结构体)上的操作
Interface{}类型是声明了空方法集的接口类型。无论包不包含方法,任何一个值都满足interface{}类型
如果我们不为有方法的值使用接口类型,我们就可以使用类型断言,类型开关,或者甚至是反射的方式
type Exchanger interface{
Exchange()
}
接口实际上声明的是一个API(程序编程入口),即0个或者多个方法,虽然并不明确规定这些方法所需的功能
Go语言的接口对嵌入的支持非常好。接口可以嵌入其他接口,其效果与在接口中直接添加被嵌入方法一样
嵌入带方法的匿名值
如果有一个嵌入字段带方法,那我们就可以在外部结构体中直接调用它,并且只有嵌入的字段(而不是整个外部结构体)会作为接收者传递这些方法
结构体除了可以聚合和嵌入具体的类型外,也可以聚合和嵌入接口。(自然地,反之在接口中嵌入或者聚合结构体是行不通的,因为接口是完全抽象的概念,所以这样的嵌入和聚合毫无意义)。当一个结构体包含嵌入(匿名的)或者聚合(具名的)的接口类型的字段时,这意味这这个结构体将满足该接口规格的值存入结构体中
Goroutine 是go里一种轻量级线程—协程。相对线程,协程的优势就在于他非常轻量级,进行上下文切换的代价非常小。对于一个goroutine,每个结构体G中有一个sched的属性就是用来保存它上下文的。这样,goroutine就可以很轻易的来回切换。由于其上下文切换在生态下发生,根本不必进入内核态,所以速度很快。而且只有当前goroutine的PC,SP等少量信息需要保存
Go语言对并发编程提供了上层支持,因此正确处理并发是很容易做到的
用来处理并发的goroutine比线程更加轻量
并发程序的内存管理有时候是非常复杂的,而go语言提供了自动垃圾回收机制,让程序员的工作更轻松
协程(gorouine)
使用sync.WaitGroup来让每个共工作gorouine报告自己的完成状态。但是,使用sync.WaitGroup本身也会产生死锁,特别是当所有工作goroutine都处于锁定状态的时候(等待接受通道的数据)调用sync.WaitGroup.Wait()
就算只使用通道,在go语言里仍然可能发生死锁。举个例子,假如我们有若干个goroutine可以相互通知对方去执行每个函数(向对方发一个请求),现在,如果这些被请求执行的函数中有一个函数向执行它的goroutine发送了一些东西,例如数据,死锁就发生了。
通道(channel)
通道为并发运行的goroutine之间提供了一种无锁通信方式(尽管实现内部可能使用了锁,但无需我们关心)。当一个通道发生通信时,发生通道和接受通道(包括他们对应的goroutine)都处于同步状态
默认情况下,通道是双向的,可以往里面发送数据也可以从里接收数据
chan<- Type 只允许发送的通道
<-chan Type 只允许接受的通道
创建通道:ch :=make(chan type,buf)
(1)如何使用for或for-range遍历一个通道:
forv:=rangech{
//dosthwithv
}
(2)如何检测一个通道ch是否关闭
for{
ifinput,open:=<-ch;!open{
break
}
fmt.Printf("%s",input)
}
(3)如何通过一个通道让主程序等待直到协程完成
ch:=make(chanint)
gofunc(){
//dosth
ch<-1
}
DoSomethingElseForAWhile()
<-ch
//如果希望程序一直阻塞,在匿名函数中省略ch<-1
(4)通道的工厂模板
funcpump()chanint{
ch:=make(chanint)
gofunc(){
fori:=0;;i++{
ch<-i
}
}()
returnch
}
(5)简单的超时模板
timeout:=make(chanbool,1)
gofunc(){
time.Sleep(1*time.Second)
timeout<-true
}()
select{
case<-ch:
//读ch
case<-timeout
//超时
}