GO语言基础(五) | 青训营

82 阅读6分钟

1.channel与select

image.png

select { 
    case 语句1: *// 如果语句1可执行就执行* 
    case 语句2: *// 如果语句2可执行就执行* . . . 
    default: *// 如果以上的语句都不可执行就执行默认语句* 
}

select语句的执行过程如下:

  1. 执行每个case分支的表达式,如果表达式都可以立即执行,则直接进入步骤2;

  2. 如果有多个case分支可以立即执行,则随机选择一个;

  3. 如果没有可执行的case分支,且存在default分支,则执行default分支;

  4. 如果没有可执行的case分支,且不存在default分支,则阻塞当前goroutine,直到有可执行的case分支为止。

2.Go Moudles

image.png

image.png

image.png

image.png

image.png

3.Golang 处理键盘输入的两种方法(fmt & bufio)

一、fmt包

  1. fmt.Scan
  2. fmt.Scanf
  3. fmt.Scanln

Scan

func Scan(a ...interface{}) (n int, err error)

Scan从标准输入扫描文本,将成功读取的空白分隔的值保存进成功传递给本函数的参数。换行视为空白。返回成功扫描的条目个数和遇到的任何错误。如果读取的条目比提供的参数少,会返回一个错误报告原因。

var a1 int var a2 string n, err := fmt.Scan(&a1, &a2)

参数间以空格或回车键进行分割。 如果输入的参数不够接收的,按回车后仍然会等待其他参数的输入。 如果输入的参数大于接收的参数,只有给定数量的参数被接收,其他参数自动忽略。

Scanf (格式输入)

func Scanf(format string, a ...interface{}) (n int, err error)

egg:

package main

import "fmt"

func main() {
var a string

     n, err := fmt.Scanf("%s", &a) // afdsfdsfdsfds
     
     fmt.Println("n = ", n)   // n = 1
     fmt.Println("err = ", err) // err = <nil>
     fmt.Println("a = ", a)   // a = afdsfdsfdsfds

}

同样,Scanf也可以接收多个参数,但是接收字符串的话,只能在最后接收; 否则按照"%s%d"的格式进行接收,无论输入多少字符(包含数字),都会被认定是第一个字符串的内容,不会被第二个参数所接收。

n, err := fmt.Scanf("%d=%s", \&b, \&a)

Scanln

func Scanln(a ...interface{}) (n int, err error)

Scanln与Scan类似,但在换行时停止扫描,并且在最后一项之后必须有换行或EOF。

package main

 import "fmt"

 func main() {
     var a string
     var b string

     n, err := fmt.Scanln(&a, &b)
     
     fmt.Println("n = ", n)
     fmt.Println("err = ", err)
     fmt.Println("a = ", a)
     fmt.Println("b = ", b)

 }

Tips* * Scan的区别:如果设置接收2个参数,Scan在输入一个参数后进行回车,会继续等待第二个参数的键入;而Scanln直接认定输入了一个参数就截止了,只会接收一个参数并产生error(unexpected newline),且n = 1。

说通俗写,就是Scanln认定回车标志着【阻塞接收参数】结束, 而Scan认定回车只是一个分隔符(或空白)而已。

二、bufio包

bufio包是对IO的封装,可以操作文件等内容,同样可以用来接收键盘的输入,此时对象不是文件等,而是os.Stdin,也就是标准输入设备。

bufio包含了Reader、Writer、Scanner等对象,封装了很多对IO内容的处理方法,但应对键盘输入来说,使用Reader对象(或Scanner对象)即可,其他略。

通过创建Reader对象,并调用其Read*系列的方法即可:

创建Reader对象

reader := bufio.NewReader(os.Stdin)
  • 1

Read

func (b \*Reader) Read(p \[]byte) (n int, err error)

n, err := reader.Read(recv)
  • 1

这里不会阻塞等待键盘的输入,而是直接返回了,所以无法接受键盘输入。

ReadByte

func (b \*Reader) ReadByte() (c byte, err error)

用来接收一个byte类型,会阻塞等待键盘输入。

package main

import ( "bufio" "fmt" "os" )

func main() {


 reader := bufio.NewReader(os.Stdin)
 
 n, err := reader.ReadByte() // a
 
 fmt.Println("n = ", n)       // n = 97
 fmt.Println("string =", string(n)) // string = a
 fmt.Println("err = ", err)     // err = <nil>


}

ReadBytes

func (b \*Reader) ReadBytes(delim byte) (line \[]byte, err error)

该方法,输入参数为一个byte字符,当输入遇到该字符,会停止接收并返回。 接收的内容包括该停止字符以及前面的内容。

Tips* * Reader* *可以接收包含空格内容的字符串,而不进行分割,这是**bufio.Reader与fmt系的一大不同。

ReadLine

func (b \*Reader) ReadLine() (line \[]byte, isPrefix bool, err error)

ReadLine是一个低水平的行数据读取原语。大多数调用者应使用ReadBytes(’\n’)或ReadString(’\n’)代替,或者使用Scanner。

ReadRune

func (b \*Reader) ReadRune() (r rune, size int, err error)

rune用来处理unicode或utf-8字符,该函数可以接收该类字符,返回接收字符的rune值、size大小(即字节数)以及error。

ReadSlice

    func (b \*Reader) ReadSlice(delim byte) (line \[]byte, err error)

调用者应尽量使用ReadBytes或ReadString替代本法功法。

ReadString

func (b \*Reader) ReadString(delim byte) (line string, err error)

ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的错误。

4.测试

image.png

image.png

image.png

5.高质量编程

image.png

错误:

image.png

image.png

recover:

image.png

在Go语言中,recover()函数用于从panic状态中恢复并重新获得程序的控制权。当发生panic时,程序会立即停止执行当前的函数,并开始向上回溯执行函数调用栈,直到找到一个包含recover()函数的defer语句为止。

以下是一个使用recover()函数的示例:

package main

import (

"fmt"

)

func main() {

defer func() {

if r := recover(); r != nil {

fmt.Println("发生了一个panic:", r)

}

}()

causePanic()

fmt.Println("程序恢复正常")

}

func causePanic() {

panic("触发了一个panic")

}

在上面的示例中,causePanic()函数触发了一个panic,并且通过panic()函数传递了一个错误消息。在main()函数中,我们使用了一个defer语句来调用recover()函数来捕获panic,并输出错误消息。这样,即使发生了panic,程序也会继续执行,并打印出错误消息。

需要注意的是,recover()函数只能在defer语句中使用。在除defer语句之外的普通函数中调用recover()函数是无效的,并且会直接导致程序崩溃。此外,recover()函数只能捕获当前Goroutine中的panic,不能捕获其他Goroutine中的panic。}

6.性能优化

可视化工具:Benchmark

image.png

slice:

image.png

避免出现下面的情况(容量不够,复制一倍)

image.png

image.png

map内存预分配:

image.png

6.性能分析工具

image.png

image.png

pprof是一个性能分析工具,用于分析和诊断Go程序的性能问题。可以帮助找出程序中的瓶颈和性能瓶颈,并提供详细的性能报告。你可以使用pprof来分析CPU使用情况、内存分配和堆栈跟踪等方面的性能问题。要使用pprof,你需要在你的Go程序中导入net/http/pprof包,并在代码中添加相应的处理器。然后,你可以使用go tool pprof命令来收集和分析性能数据。例如,你可以使用go tool pprof http://localhost:6060/debug/pprof/profile命令来收集CPU使用情况的数据,并生成相应的报告。