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

golang学习笔记20-面向对象(二):方法与结构体【重要】

本节内容是面向对象的核心与基础,很重要。
注意:由于导包语句已经在19讲(笔记19:面向对象的引入)展示过了,所以这里就不展示了。

一、方法的定义与细节

方法是与特定类型(通常是结构体)关联的函数。方法可以操作该类型的实例,并且可以使用其字段。定义方法时,需要指定一个接收者(receiver),这使得方法能够访问该接收者的属性。语法如下:

func (receiver TypeName) MethodName(parameters) returnList {
    // 方法体
}

receiver是接收者的名称,类型是你想要关联的自定义类型(通常是结构体)。
MethodName是方法的名称。
parameters是方法接受的参数。
returnList是返回值类型列表。
首先,在utils中定义一个结构体和一个方法:

type Circle struct {
	Radius float64
}

// 定义一个方法,计算圆的面积
// 1. 方法中参数名字随便起
// 2. 方法 Area 和结构体 Circle绑定,必须在同包中定义!
func (c Circle) Area() float64 {
	return 3.14 * c.Radius * c.Radius
}

然后在main中调用:

func main() {
	// 创建一个 Circle 实例
	circle := utils.Circle{Radius: 5}

	// 调用方法
	area := circle.Area()

	// 输出结果
	fmt.Printf("Area: %.2f\n", area)
}

一些细节
1.如果其他类型的变量调用area一定会报错
2.结构体对象传入方法area中,属于值传递,和参数传递一致。
3.receiver的类型是你想要关联的自定义类型
4.如果某个自定义类型实现了返回string,名字为String()的方法(如果是同包内调用,s可以小写),那么fmt包的Printf或Println函数打印该类型时,会自动调用String()
对于前两点,首先,在utils中定义另一个方法来演示值传递:

// 定义一个方法,演示值传递
func (c Circle) SetRadius(newRadius float64) {
	c.Radius = newRadius
	fmt.Printf("Inside Radius: %.2f\n", c.Radius)
}

然后在main文件中调用:

type test struct {
	a int
}

func main() {
	// 创建一个 Circle 实例
	circle := utils.Circle{Radius: 5}

	// 调用方法
	area := circle.Area()
	fmt.Printf("Area: %.2f\n", area)

	// 1. 如果其他类型变量调用 area 一定会报错
	// 下面的代码将导致编译错误
	//t := test{}
	// t.area() // 这行会报错,因为 radius 不是 Circle 类型

	// 2. 结构体对象传入方法 Area 中,属于值传递
	circle2 := utils.Circle{Radius: 10}
	fmt.Printf("Old Radius: %.2f\n", circle2.Radius)

	// 调用 SetRadius 方法尝试修改半径
	circle2.SetRadius(15)
	fmt.Printf("New Radius: %.2f\n", circle2.Radius) // 仍然是 10
}

OK,如果我就想在SetRadius内改变radius呢?那肯定是用指针了,但方法比数组指针简单:将SetRadius中的Circle前加上*即可,因为编译器会自动处理结构体指针,所以在main中的代码无需改动!
对于第三点,receiver的类型是你想要关联的自定义类型,这也就是说,基本类型不能作为方法中的接收类型!读者可自行尝试,这里不做赘述。
对于第四点,首先,在utils内定义String():

func (p Person) String() string {
	str := fmt.Sprintf("name=%s,age=%v,sex=%s", p.Name, p.Age, p.Sex)
	return str
}

然后在main中调用:

func main() {
	p := utils.Person{Name: "李华", Age: 30, Sex: "女"}
	fmt.Printf("%v\n", p) // 使用格式化字符串
	fmt.Println(p)        // 直接打印
}

这个String方法呢,也是定义结构体时常用的,以便输出结构体信息。这里我提一个问题:如果定义了Person的别名,打印其实例还会自动调用String()吗?验证很简单,读者可自行尝试,这里不做赘述。

二、方法与函数的区别

方法函数
和其他类型的关系绑定到特定类型独立于任何类型
语法func (receiver ReceiverType) MethodName(parameters) returnTypefunc FunctionName(parameters) returnType
调用方式通过类型的实例调用 instance.MethodName()直接调用 FunctionName()
作用域可以访问绑定类型的字段只能访问传入的参数
指定类型是否需要和传入类型一致不需要(可以随意传入值或指针)需要

关于最后一点,首先在utils中定义两个接收者不同的方法:

// 方法:接收者为值类型
func (p Person) PValue() {
	fmt.Println("Hello, my name is", p.Name)
}

// 方法:接收者为指针类型
func (p *Person) PPointer() {
	fmt.Println("Hello, my name is", p.Name)
}

然后在main文件中调用:

// 函数:必须传入 Person 类型
func PrintPerson(p utils.Person) {
	fmt.Println("Person's name:", p.Name)
}

func main() {
	// 创建值类型和指针类型的实例
	p1 := utils.Person{Name: "李华"}
	p2 := &utils.Person{Name: "张三"}

	p1.PPointer()   // 调用接收者为指针的方法,传入值类型
	PrintPerson(p1) // 调用函数,传入值类型

	p2.PValue()      // 调用接收者为值类型的方法,传入指针
	PrintPerson(*p2) // 调用函数,传入解引用的指针
}

程序输出如下:

Hello, my name is 李华
Person's name: 李华
Hello, my name is 张三
Person's name: 张三

http://www.kler.cn/news/326175.html

相关文章:

  • React和Vue对比
  • Oracle数据库物理结构操作管理
  • kubeadm部署k8s集群,版本1.23.6;并设置calico网络BGP模式通信,版本v3.25--未完待续
  • C++ STL(1)迭代器
  • Kafka 在 Linux 下的集群配置和安装
  • 生产k8s 应用容器内存溢出OOMKilled问题处理
  • Ubuntu 镜像替换为阿里云镜像:简化你的下载体验
  • linux内核双向链表使用list klist
  • YOLOv11改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制
  • L2-004 这是二叉搜索树吗?
  • C++中vector类的使用
  • Google Tag Manager - 服务器端代码植入
  • Python与SQL Server数据库结合导出Excel并做部分修改
  • ElasticSearch安装分词器与整合SpringBoot
  • 【制作自解压程序】使用7Z制作自解压程序
  • OceanBase技术解析:自适应分布式下压技术
  • 【软件整理资料】软件项目配套资料,项目计划书(word)
  • IDEA使用技巧和插件推荐
  • 爬虫及数据可视化——运用Hadoop和MongoDB数据进行分析
  • js中的深拷贝与浅拷贝 手写深拷贝代码
  • 深入剖析 Android Lifecycle:构建高效稳定的应用
  • 如何设计能吸引下载的截图以及注意事项
  • SpringBoot助力墙绘艺术市场创新
  • golang学习笔记16-数组
  • java 解析excel (本地资源)
  • Android常用C++特性之std::find_if
  • CF1619D.New Year‘s Problem
  • 解决 TypeError: Expected state_dict to be dict-like, , got <class ‘*‘>.
  • Acwing 最小生成树
  • 每日OJ题_牛客_NC40链表相加(二)_链表+高精度加法_C++_Java