Golang笔记(下)

news2024/11/25 16:50:24

Golang学习笔记(下)

前篇:Golang学习笔记(上)

在这里插入图片描述

十四、错误处理

14.1使用error类型
func New(text string) error

例子:

package main

import (
    "errors" // 导入errors包
    "fmt"
)

func main() {
    var number, divisor int
    fmt.Println("请输入一个整数作为分子:")
    fmt.Scan(&number)
    fmt.Println("请输入一个整数作分母:")
    fmt.Scan(&divisor)
    result, err := divide(number, divisor)
    fmt.Println("result", result)
    if err != nil {
        fmt.Println(err)
    }
}

// 除法函数,参数number是分子,参数divisor是分母
func divide(number, divisor int) (float32, error) {
    if divisor == 0 {
        // 返回多值数据
        return 0.0, errors.New("分母不能为0")
    }
    return float32(number / divisor), nil
}

14.2错误信息格式化

使用fmt包中的Errorf函数

func divide(number, divisor int) (float32, error) {
    if divisor == 0 {
        // 返回多值数据
        error := fmt.Errorf("您输入的分母是:%d", divisor)
        return 0.0, error
    }
    return float32(number / divisor), nil
}

14.3自定义错误类型
// 自定义错误类型
type error interface {
    Error() string
}

举例

package main

import (
    "fmt"
)

// 自定义错误类型结构体
type DivisionByZero struct {
    // 错误信息
    message string
}

// 实现error接口的Error()方法
func (d DivisionByZero) Error() string {
    return d.message
}

// 除法函数,参数number是分子,参数divisor是分母
func divide(number, divisor int) (float32, error) {
    if divisor == 0 {
        // 创建一个DivisionByZero错误实例,并返回
        return 0.0, DivisionByZero{message: "除数不能为0"}
    }
    return float32(number) / float32(divisor), nil
}

func main() {
    var number, divisor int
    fmt.Println("请输入一个整数作为分子:")
    fmt.Scan(&number)
    fmt.Println("请输入一个整数作分母:")
    fmt.Scan(&divisor)
    result, err := divide(number, divisor)
    if err != nil {
        // 打印具体的错误信息
        fmt.Println("发生错误:", err.Error())
        return
    }
    fmt.Printf("result: %f\n", result)
}

14.4错误机制
  • go语言提供了panic()和recover()函数

  • defer关键字实现错误处理

延迟执行

defer语句用来在函数最终要返回前被执行,用来释放资源,在错误处理的过程中,一个非常重要的环节就资源释放,无论执行成功,还是执行错误,都应该保证释放这些资源,此时可以使用defer关键字延迟执行,保证在程序运行完成之前释放资源。

当有多个defer语句时,defer语句遵守后进先出原则。

进入宕机状态

用于触发一个运行时错误。

  1. 自动进入当即状态,当发生运行期错误时自动进入。

  2. 手动触发,程序员可以根据自己的需要通过panic()函数可以手动触发宕机状态。

package main

import "fmt"

func main() {
    intSclical := []int{1, 2, 3}
    // 下标月结引发的宕机
    fmt.Println(intSclical[3])
}

输出:

D:Go/bin/go.exe run panic.go [F:/Code/Go/src]
panic: runtime error: index out of range [3] with length 3

goroutine 1 [running]:
main.main()
    F:/Code/Go/src/panic.go:8 +0x15
exit status 2
错误: 进程退出代码 1.

手动宕机

package main

import "fmt"

func main() {
    intSclical := []int{1, 2, 3}
    // 下标超出索引范围,自动引发的宕机
    // fmt.Println(intSclical[3])
    var index int = -1
    fmt.Println("请输入下标索引: ")
    fmt.Scan(&index)
    if index > 3 {
        panic("索引超出范围")
    } else {
        fmt.Println("输出元素为:", intSclical[index])
    }
}

14.5从宕机状态恢复

使用recover()函数从宕机状态恢复

package main

import (
    "fmt"
)

