按照一周写一篇博客的习惯,今天又得上交博客了 =.=
因为对区块链感兴趣,看很多人推荐学golang,所以这周买了本<<`Go语言实战>>
Go的优势(小白观点,欢迎各位大牛指正)
1.编译速度极快.因为只编译那些直接被引用的库,而不像Java,C,C++要遍历所有依赖链中所有依赖的库
2.支持并发.goroutine很像线程,但占用的内存远少于线程.channel实现多个goroutine之间的通信
3.没有继承,设计模式为组合,(不能说是优势,只是设计的角度不一样)
4.现代化的垃圾回收机制
5.现代化的语法
具体内容(纯属记录一些自己需要注意的点)
- 两个函数init和mian
每个代码文件里的init函数都会在main函数执行前调用;
main函数是项目的入口,包名为main.按照惯例,包和文件夹同名 - 数组
声明方式:
var array [5]int
var array [5]int {1,2,3,4,5}
var array […]int {1,2,3,4,5}
var array [5]int {1: 10, 2:20} //初始化索引为1和2的元素,其他元素保持零值
复制数组
值复制
var array1 [5]int
array1 = array
指针复制
var array1 [5]*int
array1 = array
函数间通过指针地址来传递数组
-
数组的长度是固定的(为什么会这样设计?),可以动态的进行增加和删除的是切片
切片是一个有三个字段的数据结构,分别为:指向底层数组的指针,切片访问的元素个数(长度),切片允许增长的元素的个数(容量).
声明方式:
var slice make([]string,5) // 制定切片长度为5,容量为5
var slice make([]string,3,5) // 制定切片长度为3,容量为5
var slice []int {1.2.3.4.5} // 与数组不同在于中括号中没有制定长度
var slice []int // 创建nil切片
var slice []int {} // 创建空的整形切片
var slice make([]int, 0) //创建空的整形切片
使用切片创建切片
newSlice := slice[1:3]
对于底层数组容量为k的slice[i,j]
长度: j - i
容量: k - i
i 代表开始的索引位置
j表示开始的索引位置(1)加上希望包含的元素的个数(2)
切片增长:append
newSlice = append(newSlice, 60)
使用3个索引创建切片
slice := source[2:3:4]
对于slice[i:j:k]
长度: j - i
容量: k - i
在函数间通过值来传递,不是指针地址 -
映射:存储无序的键值对
声明方式
dict := make(map[string] int)
dict := map[string] string {“a”:“A”,“b”:“B”}// 创建空映射
colors:= map[string] string{}
// 设置值
colors[“Red”] = “red” //类似js中操作对象属性
// 取值
values, exists := colors[“Red”] // 第二个参数用来判断是否有值(零值判断)
// 删除
delete(colors, “Red”)
函数间传递的不是映射的副本,而是指针地址 -
通道
通道分为有缓冲的通道和无缓冲的通道
无缓冲的通道: 发送和接收同时进行,如果一方没有准备好,另一方则处于等待状态
模拟网球比赛: 两位选手把两个球在两个人之间来回传递
package main
import (
"fmt"
"sync"
"time"
"math/rand"
)
var wg sync.WaitGroup
func main() {
baton := make(chan int)
// 创建两个场地
wg.Add(2)
// 创建两个运动员
// var player1 = player("A", baton);
// var player2 = player("B", baton);
// 创建channal需要用go
go player("A", baton)
go player("B", baton)
// 发球
baton <- 1
wg.Wait()
}
func player(name string, baton chan int) {
defer wg.Done() // 执行条件是什么???当前函数结束后调用
for {
// 接球,判断是否有球传过来,如果有就打回去
num, ok := <- baton
if !ok {
fmt.Printf("Player %s Won\n", name)
return
}
// 将球打回去,模拟失败,如果随机数能被13整除,就算失败
n := rand.Intn(100)
if n % 13 == 0 {
fmt.Printf("Player %s missed \n",name)
close(baton) // 关闭这个通道
return
}
num++
// 模拟等待时间
time.Sleep(time.Second)
baton <- num
fmt.Printf("Player %s hit %d \n",name, num)
}
}
**有缓冲的通道:**能够在通道中存储多个值,不要求接受和发送同步,只有在通道中没有要接收的值时,接收动作才会阻塞.只有在通道中没有可用缓冲区容纳被发送的值时,发送动作才会阻塞.
模拟搬运东西:
package main
import (
"fmt"
"sync"
"time"
)
/**
// 创建劳务所
// 创建四个工人
// 创建10个箱子
// 任务背景: 非法囚禁四个工人,当工人完成任务后,解放工人
// 任务:四个工人把十个箱子从A点拿到B点
// 任务结束,解放四个工人
// 任务结束,关闭劳务所
*/
// 创建劳务所 => 计数信号量
var wg sync.WaitGroup
// var mutex sync.Mutex 有必要用锁吗??
func main() {
// 创建存储箱子的仓库 => 创建有缓冲的通道
// 第一个参数是要传递的信息
//第二个参数代表通道中最多可以存多少个值
worker := make(chan string, 10)
// 创建四个工人 => goroutine的总数为4
wg.Add(4)
// 让四个人等待执行任务 => 4个goroutine
for j := 0; j < 4; j++ {
// 第j个人开始接受任务
fmt.Printf("第%d个人开始接受任务\n",j)
go Task(worker, j)
}
// 创建10个箱子
for i := 0; i < 10; i++ {
// 将箱子分配给闲的工人
fmt.Printf("将第%d个箱子分配给工人\n", i)
worker <- fmt.Sprintf("箱子 %d", i)
}
// 任务背景: 非法囚禁四个工人,当工人完成任务后,解放工人
close(worker)
// 等待完成
fmt.Printf("等待工作完成...\n")
wg.Wait()
fmt.Printf("销毁劳务所\n")
// fmt.Sprintf("测试Sprintf")
}
func Task(worker chan string, num int) {
// 任务结束,关闭劳务所
defer wg.Done()
for {
task, ok := <-worker
if !ok {
// 箱子已被搬完,该工人得到解放,调用done方法,使wg的值减一,当达到0时,终止程序
fmt.Printf("第%d个工人得到解放\n", num)
return
}
fmt.Printf("第%d个工人 在A点搬起了 %s\n", num, task)
// 任务:四个工人把十个箱子从A点拿到B点
time.Sleep(time.Second*2)
fmt.Printf("第%d个工人搬动中\n", num)
fmt.Printf("第%d个工人 完成 %s\n", num, task)
}
}
- 未完待续…
作者因对区块链感兴趣,学习Go语言并记录相关内容。介绍了Go语言编译速度快、支持并发等优势,还记录了Go语言中init和main函数、数组、切片、映射、通道等基础语法,如数组声明、切片增长、映射操作及通道分类等。

被折叠的 条评论
为什么被折叠?



