今天主要去看了一下官方网站,网站:https://gobyexample.com/
进行了简单的摘要。依旧是不会写博客的一天(有java基础的哦,虽然也不太行)
Constants:常量
Slices:切片 s := make([]string, 3) //长度为3的切片
fmt.Println("len:", len(s))//返回长度
s = append(s, "d")//压入新的
l := s[2:5]//得到一个包含元素 s[2]、s[3] 和 s[4] 的 slice (做包右面不包除非【2:】后面都包括)
Map:关联数据类型 m := make(map[string]int)//创建新的map
n := map[string]int{"foo": 1, "bar": 2}//声明并初始化map
m["k1"] = 7//设置键值对
fmt.Println("len:", len(m))//内建函数 len 可以返回一个 map 的键值对数量。
delete(m, "k2")//内建函数 delete 可以从一个 map 中移除键值对。
Range 遍历(for) for _, num := range nums {sum += num}//无索引遍历(无key)
for i, num := range nums {if num == 3 {fmt.Println("index:", i)}}//有索引value=3时返回key
for i, c := range "go" { fmt.Println(i, c) }//range 在字符串中迭代 unicode 码点(code point)。 第一个返回值是字符的起始字节位置,然后第二个是字符本身。
函数 func plusPlus(a, b, c int) int { return a + b + c}//a,b,c类型相同可以只声明最后一个
多返回值(同时返回结果和错误信息) func vals() (int, int) {return 3, 7}//(int,int)表示返回两个int
_, c := vals()//仅返回一部分即7
变参函数 func sum(nums ...int) {}//接受任意数量的int
sum(nums...)// func函数名(slice切片...)直接求和
函数特性
闭包 https://gobyexample-cn.github.io/closures
递归 https://gobyexample-cn.github.io/recursion
指针 func zeroptr(iptr *int) {*iptr = 0}//*int代表使用指针,*iptr解引用这个指针
zeroptr(&i)//通过&i取得i的内存地址
fmt.Println("zeroptr:", i)
fmt.Println("pointer:", &i)//打印地址
结构体 type 结构体名persnon struct { name string age int}//创建结构体
fmt.Println(person{"Bob", 20})//创建新的结构体元素
fmt.Println(person{name: "Alice", age: 30})//可以指定字段元素
fmt.Println(person{name: "Fred"})//省略字段初始化为零
fmt.Println(&person{name: "Ann", age: 40})//& 前缀生成一个结构体指针。
fmt.Println(s.name)//s的name,用“.”
sp.age = 51//结构体可变,重新赋值51
方法 支持位结构体定义方法
func (r *rect) area() int {return r.width * r.height}//接受*rect,返回int
接口 type geometry interface {area() float64 perim() float64}//接口的实现
func measure(g geometry) {}//通常使用measure函数来实现,通过它使用所有的接口
错误处理 func f1(arg int) (int, error) {//返回一个int和一个错误
if arg == 42 {return -1, errors.New("can't work with 42")//构建error
return arg + 3, nil//返回错误值为 nil 代表没有错误
}
type argError struct { arg int prob string }//可以自定义错误类型
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}//Sprint格式化输出,输出形式为%d - %s
for _, i := range []int{7, 42} {//在if的同一行进行错误检查
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:", r)
}
}
协程:量级的执行线程 go f("goroutine")//多线程开启,并发开启
go func(msg string) { fmt.Println(msg) }("going")//传入going并发异步执行
time.Sleep(time.Second)//等待进程完成,更好的方法是使用 WaitGroup
go func(){}()//以并发的形式调用函数
通道:连接多个协程的管道 messages := make(chan string)//创建新的通道(通道类型就是要传递值的类型)
go func() { messages <- "ping" }()//channel <-值,这样发送值到通道
msg := <-messages//接受通道里的值
通道缓冲:允许在没有对应接收者的情况下,缓存一定数量的值
messages := make(chan string, 2)//最多允许缓存两个值的通道
messages <- "buffered" messages <- "channel"//直接发送,无需发送之后马上接收
通道同步:可以使用通道来同步协程之间的执行状态
func worker(done chan bool) {//一个叫done的通道和一个bool
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
done <- true//done用于通知工作ok
如果你把 <- done 这行代码从程序中移除, 程序甚至可能在 worker 开始运行前就结束了。
}
通道方向:可以指定这个通道是否为只读或只写,可以提升程序的安全性
func ping(pings chan<- string, msg string) {//定义了只写(发送)权限
pings <- msg
}
func pong(pings <-chan string, pongs chan<- string) {//接收两个通道,pings用于只读(接受),pongs用于只写(发送)
msg := <-pings
pongs <- msg
}
通道选择器:可以同时等待多个通道操作
select {}//用select关键字来同时等待这两个值,默认处理第一个准备好的接受操作
time.Sleep(1 * time.Second)//等待的时间短的先输出,程序运行的时间是等待长的时间而不是和
超时处理 case <-time.After(1 * time.Second)://等待时间之后向通道传入
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(1 * time.Second)://如果操作耗时超过了允许的 1 秒(时间),执行这个
fmt.Println("timeout 1")
}
如果正常时间<超时时间,则不触发超时时间
非阻塞通道操作:常规通道是阻塞的。 可以用default,select实现非阻塞发送、接收,甚至是非阻塞的多路 select。
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)//发送msg必须有人收才会被选中,否则不会。
default:
fmt.Println("no message sent")//输出结果为这个
}
select {
case msg := <-messages://如果messages有值(接收必须有人发才会被选中)
fmt.Println("received message", msg)
case sig := <-signals://如果signals有值
fmt.Println("received signal", sig)
default://否则
fmt.Println("no activity")
}
通道的关闭:这个特性可以让通道的接收方知道工作完成
j, more := <-jobs//工作完成或关闭通道more为false
if more {}
else {
fmt.Println("received all jobs")
done <- true
return
}
close(jobs)//关闭通道
<-done//等待工作结束
通道遍历:类似for和range
queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue)//非空通道也可以关闭,关闭后可以正常接收
for elem := range queue { fmt.Println(elem) }//循环输出通道的值
Timer:定时器在一定时间之后要发生的事,它会提供一个用于通知的通道。与sleep的区别在于定时器可以在定时器触发之前取消。需要import time
timer1 := time.NewTimer(2 * time.Second)//这里的定时器等待2秒
<-timer1.C//c为定时器通道
stop2 := timer2.Stop()//停止定时器
Ticker:打点器在固定的时间间隔重复执行知道主动停止,停止后不能接受值
ticker := time.NewTicker(500 * time.Millisecond)//创建打点器
case t := <-ticker.C: fmt.Println("Tick at", t)//触发打点器
ticker.Stop()//结束打点器
网友评论