// 除法函数,参数number是分子,参数divisor是分母
func divide(number, divisor int) (float32, bool) {
    if divisor == 0 {
        // 触发panic,表示发生了严重的错误
        panic("除数不能为0")
    }
    return float32(number) / float32(divisor), true
}

func main() {
    var number, divisor int
    fmt.Println("请输入一个整数作为分子:")
    fmt.Scan(&number)
    fmt.Println("请输入一个整数作分母:")
    fmt.Scan(&divisor)

    // 使用defer和recover来捕获panic
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("程序遇到严重错误:", r)
        }
    }()

    result, ok := divide(number, divisor)
    if !ok {
        // 实际上,由于我们使用了panic,这里的ok检查是多余的
        // 因为panic会导致程序停止执行,不会到达这里
        fmt.Println("发生错误,无法执行除法")
        return
    }
    fmt.Printf("result: %f\n", result)
}

十五、并发编程

15.1进程
  • 一个进程就是一个执行中的程序

  • 每一个进程都有自己独立的一块内存空间

  • 每一个进程都有一组系统资源

15.2线程
  • 线程和进程都是一段完成特定功能的代码。

  • 它们都是程序中的单个顺序控制流程

  • 多个线程共享一块内存空间和一组系统资源。

  • 在切换不同线程之间时,系统的开销比切换进程要小得多,称为轻量级进程。

  • 一个进程可以包含多个线程。

15.3协程
  • 协程(Goroutines)是一种轻量级的线程。

  • 不阻塞线程,但可以挂起的计算过程。

  • 挂起几乎没有开销。

  • 底层库处理一部阻塞任务。

  • 协程代码流程顺序,无需大量的回调函数。

  • 类似同步代码,已于理解、调试和开发。

15.4创建协程
  • go语言的并发编程时通过协程(Goroutines)实现的。

  • 在Go中创建协程很简单,只要在函数或方法前加go关键字,则会创建一个新协程。

创建协程示例

package main

import "fmt"

func display(str string) {
    fmt.Println(str)
}

func main() {
    // 创建协程,异步调用函数
    go display("welcome to Beijing!")
    // 正常调用函数
    display("Hello World")
}

每次运行的结果不一致,原因

在这里插入图片描述

也就是说主线程会调用display(“Hello World!”)和协程中的dispaly(“Welcome to Beijing!”),这两调用的过程时随机的,谁先谁后不一定。

两个协程执行是异步的,哪个先执行,哪个后执行,都是不确定的,中就是并发程序的特点。

15.5通道

在这里插入图片描述

声明通道

  1. 使用chan关键字声明,语法如下:
    var Channel_name chan Type

  2. 使用make()函数创建通道,语法如下:
    channel_name := make(chan Type)

举例


package main

import "fmt"

func main() {
	// 1.使用chan声明通道
	var mychannel1 chan int
	fmt.Printf("mychannel1:%V\n", mychannel1)
	fmt.Printf("mychannel1类型:%T\n", mychannel1)

	// 2.通过make()函数创建通道
	mychannel2 := make(chan int)
	fmt.Printf("mychannel2:%v\n", mychannel2)
	fmt.Printf("mychannel类型:%T\n", mychannel2)
}

发送和接收数据

  1. 向通道发生数据语法如下:

    mychannel<-data

  2. 从通道接收数据语法如下:

    接收数据变量:=<-mychannel

关闭通道

使用close()函数关闭通道。

示例代码:

package main

import "fmt"

func display(chstr chan string) {
	// 向通道发生数据
	chstr <- "Hello,World!"
}

