golang数组
var a [3]int //定义一个大小为3的元组
var a [3]int{1, 2, 3} //设定初始值
a := []int{1, 2, 3} // 一般的写法,可以设定初始值,让go 自己判定元素多少。
a[1] = 9 //更改值
a = append(a, 10) //末尾添加值
golang映射(词典)
numbers := make(map[string]int) //关键词的数据类型和对应的数据类型。
numbers["one"] = 1
numbers["two"] = 2
delete(numbers, "one") // 通过delete关键词删除一个映射
fmt.Println(numbers)
map[two:2]
golang for循环
func main() {
for i := 0; i < 5; i++ { //三部分,第一个部分是整个循环开始之前需要执行的代码,第二部分是程序执行的判断条件,决定是否执行下去,第三部分是循环结束后执行的代码。
fmt.Println(i)
} // for循环中的任意一个循环都可以被忽略。
}
0
1
2
3
4
golang 利用for遍历数组
func main() {
a := []int{1, 2, 3, 4, 5}
for k, v := range a {
fmt.Println(k, v)
}
}
0 1
1 2
2 3
3 4
4 5
golang 利用for遍历词典
func main() {
numbers := make(map[string]int) //关键词的数据类型和对应的数据类型。
numbers["one"] = 1
numbers["two"] = 2
for k, v := range numbers {
fmt.Println(k, v)
}
}
one 1
two 2
go 函数
# 例1
func main() {
fmt.Println(add(1, 3))
}
func add(x int, y int) int {
return x + y
}
# 例2
func main() {
// fmt.Println(add(1, 3))
sum, product := do_math(2, 3)
fmt.Println(sum, product)
}
func do_math(x int, y int) (int, int) { //可以接收两个值,返回两个值
return x + y, x * y
}
golang 闭包
pass
golang 指针
func main() {
n := 0
add(&n) // 传入的是这个参数的地址
fmt.Println(n)
}
func add(n *int) { //这个'*'表示接收一个指向这个整数的指针,也就是地址
*n = *n + 1 //通过这个地址的值进行更改数据
}
1
golang 自定义数据类型
type cat struct { //定义自己的数据类型
name string
age int
}
func main() {
newCat := cat{name: "Kitty", age: 3}
newCat.age = 4 //重新定义
fmt.Println(newCat)
}
{Kitty 4}
golang 给自己的类型定义方法
type MyFloat float64 //定义自己的方法类型
func (n *MyFloat) add() { //也可以运用指针传参
*n = *n + 0.5
}
func (n MyFloat) show() {
fmt.Println(n)
}
func show(n MyFloat) {
fmt.Println(n)
}
func main() {
var a MyFloat = 1.5
a.add()
a.show() // 方法类型传参
show(a)
}
golang 实例
普通的函数功能,问题是如何同时进行呢?
func count(n int, animal string) {
for i := 0; i < n; i++ {
fmt.Println(i+1, animal)
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
}
func main() {
count(5, "羊")
count(5, "牛") //这里是按照顺序执行的。
}
goroutine,问题是不知道还有多少goroutine没有执行完成
func count(n int, animal string) {
for i := 0; i < n; i++ {
fmt.Println(i+1, animal)
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
}
func main() {
go count(5, "🚗") //可以创建一个goroutine,其实本质就是协程。
go count(5, "🛹") //当这里创建两个goroutine的时候,main函数会直接执行完毕,期间创建的所有的goroutine都会被销毁。
}
waitGroup,问题是两个程序是各干各的
func count(n int, animal string) {
for i := 0; i < n; i++ {
fmt.Println(i+1, animal)
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2) //这个waitgroup其实就是一个计数器
go func() {
count(5, "🚗")
wg.Done() //如果这个协程完成了计数器就减一
}()
go func() {
count(3, "🛹")
wg.Done()
}()
wg.Wait() //等计数器的值等于0的时候就继续执行,也就是完成计算
}
golang channel 信道
如果需要进行交流,可以加一个全局变量,但是问题是每一个goroutine可能是不同cpu的,可能存在同时更改同一块内存的情况。
通常其他的语言比如python就是全局锁,同一时间,只能是一个线程操作一块内存地址。
但是golang 做法是不同的,它的设计者采用了communicating Sequential Processes的一种方法,(我们不通过共享内存来交流,我们要通过交流来共享内存)
注意的是:往channel里发送一条消息,和从channel里面收听一条消息,都会阻塞代码的运行。当我要发送一条消息的时候,我会一直在这里等着,直到这条消息在channel的另一边被接收了。相反如果我想从channel里面接收一条消息,如果有人发送消息,我就会接收到,但是如果没有人发送消息,我就会在这里一直等着。就可以利用这种阻塞代码的特性,来同步我们的代码。
func count(n int, animal string, c chan string) { // 让count函数多接收一个参数channel
for i := 0; i < n; i++ {
c <- animal
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
}
func main() {
channel := make(chan string)
go count(5, "🚗", channel)
for { // 因为只能接收一条消息,所以写一个for循环让他不停的接收消息
message := <-channel
fmt.Println(message)
}
}
🚗
🚗
🚗
🚗
🚗
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/theing/study/go_study/hello/test.go:18 +0xba
exit status 2
上述出现了错误,因为count函数不会有新的值传进去,但是main函数里面一个channel一直等着那边的消息。所以给出了报错。方法就是关闭channel。
通过 channel传过来是否可以通讯的布尔值是否关闭channel
func count(n int, animal string, c chan string) { // 让count函数多接收一个参数channel
for i := 0; i < n; i++ {
c <- animal
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
close(c) //for循环完毕了就关闭这个channel
}
func main() {
channel := make(chan string)
go count(5, "🚗", channel)
for { // 因为只能接收一条消息,所以写一个for循环让他不停的接收消息
message, open := <-channel //每个channel都有一个布尔值,判断这个channel是否还可以通讯。
if !open { //通过这个布尔值判断是否接收消息。
break
}
fmt.Println(message)
}
}
通过for循环判断channel
func count(n int, animal string, c chan string) { // 让count函数多接收一个参数channel
for i := 0; i < n; i++ {
c <- animal
time.Sleep(time.Millisecond * 500) // 睡眠5秒
}
close(c) //for循环完毕了就关闭这个channel
}
func main() {
channel := make(chan string)
go count(5, "🚗", channel)
for message := range channel { //也可以用for循环进行判断,如果channel关闭了for循环就退出了。
fmt.Println(message)
}
}
通过channel交流
问题是阻塞代码
func main() {
c1 := make(chan string) //创建两个channel
c2 := make(chan string)
go func() {
for {
c1 <- "🚗"
time.Sleep(time.Millisecond * 500) //每次发送数据间隔半秒
}
}()
go func() {
for {
c2 <- "🚍"
time.Sleep(time.Millisecond * 2000) //每次发送数据间隔2秒
}
}()
for {
fmt.Println(<-c1) //发送数据和接收数据都会阻塞代码的运行
fmt.Println(<-c2)
}
}
select 语句
func main() {
c1 := make(chan string) //创建两个channel
c2 := make(chan string)
go func() {
for {
c1 <- "🚗"
time.Sleep(time.Millisecond * 500) //每次发送数据间隔半秒
}
}()
go func() {
for {
c2 <- "🚍"
time.Sleep(time.Millisecond * 2000) //每次发送数据间隔2秒
}
}()
for {
select { //运用select 看那个channel不是阻塞的就运行那个。
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
}
}
}
实践,对树形结构的数据进行遍历,搜索文件
pass
buffer带有缓存的channel
contast包裹,可以很好的管理goroutine