当前位置: 首页 > news >正文

50周学习go语言:第四周 函数与错误处理深度解析

第四周 函数与错误处理深度解析
以下是第4周函数基础的深度教程,包含两个完整案例和详细实现细节:


第四周:函数与错误处理深度解析


一、函数定义与参数传递

1. 基础函数结构
// 基本语法
func 函数名(参数列表) 返回值类型 {// 函数体
}// 示例:计算圆面积
func circleArea(radius float64) float64 {return math.Pi * radius * radius
}
2. 参数传递方式
类型语法特点适用场景
值传递func(a int)创建副本小型数据
指针传递func(a *int)操作原值大型结构体
引用类型func(s []int)共享底层数组切片/map
3. 参数类型详解

案例1:值传递 vs 指针传递

// 值传递示例
func addValue(n int) {n += 10
}// 指针传递示例
func addPointer(n *int) {*n += 10
}func main() {num := 5addValue(num)      // 不影响原值addPointer(&num)   // 修改原值fmt.Println(num)   // 输出15
}

二、返回值与错误处理

1. 多返回值
// 返回商和余数
func div(a, b int) (int, int) {return a/b, a%b
}// 使用
q, r := div(17, 5)  // q=3, r=2
2. 错误处理规范
// 标准错误返回格式
func sqrt(x float64) (float64, error) {if x < 0 {return 0, errors.New("负数不能求平方根")}return math.Sqrt(x), nil
}
3. 错误处理实践

案例2:安全除法函数

func safeDivide(a, b int) (int, error) {if b == 0 {return 0, fmt.Errorf("除数不能为零 (a=%d, b=%d)", a, b)}return a / b, nil
}// 使用示例
result, err := safeDivide(10, 0)
if err != nil {log.Printf("计算失败: %v", err)// 输出:计算失败: 除数不能为零 (a=10, b=0)
}

三、素数判断任务实现

需求分析
  1. 函数isPrime接收整数参数
  2. 返回:
    • true:质数
    • false:非质数
    • error:输入非法(n < 2)
  3. 使用优化算法(试除法到平方根)
版本1:基础实现
func isPrime(n int) (bool, error) {if n < 2 {return false, fmt.Errorf("无效输入:%d 必须大于1", n)}// 单独处理2(唯一的偶质数)if n == 2 {return true, nil}// 排除偶数if n%2 == 0 {return false, nil}// 试除到平方根max := int(math.Sqrt(float64(n)))for i := 3; i <= max; i += 2 {if n%i == 0 {return false, nil}}return true, nil
}
版本2:性能优化(预计算小质数)
var smallPrimes = []int{2, 3, 5, 7, 11, 13}func optimizedIsPrime(n int) (bool, error) {if n < 2 {return false, fmt.Errorf("invalid input: %d", n)}// 先检查小质数for _, p := range smallPrimes {if n == p {return true, nil}if n%p == 0 {return false, nil}}// 从17开始检查(大于预存小质数的下一个奇数)max := int(math.Sqrt(float64(n)))for i := 17; i <= max; i += 2 {if n%i == 0 {return false, nil}}return true, nil
}

四、测试驱动开发