func main() {
	// 1.使用chan声明通道
	var mychannel1 chan int
	fmt.Printf("mychannel1:%V\n", mychannel1)
	fmt.Printf("mychannel1类型:%T\n", mychannel1)

	// 2.通过make()函数创建通道
	mychannel2 := make(chan int)
	fmt.Printf("mychannel2:%v\n", mychannel2)
	fmt.Printf("mychannel类型:%T\n", mychannel2)

	// 发生和接收数据
	message := make(chan string)
	// 启动协程
	go display(message)
	// 从通道中接收数据
	msg := <-message
	fmt.Println(msg)

	// 关闭通道
	ch := make(chan int, 3)
	ch <- 2
	ch <- 3
	close(ch)
	fmt.Println("关闭通道")

	// 试图向关闭的通道发生数据(error)
	// ch <- 4
	fmt.Println("关闭通道")

	// 试图从关闭的通道中接收数据
	msg1 := <-ch
	fmt.Println("从通道中接收数据")
	mgs2, ok := <-ch
	fmt.Println("从通道中接收的数据:", msg)
	fmt.Println(ok)
	fmt.Println(msg1, mgs2)
}

遍历通道

package main

import "fmt"

// 遍历通道
func producer(chnl chan int) {
	for i := 0; i < 10; i++ {
		chnl <- i
	}
}

func main() {
	// 创建int类型通道
	ch := make(chan int)
	// 创建协程
	go producer(ch)
	// 遍历从通道中接收的数据
	for v := range ch {
		fmt.Println("接受:", v)
	}
}

单向通道和双向通道

channel_name := make(<-chan Typr) // 只接收数据

channel_name := make(chan<- Typr) // 只发送数据

package main

import "fmt"

func main() {
	// 创建只接收的数据通道
	mychannel1 := make(<-chan string)

	// 创建只发送的数据通道
	mychannel2 := make(chan<- string)
	fmt.Printf("mychannel1:%v\n", mychannel1)
	fmt.Printf("mychannel1类型:%T\n", mychannel1)
	fmt.Printf(<-mychannel2) // error:invalid operation: cannot receive from send-only channel mychannel2 (variable of type chan<- string)

	fmt.Printf("mychannel2:%v\n", mychannel2)
	fmt.Printf("mychannel2类型:%T\n", mychannel2)
}	

缓冲区通道

  • 无缓冲区通道

无缓冲区通道,通道中无法存储数据。发送和接收数据时是同步的,无缓冲区通道使用make()函数创建,自谦创建的都是无缓冲区通道。

有两种情况下会造成程序的阻塞:

  1. 当一个协程A将数据发送给通道时,其他协程还未接收数据时,协程A被迫阻塞,知道其他协程接收数据后,协程A才能继续执行。

  2. 当一个协程A试图从通道接收数据时,如果通道A中没有数据,则会等待其他协程发送,知道其他协程发送数据后,协程A才能继续执行。

  • 有缓冲区通道

有缓冲区通道,通道中可以存储数据,发送和接受时是异步的,创建有缓冲区的通道可以使用make(chan Type int)函数,

该函数的第一个参数是通道中的数据类型,第二个参数是设置缓冲区的大小。

在这里插入图片描述

15.6使用select语句

语法:

select {
    case 通道1:
        语句组1
    case 通道2:
        语句组2
    ...
    case 通道n:
        语句组n
    default:
        语句组n+1
}

举例:

package main

import (
	"fmt"
	"time"
)

func process(ch chan string) {
	time.Sleep(5 * time.Second)
	ch <- "Hello World."
}

func main() {
	// 声明两个通道c1和c2
	c1 := make(chan string)
	c2 := make(chan string)

	// 协程处理匿名函数
	go func() {
		// 休眠1秒
		time.Sleep(1 * time.Second)
		c1 <- "one"
	}()
	// 协程处理匿名函数
	go func() {
		// 休眠2秒
		time.Sleep(2 * time.Second)
		// 发送数据
		c2 <- "two"
	}()

	// 循环遍历从通道中接收的数据
	for i := 0; i < 2; i++ {
		select {
		// 从c1通道接收数据
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		// 从c2通道接收数据
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}

	// default
	ch := make(chan string)
	// 启动协程
	go process(ch)
	// 一直遍历从通道中取数据
	for {
		time.Sleep(1 * time.Second)
		select {
		case v := <-ch:
			fmt.Println("接收数据:", v)
			return
		default:
			fmt.Println("没有数据接收。")
		}
	}
}
	for {
		time.Sleep(1 * time.Second)
		select {
		case v := <-ch:
			fmt.Println("接收数据:", v)
			return
		default:
			fmt.Println("没有数据接收。")
		}
	}
}

