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

【Go语言基础【13】】函数、闭包、方法

文章目录

  • 零、概述
  • 一、函数基础
    • 1、函数基础概念
    • 2、参数传递机制
    • 3、返回值特性
      • 3.1. 多返回值
      • 3.2. 命名返回值
      • 3.3. 错误处理
  • 二、函数类型与高阶函数
    • 1. 函数类型定义
    • 2. 高阶函数(函数作为参数、返回值)
  • 三、匿名函数与闭包
    • 1. 匿名函数(Lambda函数)
    • 2. 闭包(Closure)
  • 四、内置函数
  • 五、方法(让go有了面向对象的特性)

零、概述

函数核心特性速查

特性说明
多返回值支持同时返回结果和错误(如(int, error)
可变参数通过...Type定义,本质为切片([]Type
函数类型可定义函数类型(如type FuncType func(int) bool
闭包匿名函数捕获外部变量,保持状态
方法绑定到结构体的函数,通过接收者参数(func (t Type) Method())定义
内置函数lenmakeappend等预定义函数,直接使用

最佳实践

  1. 错误处理
    • 多返回值中优先返回错误(如func() (Result, error))。
    • 使用if err != nil判断错误,避免忽略重要异常。
  2. 减少值拷贝
    • 传递大结构体时使用指针(*T),避免性能损耗。
    • 切片、map等引用类型默认传递指针,无需额外处理。
  3. 函数职责单一
    • 每个函数专注完成一个独立功能,符合单一职责原则。
    • 避免函数过长(建议不超过50行),复杂逻辑拆分为子函数。

 

一、函数基础

1、函数基础概念

Go语言中的函数可赋值给变量、作为参数传递或作为返回值,极大提升了编程灵活性。

1. 函数定义语法

func 函数名(参数列表) (返回值列表) {函数体return 返回值
}
  • 参数列表:参数类型需后置,连续相同类型可合并声明。
    func sum(x, y int) int { // x, y 均为 int 类型return x + y
    }
    
  • 返回值列表:可无返回值或多返回值(用括号包裹),支持命名返回值。
    func div(x, y int) (int, error) { // 多返回值if y == 0 {return 0, errors.New("除数不能为0")}return x / y, nil
    }
    

 

2、参数传递机制

1.1. 值传递

  • 机制:传递参数的副本,函数内修改不影响原始值。
  • 适用场景:小数据类型(如intstring)或无需修改原始值的场景。
    func modifyValue(x int) {x = 100 // 仅修改副本
    }
    func main() {a := 20modifyValue(a) // a 仍为 20
    }
    

1.2. 引用传递

  • 机制:传递参数的地址(通过指针*T),函数内可修改原始值。
  • 适用场景:大数据类型(如结构体)或需修改原始值的场景。
    func modifyPointer(x *int) {*x = 100 // 修改原始值
    }
    func main() {a := 20modifyPointer(&a) // a 变为 100
    }
    

1.3. 可变参数
语法:通过...Type定义可变参数,本质为切片。

func sum(nums ...int) int { // nums 类型为 []inttotal := 0for _, num := range nums {total += num}return total
}
func main() {sum(1, 2, 3) // 等价于 sum([]int{1,2,3})
}

 

3、返回值特性

3.1. 多返回值

用途:同时返回结果和错误(Go语言的惯用模式)。

func readFile(path string) ([]byte, error) {data, err := os.ReadFile(path)return data, err
}

3.2. 命名返回值

语法:为返回值命名,函数体可直接使用(类似变量声明)。

func calculate(x, y int) (sum, product int) { // 命名返回值sum = x + yproduct = x * yreturn // 隐式返回 sum, product
}

3.3. 错误处理

丢弃返回值:用_忽略不关心的返回值。

data, _ := readFile("data.txt") // 忽略错误

 

二、函数类型与高阶函数

1. 函数类型定义

在Go语言中,函数类型定义是指为一种特定的函数签名创建一个自定义类型名称。这样可以让具有相同签名的函数共享同一个类型(有点面向接口开发的感觉)。

type Calculator func(int, int) int // 定义函数类型// 这些函数都符合Calculator类型的签名
func add(x, y int) int { return x + y }
func subtract(x, y int) int { return x - y }
func multiply(x, y int) int { return x * y }
func divide(x, y int) int { return x / y }

 

例题:

package mainimport "fmt"type Calculator func(int, int) intfunc add(x, y int) int      { return x + y }
func subtract(x, y int) int { return x - y }// 使用函数类型作为参数
func calculate(calc Calculator, a, b int) int {return calc(a, b)
}// 使用函数类型作为变量
func main() {var myCalc CalculatormyCalc = addfmt.Println(myCalc(5, 3)) // 输出: 8myCalc = subtractfmt.Println(myCalc(5, 3)) // 输出: 2// 作为参数传递result := calculate(add, 10, 5)fmt.Println(result) // 输出: 15
}

 

2. 高阶函数(函数作为参数、返回值)

函数作为参数

func operate(x, y int, fn Calculator) int { // 接收函数作为参数
// 作为参数的函数,来处理参数return fn(x, y)
}
func main() {result := operate(10, 5, add) // 调用 add 函数
}

 
函数作为返回值
在Go语言中,函数可以作为返回值,这使得我们可以创建闭包。闭包是一个函数,它可以捕获并记住其所在环境中的变量。

func makeAdder(n int) Calculator { // 返回函数return func(x int) int {return x + n}
}
func main() {add5 := makeAdder(5) // add5(3) 返回 8
}

 

三、匿名函数与闭包

1. 匿名函数(Lambda函数)

  • 无名称函数,可直接定义和调用
 // 赋值给变量greet := func() {fmt.Println("Hello, Go!")}greet() // 调用匿名函数1. 定义:func() { ... }是一个匿名函数,因为它没有名称。
2. 赋值:我们将这个匿名函数赋值给变量greet。
3. 调用:通过greet()来调用这个匿名函数。// 立即执行函数表达式(IIFE)result := func(x, y int) int {return x * y}(3, 4) 1. 定义并执行:func(x, y int) int { return x * y }是一个匿名函数。
2. 立即执行:在定义后面紧跟(3, 4),这表示立即用参数34调用这个函数。
3. 结果:函数返回3 * 4的结果12,并将其赋值给变量result。

 

2. 闭包(Closure)

定义:匿名函数捕获外部变量形成闭包,变量在闭包内保持状态。

闭包能够捕获并记住其外部环境中的变量,即使在函数执行完毕后,这些变量仍然可以被访问和修改。这使得闭包可以在不同的调用之间保持状态,例如计数器、缓存等。

package mainimport "fmt"// adder 返回一个闭包函数,该函数捕获了外部变量 sum
func adder() func(int) int {sum := 0 // 这是被闭包捕获的外部变量return func(x int) int {sum += x // 每次调用时,更新并返回 sumreturn sum}
}func main() {pos := adder() // 创建一个新的闭包fmt.Println(pos(1)) // 输出: 1fmt.Println(pos(2)) // 输出: 3fmt.Println(pos(3)) // 输出: 6// 创建另一个独立的闭包neg := adder()fmt.Println(neg(-1)) // 输出: -1fmt.Println(neg(-2)) // 输出: -3
}

 

四、内置函数

Go语言预定义了一组内置函数,无需导入包即可使用:

函数名功能描述
len()获取切片、字符串、通道等的长度
new()分配零值内存,返回指针(如new(int)返回*int
make()创建引用类型(切片、map、通道)并初始化
append()向切片追加元素,返回新切片
panic()触发运行时恐慌,用于错误处理
recover()defer中恢复恐慌,避免程序崩溃

 

五、方法(让go有了面向对象的特性)

在Go语言中,方法和函数的主要区别在于方法是绑定到特定类型的,而函数则是独立的。

package mainimport ("fmt""math"
)type Circle struct {radius float64
}func (c Circle) area() float64 {return math.Pi * c.radius * c.radius
}func (c *Circle) updateRadius(r float64) {c.radius = r
}func calculateArea(radius float64) float64 {return math.Pi * radius * radius
}func main() {c := Circle{radius: 5}// 调用方法fmt.Println("Area using method:", c.area()) // 使用方法计算面积// 更新半径c.updateRadius(10)fmt.Println("Updated area using method:", c.area())// 调用函数fmt.Println("Area using function:", calculateArea(5)) // 使用函数计算面积
}

通过方法,Go语言实现了面向对象编程的特性,使得类型可以拥有自己的行为。

相关文章:

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

JVM 内存结构 详解

内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: ​ 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) ​遍历字符串​:通过外层循环逐一检查每个字符。​遇到 ? 时处理​: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: ​与…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Java编程之桥接模式

定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息&#xff0…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...