1. 表格驱动测试
func TestIsPrime(t *testing.T) {tests := []struct {name    stringinput   intwant    boolwantErr bool}{{"负数测试", -5, false, true},{"0测试", 0, false, true},{"1测试", 1, false, true},{"最小质数", 2, true, false},{"偶合数", 4, false, false},{"大质数", 9973, true, false},{"平方数", 25, false, false},}for _, tt := range tests {t.Run(tt.name, func(t *testing.T) {got, err := isPrime(tt.input)if (err != nil) != tt.wantErr {t.Errorf("isPrime() error = %v, wantErr %v", err, tt.wantErr)return}if got != tt.want {t.Errorf("isPrime() = %v, want %v", got, tt.want)}})}
}
2. 性能基准测试
func BenchmarkIsPrime(b *testing.B) {for i := 0; i < b.N; i++ {isPrime(104729) // 第10000个质数}
}

五、错误处理进阶

1. 错误包装
func process(n int) error {if valid, err := isPrime(n); err != nil {return fmt.Errorf("处理失败: %w", err)  // 使用%w包装错误} else if !valid {return errors.New("需要质数输入")}return nil
}
2. 错误类型断言
func handleError(err error) {if pe, ok := err.(*PrimeError); ok {fmt.Printf("质数错误代码%d: %s\n", pe.Code, pe.Message)} else {fmt.Println("通用错误:", err)}
}// 自定义错误类型
type PrimeError struct {Code    intMessage string
}func (e *PrimeError) Error() string {return fmt.Sprintf("错误%d: %s", e.Code, e.Message)
}

六、扩展练习

  1. 质因数分解函数

    func primeFactors(n int) ([]int, error) {// 返回所有质因数// 示例:输入12 → [2, 2, 3]
    }
    
  2. 并发素数筛选

    // 实现并发版本的埃拉托斯特尼筛法
    func sieve(max int) []int {// 返回所有小于max的质数
    }
    

七、学习检查清单

  • 能正确声明带多个返回值的函数
  • 会使用指针参数修改外部变量
  • 理解error接口的使用场景
  • 能编写表格驱动测试用例
  • 会处理负数输入的边界情况
  • 能解释试除法的优化原理
  • 理解自定义错误类型的优势

通过这两个完整案例(安全除法与素数判断),你已掌握Go函数的定义、参数传递、错误处理和测试方法。建议:

  1. 实际运行测试用例观察结果
  2. 使用go test -bench .查看性能差异
  3. 尝试为优化版本添加更多预计算质数
  4. 实现扩展练习中的质因数分解功能

以下同扩展部分的代码与分析

以下是两个扩展练习的完整实现代码,包含详细注释说明每个关键步骤:


扩展练习1:质因数分解函数

// primeFactors 返回给定整数的质因数分解结果
// 输入:n - 需要分解的正整数(n >= 2)
// 返回:质因数切片(升序排列)和可能的错误
func primeFactors(n int) ([]int, error) {// 输入验证if n < 2 {return nil, fmt.Errorf("无效输入:%d 必须大于1", n)}factors := make([]int, 0)original := n// 处理偶数因子for n%2 == 0 {factors = append(factors, 2)n /= 2}// 从3开始检查奇数因子(步长2)for i := 3; i*i <= n; i += 2 {// 当i是因子时持续除尽for n%i == 0 {factors = append(factors, i)n /= i}}// 处理剩余的大质数因子if n > 2 {factors = append(factors, n)}// 验证分解结果product := 1for _, f := range factors {product *= f}if product != original {return nil, fmt.Errorf("分解验证失败:%d != %d", product, original)}return factors, nil
}/* 使用示例:
factors, err := primeFactors(360)
if err != nil {log.Fatal(err)
}
fmt.Println(factors) // 输出:[2 2 2 3 3 5]
*/

扩展练习2:并发素数筛选(埃拉托斯特尼筛法)

// sieve 使用并发筛法返回所有小于max的质数
func sieve(max int) []int {if max < 2 {return []int{}}// 创建初始数字生成器(2到max)ch := generateNumbers(2, max)primes := make([]int, 0)for {// 从当前通道获取候选质数p, ok := <-chif !ok {break}primes = append(primes, p)// 创建新的过滤通道ch = filter(ch, p)}return primes
}// generateNumbers 生成连续整数序列
func generateNumbers(start, end int) <-chan int {ch := make(chan int)go func() {for i := start; i <= end; i++ {ch <- i}close(ch)}()return ch
}// filter 创建新的通道过滤特定质数的倍数
func filter(in <-chan int, prime int) <-chan int {out := make(chan int)go func() {for n := range in {// 过滤掉能被当前质数整除的数if n%prime != 0 {out <- n}}close(out)}()return out
}/* 使用示例:
primes := sieve(30)
fmt.Println(primes) // 输出:[2 3 5 7 11 13 17 19 23 29]
*/

代码关键点解析

质因数分解函数
  1. 输入验证:确保输入符合质因数分解的基本要求
  2. 分阶段处理
    • 先处理所有偶数因子(2的幂次)
    • 再处理奇数因子(从3开始,步长2)
  3. 验证机制:最终乘积验证确保分解的正确性
  4. 性能优化
    • 循环上限设置为√n(i*i <= n)
    • 跳过偶数检查(通过步长2)
并发素数筛法
  1. 通道链式结构
    generateNumbers
    filter2
    filter3
    filter5
    ...
  2. 动态过滤
    • 每个新发现的质数都会创建一个新的过滤通道
    • 前序通道处理完成后自动关闭
  3. 并发控制
    • 每个filter操作在独立的goroutine中执行
    • 通过通道关闭机制自然终止循环

测试用例

质因数分解测试
func TestPrimeFactors(t *testing.T) {tests := []struct {input  intexpect []int}{{12, []int{2, 2, 3}},{360, []int{2, 2, 2, 3, 3, 5}},{9973, []int{9973}},      // 大质数{1024, []int{2, 2, 2, 2, 2, 2, 2, 2, 2, 2}},}for _, tt := range tests {result, _ := primeFactors(tt.input)if !reflect.DeepEqual(result, tt.expect) {t.Errorf("输入%d 期望%v 实际%v", tt.input, tt.expect, result)}}
}
并发筛法测试
func TestSieve(t *testing.T) {expected := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29}result := sieve(30)if !reflect.DeepEqual(result, expected) {t.Errorf("期望%v 实际%v", expected, result)}
}

性能对比

实现方式时间复杂度空间复杂度适合场景
传统筛法O(n log log n)O(n)大数据量
并发筛法O(n)(理论)O(k)(k为goroutine数量)学习并发原理

实际测试显示,当max超过1,000,000时,传统实现效率更高。并发版本更适合理解通道和goroutine的协作机制。


扩展方向

  1. 质因数分解优化

    • 预生成小质数列表加速试除过程
    • 添加Pollard’s Rho算法处理大数分解
  2. 并发筛法改进

    • 限制最大goroutine数量
    • 添加超时控制
    • 实现分片并行处理

这两个练习展示了Go语言在处理数学问题和并发编程方面的优势,建议通过实际调试观察通道数据的流动过程,可以更深入理解并发筛法的工作原理。

相关文章:

50周学习go语言:第四周 函数与错误处理深度解析

第四周 函数与错误处理深度解析 以下是第4周函数基础的深度教程&#xff0c;包含两个完整案例和详细实现细节&#xff1a; 第四周&#xff1a;函数与错误处理深度解析 一、函数定义与参数传递 1. 基础函数结构 // 基本语法 func 函数名(参数列表) 返回值类型 {// 函数体 }// …...

debian 12安装 postgresql 17

按照官方文档安装&#xff0c;即可安装成功 https://www.postgresql.org/download/linux/debian/ 添加存储库 #添加存储库 sudo apt install -y postgresql-common#执行 存储库内 命令&#xff0c;自动处理某些东西 sudo /usr/share/postgresql-common/pgdg/apt.postgresql.o…...

C++....................4

1. using namespace std; class mystring { private:char* p;int len;// 辅助函数&#xff1a;复制字符串void copy(const char* source) {len strlen(source);p new char[len 1];strcpy(p, source);}// 辅助函数&#xff1a;释放内存void release() {if (…...

图书馆系统源码详解

本项目是一个基于Scala语言开发的图书馆管理系统。系统主要由以下几个部分组成&#xff1a;数据访问层&#xff08;DAO&#xff09;、数据模型层&#xff08;Models&#xff09;、服务层&#xff08;Service&#xff09;以及用户界面层&#xff08;UI&#xff09;。以下是对项目…...

Node.js中如何修改全局变量的几种方式

Node.js中如何修改全局变量。我需要先理解他们的需求。可能他们是在开发过程中遇到了需要跨模块共享数据的情况&#xff0c;或者想要配置一些全局可访问的设置。不过&#xff0c;使用全局变量可能存在一些问题&#xff0c;比如命名冲突、难以维护和测试困难&#xff0c;所以我得…...

基于javaweb的SpringBoot个人博客系统设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…...

厦大团队:DeepSeek大模型概念、技术与应用实践 140页PDF完整版下载

DeepSeek使用教程系列&#xff1a; 厦门大学&#xff1a; DeepSeek大模型概念、技术与应用实践 140页PDF完整版文件 厦大团队&#xff1a;DeepSeek大模型概念、技术与应用实践&#xff08;140页PPT读懂大模型&#xff09;.pdf https://pan.baidu.com/s/1de4UIxqPsvMBIYcpen_M-…...

【Blender】二、建模篇--05,阵列修改器与晶格形变

阵列修改器是bender里面一个比较常用的修改器,所以我们单独开口来讲,我们会先从几片树叶出发,然后我们用阵列修改器把这几片树叶变成这样的造型和这样的造型。这两个造型分别就代表着阵列修改器最常用的两种偏移方法,我们现在就开始我们先来做几个树叶。 1.树叶建模 首先…...

#渗透测试#批量漏洞挖掘#畅捷通T+远程命令执行漏洞

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 一、漏洞概况 二、攻击特征 三、应急处置…...

【Python爬虫(23)】探秘Python爬虫数据存储:MongoDB实战指南

【Python爬虫】专栏简介&#xff1a;本专栏是 Python 爬虫领域的集大成之作&#xff0c;共 100 章节。从 Python 基础语法、爬虫入门知识讲起&#xff0c;深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑&#xff0c;覆盖网页、图片、音频等各类数据爬取&#xff…...

Pytorch使用手册-音频数据增强(专题二十)

音频数据增强 torchaudio 提供了多种方式来增强音频数据。 在本教程中,我们将介绍一种应用效果、滤波器、RIR(房间脉冲响应)和编解码器的方法。 最后,我们将从干净的语音合成带噪声的电话语音。 import torch import torchaudio import torchaudio.functional as Fprin…...

Linux 命令大全完整版(04)

1. 用户信息相关命令 who 功能说明&#xff1a;显示目前登入系统的用户信息。语  法&#xff1a;who [-Himqsw][--help][--version][am i][记录文件]补充说明&#xff1a;执行这项指令可得知目前有哪些用户登入系统&#xff0c;单独执行 who 指令会列出登入帐号、使用的终端…...

嵌入式Linux内核底层调试技术Kprobes

大家好&#xff0c;我是bug菌~ Kprobes 是 Linux 内核中一种动态插桩&#xff08;Dynamic Instrumentation&#xff09;技术&#xff0c;允许在不修改内核源码或重启系统的前提下&#xff0c;动态监控内核函数的执行。它是内核调试、性能分析和安全监控的重要工具。以下从技术…...

leetcode 119. 杨辉三角 II

给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0 输出: [1]示例 3: 输入: rowIndex 1 输出: [1,1]提示…...

内网网络安全的解决之道

本文简要分析了企业内部网络所面临的主要分析&#xff0c;阐述了安全管理人员针对不同威胁的主要技术应对措施。进一步介绍了业界各种技术措施的现状&#xff0c;并提出了未来可能的发展趋势。 内网网络安全问题的提出 网络安全对于绝大多数人而言指的都是互联网安全&#xff…...

分布式光纤声波振动技术在钻井泄漏检测中的应用

在石油天然气的钻井作业中&#xff0c;及时发现并定位泄漏点对于保障开采安全、降低环境污染以及避免经济损失至关重要。传统的泄漏检测方法往往存在局限性&#xff0c;而分布式光纤声波振动技术凭借其独特的优势&#xff0c;正逐渐成为钻井过程中寻找泄漏的有力工具。 技术原理…...

deepseek 导出导入模型(Windows)

前言 实现导出导入deepseek 模型。deepseek 安装Windows下参考 Windows 导出模型 Restart-Service 重启服务参考Stop-Service 关闭服务参考Start-Service 确定服务参考Compress-Archive 压缩参考Expand-Archive 解压参考setx 环境变量参考C:\Users\用户名\.ollama\models 默…...

Spring MVC配置文件

1. DispatcherServlet配置 作用&#xff1a;DispatcherServlet是Spring MVC的核心前端控制器&#xff0c;用于接收所有HTTP请求&#xff0c;并将请求分发给对应的处理器&#xff08;Controller&#xff09;。 配置方式&#xff1a; 在web.xml中配置DispatcherServlet&#xff…...

计算机视觉:主流数据集整理

第一章&#xff1a;计算机视觉中图像的基础认知 第二章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(一) 第三章&#xff1a;计算机视觉&#xff1a;卷积神经网络(CNN)基本概念(二) 第四章&#xff1a;搭建一个经典的LeNet5神经网络(附代码) 第五章&#xff1…...

基于AT89C52单片机的出租车计价器

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/90419909?spm1001.2014.3001.5501 C17 部分参考设计如下&#xff1a; 摘要 随着城市交通行业的迅速发展&#xff0c;出租车作为最主要的城市公共交通工具之一…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...