十六、正则表达式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1580412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网页版五子棋对战实现和自动化测试

文章目录 前言一、项目描述项目演示链接 二、实现的功能与操作1.登录注册2.游戏大厅线程安全问题多开处理 3.五子棋对战 三、项目测试1.测试用例2.测试技术点3.部分测试用例展示&#xff08;1&#xff09;注册页面&#xff08;2&#xff09;登录页面&#xff08;3&#xff09;游…

ChatGPT与生成式AI:教育领域内新的浪潮与挑战

随着ChatGPT和其他生成式AI技术&#xff0c;如GPT-3.5、GPT-4的出现&#xff0c;我们正见证教育领域一场前所未有的变革浪潮。这些技术不仅推动了教育方式的进步&#xff0c;也为学习者带来了全新的机遇和挑战。 NO.1教育变革的新浪潮 生成式AI技术&#xff0c;特别是ChatGPT&…

【Nature Electronics】二维钙钛矿氧化物SNO作为high-κ栅介质的应用

【Li, S., Liu, X., Yang, H. et al. Two-dimensional perovskite oxide as a photoactive high-κ gate dielectric. Nat Electron 7, 216–224 (2024). https://doi.org/10.1038/s41928-024-01129-9】 概括总结&#xff1a; 本研究探讨了二维钙钛矿氧化物Sr2Nb3O10&#xf…

我们有了统一的Domino应用市场

大家好&#xff0c;才是真的好。 和大家一样&#xff0c;刚休假回来就发现HCL又上新了。这回是个大消息&#xff0c;直接上了一个Notes/Domino应用市场&#xff0c;地址是https://hclsofy.com/domino。 截至本篇写作时&#xff0c;提交到该市场的Notes/Domino相关扩展工具和应…

ATM04-6P 安费诺汽车连接器6芯压线端子胶壳

ATM04-6P是一款压线端子胶壳&#xff0c;属于Amphenol&#xff08;安费诺&#xff09;品牌 ATM04-6P 规格信息&#xff1a; 制造商:Amphenol 产品种类:汽车连接器 RoHS:是 产品:Connectors 位置数量:6 Position 型式:Receptacle (Female) 线规量程:22 AWG to 16 AWG 系列:ATM 颜…

layui后台框架,将左侧功能栏目 集中到一个页面,通过上面的tab切换 在iframe加载对应页面

实现上面的 功能效果。 1 html代码 <form class"layui-form layui-form-pane" action""><div class"layui-tab" lay-filter"demo"><ul class"layui-tab-title"><li id"a0" class"lay…

常见的mq产品和优点

常见的mq产品和优点 一、什么是mq? MQ全称 Message Queue&#xff08;消息队列&#xff09;&#xff0c;是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信&#xff0c;解耦。 二、常见的mq产品 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq …

基于51单片机轮胎胎压监测系统—数码管显示

基于51单片机轮胎胎压监测系统 &#xff08;仿真&#xff0b;程序&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.MPX4115压力传感器胎压检测&#xff1b; 2.ADC0832进行模数转换后&#xff0c;51单片机处理控制&#xff1b; 3.数码管显示胎压&#xff…

谷歌留痕霸屏要怎么做?

谷歌留痕霸屏&#xff0c;就是让你的网站或者页面在谷歌搜索结果里尽可能多地出现&#xff0c;就像是在你的潜在客户眼前留下深刻印象一样&#xff0c;你要做的就是在一些高权重平台发布有价值的信息&#xff0c;同时巧妙地留下你的品牌名、产品名或者任何你想要推广的关键词&a…

Selenium+Chrome Driver 爬取搜狐页面信息

进行selenium包和chromedriver驱动的安装 安装selenium包 在命令行或者anaconda prompt 中输入 pip install Selenium 安装 chromedriver 先查看chrome浏览器的版本 这里是 123.0.6312.106 版 然后在http://npm.taobao.org/mirrors/chromedriver/或者https://googlechrom…

