深入理解Go语言的方法定义与使用
在Go语言编程中,方法(Method) 是附属于特定类型的函数,使我们能够以面向对象的方式编写代码。通过方法,我们可以更自然地对类型进行操作。本文将通过实际的代码示例,深入探讨Go语言中方法的定义与使用。
一、准备工作
为了实践本文的内容,我们需要先创建一个新的Go项目。
1. 创建项目目录
打开命令行,导航到合适的目录下,创建一个名为methodsAndInterfaces的文件夹:
mkdir methodsAndInterfaces
cd methodsAndInterfaces
2. 初始化Go模块
在methodsAndInterfaces目录下,运行以下命令初始化Go模块:
go mod init methodsandinterfaces
3. 创建main.go文件
在methodsAndInterfaces目录下,创建一个名为main.go的文件,输入以下内容:
package mainimport "fmt"// 定义Product结构体
type Product struct {name, category stringprice float64
}func main() {// 创建Product指针的切片products := []*Product{{"皮划艇", "水上运动", 275},{"救生衣", "水上运动", 48.95},{"足球", "足球运动", 19.50},}// 遍历并打印商品信息for _, p := range products {fmt.Println("名称:", p.name, "分类:", p.category, "价格:", p.price)}
}
4. 运行程序
在命令行中,确保当前目录是methodsAndInterfaces,运行以下命令:
go run .
程序将输出:
名称: 皮划艇 分类: 水上运动 价格: 275
名称: 救生衣 分类: 水上运动 价格: 48.95
名称: 足球 分类: 足球运动 价格: 19.5
二、定义和使用方法
1. 从函数到方法
首先,我们来看一个普通的函数如何定义:
// 定义一个函数,接收*Product类型的参数
func printDetails(product *Product) {fmt.Println("名称:", product.name, "分类:", product.category, "价格:", product.price)
}
在main函数中,我们可以这样调用它:
for _, p := range products {printDetails(p) // 调用函数
}
2. 将函数转换为方法
现在,我们将上述函数转换为Product类型的方法:
// 定义一个方法,作用于*Product类型
func (product *Product) printDetails() {fmt.Println("名称:", product.name, "分类:", product.category, "价格:", product.price)
}
注意这里的(product *Product)部分,这就是方法的接收者,表示printDetails方法绑定到了*Product类型。
在main函数中,调用方法的方式也有所不同:
for _, p := range products {p.printDetails() // 调用方法
}
这样,我们就将函数转换为了方法,调用时更加直观。
三、方法的参数和返回值
方法可以像函数一样,拥有自己的参数和返回值。
1. 定义带参数和返回值的方法
我们为Product类型定义一个计算税后价格的方法:
// 计算税后价格的方法
func (product *Product) calcTax(rate, threshold float64) float64 {if product.price > threshold {return product.price + (product.price * rate)}return product.price
}
rate:税率threshold:价格阈值,超过该值才计算税
2. 在方法中调用另一个方法
修改printDetails方法,调用calcTax方法:
func (product *Product) printDetails() {finalPrice := product.calcTax(0.2, 100) // 计算税后价格fmt.Println("名称:", product.name, "分类:", product.category, "价格:", finalPrice)
}
3. 运行结果
重新运行程序,输出如下:
名称: 皮划艇 分类: 水上运动 价格: 330
名称: 救生衣 分类: 水上运动 价格: 48.95
名称: 足球 分类: 足球运动 价格: 19.5
可以看到,价格高于100的商品(皮划艇)被加上了20%的税费。
四、方法重载的限制
1. Go语言不支持方法重载
在Go语言中,不支持方法重载。也就是说,不能在同一个类型上定义多个同名的方法,即使它们的参数不同。
2. 示例
如果尝试这样做:
func (product *Product) printDetails() {// 方法体
}func (product *Product) printDetails(showPrice bool) {// 方法体
}
编译器会报错:
method redeclared: Product.printDetails
3. 合理命名方法
为了避免冲突,应为不同的方法使用不同的名称,例如printBasicDetails和printFullDetails。
五、指针接收者和值接收者
1. 指针接收者
当方法的接收者是指针类型时,可以通过值类型或指针类型的变量调用该方法,Go会自动完成转换。
func (product *Product) printDetails() {// 方法体
}func main() {prod := Product{"皮划艇", "水上运动", 275}prod.printDetails() // 自动转换为指针类型调用
}
2. 值接收者
同样,当方法的接收者是值类型时,也可以通过指针类型的变量调用。
func (product Product) showCategory() {fmt.Println("分类:", product.category)
}func main() {prodPtr := &Product{"救生衣", "水上运动", 48.95}prodPtr.showCategory() // 自动解引用,调用值接收者的方法
}
3. 选择接收者类型
- 指针接收者:需要修改接收者,或者接收者包含大量数据,避免拷贝。
- 值接收者:接收者为基本类型,方法不需要修改接收者状态。
六、为类型别名定义方法
1. 定义类型别名
我们可以使用type关键字为现有类型创建别名,然后为其定义方法。
// 定义ProductList类型,表示Product的切片
type ProductList []Product
2. 为类型别名定义方法
// 计算各分类商品总价的方法
func (products ProductList) calcCategoryTotals() map[string]float64 {totals := make(map[string]float64)for _, p := range products {totals[p.category] += p.price}return totals
}
3. 使用方法
func main() {products := ProductList{{"皮划艇", "水上运动", 275},{"救生衣", "水上运动", 48.95},{"足球", "足球运动", 19.50},}totals := products.calcCategoryTotals()for category, total := range totals {fmt.Println("分类:", category, "总价:", total)}
}
4. 运行结果
分类: 水上运动 总价: 323.95
分类: 足球运动 总价: 19.5
七、将类型和方法分离到不同文件
1. 项目结构的优化
随着项目的增长,将所有代码写在一个文件中会使得代码难以维护。我们可以将类型和方法分离到不同的文件中,但它们需要属于同一个包。
2. 创建product.go文件
package main// 定义Product结构体
type Product struct {name, category stringprice float64
}// 为Product定义方法
func (product *Product) printDetails() {fmt.Println("名称:", product.name, "分类:", product.category, "价格:", product.price)
}
3. 创建service.go文件
package main// 定义Service结构体
type Service struct {description stringdurationMonths intmonthlyFee float64
}// 为Service定义方法
func (service *Service) printDetails() {totalFee := service.monthlyFee * float64(service.durationMonths)fmt.Println("服务:", service.description, "总费用:", totalFee)
}
4. 修改main.go文件
package mainfunc main() {product := Product{"皮划艇", "水上运动", 275}service := Service{"船只保险", 12, 89.50}product.printDetails()service.printDetails()
}
5. 运行结果
名称: 皮划艇 分类: 水上运动 价格: 275
服务: 船只保险 总费用: 1074
通过将代码拆分到不同的文件中,我们的项目结构更加清晰,代码维护也更方便。
八、总结与补充
本文详细介绍了Go语言中方法的定义和使用,包括:
- 将函数转换为方法
- 方法的参数和返回值
- 方法重载的限制
- 指针接收者和值接收者
- 为类型别名定义方法
- 将类型和方法分离到不同文件
相关文章:
深入理解Go语言的方法定义与使用
在Go语言编程中,方法(Method) 是附属于特定类型的函数,使我们能够以面向对象的方式编写代码。通过方法,我们可以更自然地对类型进行操作。本文将通过实际的代码示例,深入探讨Go语言中方法的定义与使用。 一…...
堆排序,快速排序
目录 1.堆排序 2.快速排序 1.hoare版本 2.挖坑法 3.前后指针法 注意点 1.堆排序 void Swap(int* a, int* b) {int tmp *a;*a *b;*b tmp; } void adjustdown(int* a, int n, int parent) {int child parent * 2 1;while (child < n){if (child 1 < n &&am…...
系统架构师---数据库设计的四个阶段
需求分析、概念设计、逻辑设计和物理设计是数据库设计中的四个关键阶段,每个阶段都有其独特的任务和目标,以下是对这四个阶段的区别的详细阐述: 需求分析阶段 目标:全面理解用户对数据库系统的需求,包括业务需求、信…...
MySQL_简介及安装、配置、卸载(超详细)
课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :…...
大数据处理技术:分布式文件系统HDFS
目录 1 实验名称: 2 实验目的 3 实验内容 4 实验原理 5 实验过程或源代码 5.1 HDFS的基本操作 5.2 HDFS-JAVA接口之读取文件 5.3 HDFS-JAVA接口之上传文件 5.4 HDFS-JAVA接口之删除文件 6 实验结果 6.1 HDFS的基本操作 6.2 HDFS-JAVA接口之读取文件 6.…...
组合数(模板)
1.杨辉三角求组合数,最高只能求几千内的组合数。 #include<bits/stdc.h> using namespace std; #define int long long int C[1005][1005]; signed main() {//求 1000 以内的组合数 for(int i0;i<1000;i){C[i][0]C[i][i]1;for(int j1;j<i;j){C[i][j]C[…...
时序数据库 TDengine 的入门体验和操作记录
时序数据库 TDengine 的学习和使用经验 什么是 TDengine ?什么是时序数据 ?使用RPM安装包部署默认的网络端口 TDengine 使用TDengine 命令行(CLI)taosBenchmark服务器内存需求删库跑路测试 使用体验文档纠错 什么是 TDengine &…...
Qt-QPushButton按钮类控件(22)
目录 描述 使用 给按钮添加图片 给按钮添加快捷键 添加槽函数 添加快捷键 添加组合键 开启鼠标的连发功能 描述 经过上面的一些介绍,我们也尝试的使用过了这个控件,接下来我们就要详细介绍这些比较重要的控件了 使用 给按钮添加图片 我们创建…...
镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态
当今企业数据管理日益规范化,数据应用系统随着数据类型与数量的增长不断细分,为了提升市场竞争力与技术实力,数据领域软件服务商与上下游伙伴的紧密对接与合作显得尤为重要。通过构建完善的生态系统,生态内企业间能够整合资源、共…...
蒸!--数据在内存中的存储
一.整数在内存中的存储 对于整形来说:数据存放内存中其实存放的是补码。 为什么? 在计算机系统中,数值⼀律⽤补码来表⽰和存储。 原因在于,使⽤补码,可以将符号位和数值域统⼀处理; 同时,加法和…...
利用AI增强现实开发:基于CoreML的深度学习图像场景识别实战教程
🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…...
每个企业都需要 (但未使用) 的 BYOD 安全解决方案
远程办公模式的转变彻底改变了组织管理员工设备的方式。如今,员工希望能够灵活地在任何地方使用任何设备工作,这导致自带设备 (BYOD) 政策被广泛采用。 但随着越来越多的企业采用BYOD,一个问题依然摆在眼前:如何在不侵犯个人隐私…...
【多系统萎缩患者必看】科学锻炼秘籍,让生命之树常青
亲爱的小红书朋友们,👋 今天我们要聊一个温暖而坚韧的话题——关于多系统萎缩(MSA)患者的锻炼指南。在这个充满挑战的旅程中,锻炼不仅是身体的锻炼,更是心灵的滋养,是对抗病魔的勇敢姿态&#x…...
【Android】Room—数据库的基本操作
引言 在Android开发中,数据持久化是一个不可或缺的部分。随着应用的复杂度增加,选择合适的数据存储方式变得尤为重要。Room数据库作为Android Jetpack架构组件之一,提供了一种抽象层,使得开发者能够以更简洁、更安全的方式操作SQ…...
「数组」堆排序 / 大根堆优化(C++)
目录 概述 核心概念:堆 堆结构 数组存堆 思路 算法过程 up() down() Code 优化方案 大根堆优化 Code(pro) 复杂度 总结 概述 在「数组」快速排序 / 随机值优化|小区间插入优化(C)中,我们介绍了三种基本排序中的冒泡…...
Edegex Foundry docker和源码安装
edgex文档下载 https://github.com/edgexfoundry/edgex-docs/branches/all 在线文档查看 首先要安装python3环境 然后后安装 打开超级终端 #pip3 install mkdocs #mkdocs serve 在浏览器中输入 http://127.0.0.1:8000/edgex-docs/2.3/ 即可打开在线文档 edgex入门可以参考…...
阿里P8和P9级别有何要求
阿里巴巴的P8和P9级别,代表着公司的资深技术专家或管理者岗位,要求候选人具有丰富的职业经历、深厚的技术能力以及出色的领导力。以下是对P8和P9级别的要求、考察点以及准备建议的详细分析。 P8 级别要求 1. 职业经历: 8年以上的工作经验&a…...
【目标检测数据集】锯子数据集1107张VOC+YOLO格式
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):1107 标注数量(xml文件个数):1107 标注数量(txt文件个数):1107 标注…...
移动产业处理器接口(MIPI)协议是什么?
未来汽车的宏伟愿景备受瞩目,特别是驱动这些汽车的技术更是成为焦点。如今,传感器对于汽车视觉和安全技术的下一阶段至关重要,因为驾驶员和乘客都依赖于它们。这些传感器能够支持众多应用,这些应用往往基于人工智能(AI…...
OpenAI o1:隐含在训练与推理间的动态泛化与流形分布
随着OpenAI o1发布,进一步激发了产业与学术各界对AGI的期待以及new scaling law下的探索热情,也看到来自社区和专业机构对o1的阐释,但总感觉还差点什么,因此决定以自己的角度分篇幅梳理下,并分享给大伙: O…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
CMake系统学习笔记
CMake系统学习笔记 基础操作 最基本的案例 // code #include <iostream>int main() {std::cout << "hello world " << std::endl;return 0; }// CMakeLists.txt cmake_minimum_required(VERSION 3.0)# 定义当前工程名称 project(demo)add_execu…...
