2022-5-31 实习Day48

1、清算系统环境搭建与配置,查找清算系统的相关问题 – 2小时 100%
2、清算系统报文查询相关列表排列混乱原因查找,定位至前端未添加排序组件,前端未传递排序数据至后端 –2小时 50%
3、汇出汇款会计分录对照excel表进行相关配置,使其呈现符合要求的格式 –2小时 100%


Golang编程学习(part 43)

1、channel可以声明为只读,或者只写性质

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

func main() {
// 管道可以声明为只读或者只写

// 1、在默认情况下,管道是双向的
var chan1 chan int
chan1 = make(chan int, 3)
chan1 <- 1
chan1 <- 2
n := <-chan1
fmt.Println(n)

// 2、声明为只写
var chan2 chan<- int
chan2 = make(chan int, 3)
chan2 <- 20
// num:=<-chan2 //error
fmt.Println("chan2=", chan2)

// 3、声明为只读
var chan3 <-chan int
chan3 = chan1
//chan3<-5 //error
fmt.Println(<-chan3)
}


2、channel只读、只写的最佳实践案例

实参是可读可写双向的,而形参是只读或者只写,也就是函数形参限定了模式,但是类型还是管道类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import "fmt"

func main() {
ch := make(chan int, 10)
exitChan := make(chan struct{}, 2)
go send(ch, exitChan)
go recv(ch, exitChan)

var total = 0
for range exitChan {
total++
if total == 2 {
break
}
}
fmt.Println("结束....")
}

// ch chan<- int,这样ch就只能写操作了
func send(ch chan<- int, exitChan chan struct{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
var a struct{}
exitChan <- a
}

// ch <-chan int,这样ch就只能读操作了
func recv(ch <-chan int, exitChan chan struct{}) {
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
var a struct{}
exitChan <- a
}


3、使用select可以解决从管道取数据的阻塞问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
"fmt"
"time"
)

func main() {
// 使用select可以解决从管道取数据的阻塞问题
// 1、定义一个管道10个数据int
intChan := make(chan int, 10)
for i := 0; i < 10; i++ {
intChan <- i
}

// 2、定义一个管道5个数据string
stringChan := make(chan string, 5)
for i := 0; i < 5; i++ {
stringChan <- "hello" + fmt.Sprintf("%d", i)
}

// 传统的方法在遍历管道时,如果不关闭会阻塞而导致deadlock

// 问题:在实际开发中,可能我们不好确定什么时候关闭该管道
// 可以使用select方式去解决
// label:
for {
select {
// 注意:这里,如果intChan一直没有关闭,不会一直阻塞而deadlock
// 会自动到下一个case匹配
case v := <-intChan:
fmt.Printf("从 intChan 读取的数据%d\n", v)
time.Sleep(time.Second)
case V := <-stringChan:
fmt.Printf("从 stringChan 读取的数据%s\n", V)
time.Sleep(time.Second)
default:
fmt.Printf("都取不到了,不玩了,程序员可以加入逻辑\n")
time.Sleep(time.Second)
return
// break label
}
}
}


4、goroutine中使用recover,解决协程中出现panic,导致程序崩溃问题

说明:如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成整个程序崩溃,这时我们可以在goroutine中使用recover来捕获panic,进行处理,这样即使这个协程发生问题,但是主线程仍然不受影响,可以继续运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main

import (
"fmt"
"time"
)

func main() {
go sayHello()
go test()

for i := 0; i < 10; i++ {
fmt.Println("main() ok=", i)
time.Sleep(time.Second)
}
}

func sayHello() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Println("hello,world")
}
}

func test() {
// 这里我们可以使用defer+recover
defer func() {
// 捕获test抛出的panic
if err := recover(); err != nil {
fmt.Println("test()发生了错误", err)
}
}()

// 定义了一个map
var myMap map[int]string
myMap[0] = "golang" //error
}