位图/矢量图/GIF/PNG/JPEG/WEBP一网打尽

❝ 想把一件事做好&#xff0c;那就先把眼前的小事攻克 ❞ 大家好&#xff0c;我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder。 前言 最近&#xff0c;在做项目资源打包优化。如果大家做过类似的工作&#xff0c;在操作过程中&#xff0c;想必有一个…

实战:gcc-11.4.0编译wxWidgets-2.8.12的xrc演示例程

由于我上次编译安装的wxWidgets-2.8.12的abi是1009的&#xff0c;现在编译xrc演示程序也要使用09的abi才能正常运行。 到sourceforge去下载wxGTK-2.8.12&#xff0c;然后解压。 上述的文件夹中有msvc的make, 有watcom的makefile, 还有 unx 的makefile, 在mint-21.3上就用unx这…

配置VM开机自启动

1. 在此电脑-右键选择“管理”-服务和应用程序-服务中找到VMware Workstation Server服务&#xff08;新版名称也可能是VMware自启动服务&#xff0c;自己找一下&#xff0c;服务属性里有描述信息的&#xff09;&#xff0c;将其启用并选择开机自动启动 新版参考官方文档&…

抖音变现项目有哪些?来这几个资源网站看看吧

做短视频就像是在做一道菜&#xff0c;你得有那么几个秘密武器&#xff0c;才能让你的作品从众多视频中脱颖而出。我这个视频剪辑界的“烹饪大师”&#xff0c;今天就来给大家分享一下我的厨房秘籍——那些让我视频大放异彩的素材网站。九才素材网&#xff1a; 说起九才素材网…

吴恩达深度学习笔记:深层神经网络(Deep Neural Networks)4.1-4.4

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第四周&#xff1a;深层神经网络(Deep Neural Networks)4.1 深层神经网络&#xff08;Deep L-layer neural network&#xff09;4.2 前向传播和反向传播&#xff08;Forward and backward pro…

3dmax渲染十几个小时怎么办?3dmax怎么多机渲染

当使用3ds Max进行渲染作业时&#xff0c;如果发现单张图像的渲染时间长达十数小时&#xff0c;这可能是由于计算机硬件配置较低或渲染场景过于复杂所致。为了缩短渲染时间并提高效率&#xff0c;我们可以考虑采用多台计算机进行协同渲染。下面&#xff0c;让我们一起探讨如何通…

Webots常用的执行器(Python版)

文章目录 1. RotationalMotor2. LinearMotor3. Brake4. Propeller5. Pen6. LED 1. RotationalMotor # -*- coding: utf-8 -*- """motor_controller controller."""from controller import Robot# 实例化机器人 robot Robot()# 获取基本仿真步长…

【编译原理】Antlr 入门使用

前面文章我们学习了编译器前端的词法和语法分析工具&#xff0c;本篇我们来看看如何借助 Antlr 工具&#xff0c;快速生成词法和语法分析代码。 一、安装 mac 环境&#xff1a; 1&#xff09;安装 brew install antlr2&#xff09;配置 classpath &#xff08;把 Antlr 的 J…

MySQL -- 07_最流行的查询需求分析(一些分组排序查询、开窗函数 dense_rank、distinct 去重函数 等~)

目录 最流行的查询需求分析07演示数据准备的SQL需求演示36、查询每一门课程成绩都在70分以上的姓名、课程名称和分数group by min() in() 函数 37、查询不及格的课程及学生普通表连接查询 38、查询课程编号为01语文且课程成绩在80分以上的学生的学号和姓名普通表连接查询 39、…

使用axios进行前后端数据传输

最近在和朋友合作写一个新的项目&#xff0c;前后端进行了分离&#xff0c;既然是分离的&#xff0c;肯定需要交互&#xff0c;今天这篇文章详细介绍一下数据交互的一种常见方式&#xff1a;使用axios,希望对大家有所帮助。 前端&#xff1a;以LoginPage.vue登录页面为例&…