for i <= 3 {
fmt.Println(i)
i = i + 1
}
for j := 7; j <= 9; j++ {
fmt.Println(j)
}
if num := 9; num < 0 { // 这个num在if上面定义会死啊。。非要挤在一起。。
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
i := 2
switch i {
case 1: // 如果 i == 1
fmt.Println("one")
case 2:
fmt.Println("two")
case 3 , 4: // 逗号表达 或
fmt.Println("three or four")
default:
fmt.Println("default")
}
// 用来判断类型,只能在switch里面用.(type)
switch t := i.(type) {
case bool:
fmt.Println("I'm a bool")
case int:
fmt.Println("I'm an int")
default:
fmt.Printf("Don't know type %T\n", t)
}
// 创建数组
var a [5]int // [0 0 0 0 0]
b := [5]int{1, 2, 3, 4, 5} // [1 2 3 4 5]
// 取值与赋值
a[4] = 100
// 数组长度
len(a)
// 多维数组(元素是数组的数组)
// 似乎不能通过:=创建,只能先定义一个,然后for循环填满
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
// 用make来新建,规定内容和大小
s := make([]string, 3)
// 或者这样也行。和数组的区别在于,不规定长度
t := []string{"g", "h", "i"}
// 获取值和长度的方法和数组一样
// slice增加一个元素,返回一个新的slice
s = append(s, "d")
// 如果直接用s[3]来赋值,会报错。数组也是。
// copy一个slice
c := make([]string, len(s)) // 先要准备好长度和类型一样的位置,才能复制
copy(c, s)
// 切片操作。和python差不多
l := s[2:5] // 包括前面不包括后面
// 新建一个slice
nums := []int{2, 3, 4}
// 循环一下
for i, num := range nums { // 第一个参数可以写_,表示不需要用这个索引
if num == 3 {
fmt.Println("index:", i)
}
}
// 循环map
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs { // 第一个是key,第二个是value
fmt.Printf("%s -> %s\n", k, v)
}
// 只有一个值,那就是遍历key
for k := range kvs {
fmt.Println("key:", k)
}
// 循环字符串,返回的是unicode
for i, c := range "go" { // i是索引,c是unicode
fmt.Println(i, c)
}
// 函数定义:
func plus(a int, b int) int { // 函数名(参数,参数的数据类型) 返回值的数据类型
return a + b
}
// 输入参数都是一种类型,可以统一写在最后
func plusPlus(a, b, c int) int {
return a + b + c
}
// 多返回值可以加个括号
func vals() (int, int) {
return 3, 7
}
// 调用
res = plusPlus(1, 2, 3)
_, c := vals() // 不需要用到的返回值,可以用下划线代替
// 可变参数
func sum(nums ...int) { // 数据类型前面加上...
// 函数内容
}
// 调用
sum(1, 2) // 普通地传入
// 装在slice里面传入
nums := []int{1, 2, 3, 4}
sum(nums...) // ...写在后面
func intSeq() func() int { // 返回是一个函数,函数的返回是int
i := 0
return func() int { // 返回的函数
i++
return i
}
}
// 返回值放到nextInt之中
nextInt := intSeq()
fmt.Println(nextInt()) // 每次调用,输出都会+1
// 重新赋值返回的函数,就会获得一个新的i
newInts := intSeq()
func fact(n int) int {
if n == 0 {
return 1
}
return n * fact(n-1)
}
// 感觉这种做法也不是最好,不是尾递归
ticker := time.NewTicker(time.Millisecond * 500) // 500毫秒一次循环的定时器
go func() {
for t := range ticker.C { // 自带的频道同样在C,返回值是触发的时间
fmt.Println("Tick at", t)
}
}()
ticker.Stop() // 需要手动停止定时器,不然会一直间隔打点下去
// 这是我们将要在多个并发实例中支持的任务了。这些执行者
// 将从 `jobs` 通道接收任务,并且通过 `results` 发送对应
// 的结果。我们将让每个任务间隔 1s 来模仿一个耗时的任务。
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j) // 不同的协程对应的worker
time.Sleep(time.Second)
results <- j * 2
}
}
func main() {
// 为了使用 worker 工作池并且收集他们的结果,我们需要
// 2 个通道。
jobs := make(chan int, 100) // 创建通道,缓存100
results := make(chan int, 100)
// 这里启动了 3 个 worker,初始是阻塞的,因为
// 还没有传递任务。
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 这里我们发送 9 个 `jobs`,然后 `close` 这些通道
// 来表示这些就是所有的任务了。
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// 最后,我们收集所有这些任务的返回值。
for a := 1; a <= 9; a++ {
fmt.Println("<-results", <-results)
}
}
// 创建通道,往里面传1到5
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests) // 关闭
// 这个 `limiter` 通道将每 200ms 接收一个值。这个是
// 速率限制任务中的管理器。
limiter := time.Tick(time.Millisecond * 200) // Tick 会返回一个通道,源码中用make创建了
// 通过在每次请求前阻塞 `limiter` 通道的一个接收,我们限制
// 自己每 200ms 执行一次请求。
for req := range requests {
<-limiter // 阻塞,只有当limiter有了返回值了之后,才能继续下面的操作
fmt.Println("request", req, time.Now())
}
burstyLimiter := make(chan time.Time, 3) // 通道长度只有3
for t := range time.Tick(time.Millisecond * 200) {
burstyLimiter <- t
}
...
for req := range requests {
<-burstyLimiter // 只能影响前三个的速率
fmt.Println("request new /n", req, time.Now())
}
// 我们将使用一个无符号整型数来表示(永远是正整数)这个*计数器*。
var ops uint64 = 0
// 为了模拟并发更新,我们启动 50 个 Go 协程
for i := 0; i < 50; i++ {
go func() {
for {
// 使用 `AddUint64` 来让计数器自动增加,使用
// `&` 语法来给出 `ops` 的内存地址。
atomic.AddUint64(&ops, 1) // 在计数器地址,自动+1
// 允许其它 Go 协程的执行
runtime.Gosched() // 应该是为了让出执行堆栈
}
}()
}
// 等待一秒,让 ops 的自加操作执行一会。
time.Sleep(time.Second)
// 为了在计数器还在被其它 Go 协程更新时,安全的使用它,
// 我们通过 `LoadUint64` 将当前值的拷贝提取到 `opsFinal`
// 中。和上面一样,我们需要给这个函数所取值的内存地址 `&ops`
opsFinal := atomic.LoadUint64(&ops) // 安全使用计数器
fmt.Println("ops:", opsFinal)
// 定义map
var state = make(map[int]int)
// 定义锁
var mutex = &sync.Mutex{}
// 取值
mutex.Lock() // 上锁才能操作map,一次只能有一个人在操作
total += state[key]
mutex.Unlock()
// 赋值
mutex.Lock()
state[key] = val
mutex.Unlock()
// 打印值也要上锁
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()