方法使用的深度剖析(1)|学习笔记

简介: 快速学习方法使用的深度剖析(1)

开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:方法使用的深度剖析(1)】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/626/detail/9678


方法使用的深度剖析(1)

 

内容介绍:

一、方法的声明(定义)

二、方法注意事项和细节讨论(1)

三、方法注意事项和细节讨论(2)

 

一、方法的声明(定义)

1、语法:

func (recevier type) methodName(参数列表)(返回值列表){

方法体

return返回值}

关键词 func 后的括号用来确定方法与何种数据类型完成绑定。receiver 是 type 类型的一个变量,比如:Person结构体的一个变量;methodName是方法的名字,根据前面所讲的标识符的命名规则来写;参数列表类似于函数的形参列表,表示方法输入;返回值列表,方法如果有返回值,返回值就会写入返回值列表中;方法体表示该方法要完成的任务是什么,比如输入 return 表示返回值。recevier type:表示该方法和 type 类型进行绑定,或者说该方法作用于 type 类型,type 可以是结构体,也可以其它的自定义类型;返回值列表表示返回的值,可以是多个;方法主体:表示为了实现某一功能代码块;return 语句不是必须的。

2、具体说明:

1)参数列表

表示方法输入,有什么输入就在参数列表中写清楚。比如前面所举的例子,得到两个数的和,n1和n2就是输入的参数。

2) recevier type

表示这个方法和 type 这个类型进行绑定,或者说该方法作用于 type 类型,当然type 的类型根据实际情况而定。例如前面所讲的 person,或者是 student,就表示方法分别与 person、student 进行绑定。

3) receiver type

type 可以是结构体,也可以其它的普通自定义类型。例如 type integer int,也可以给 integer 进行绑定方法

4) Receiver

Receiver就是 type 类型的一个变量(实例),如果是结构体变量,有些程序员还是习惯于称作实例。比如:Person 结构体的一个变量(实例)

5) 返回值列表

表示返回的值,可以是多个

6) 方法主体

表示为了实现某一功能的代码块,根据实际需求来写,可以实现计算、连接数据库、添加数据等功能。

7) return 语句

Return 语句不是必预的,如果没有 return 语句,返回值列表也就不存在了;反之,如果有返回值列表,那么 return 语句一定存在。

 

二、方法注意事项和细节讨论(1)

结构体类型是值类型,在方法调用中,遵守值类型的传递机制,即值拷贝传递方式。

该注意事项在之前的内容中已经做了详细的解释和说明,因此在此不再进行赘述了。

 

三、方法注意事项和细节讨论(2)

如程序员希望在方法中修改结构体变量的值,可以通过结构体指针的方式来处理。

实际上,更多的是绑定结构体指针类型,而不是结构体本身,因为这样可以提高传输的速度、效率。如果是结构体类型的绑定,在传输的时候,进行值的拷贝;而如果是与结构体的指针进行绑定,拷贝的时候只进行地址的拷贝

举例说明:指针类型,而不是结构体

func (c *circle)area2() f1oat64 {

c.radius =10

return 3.14*(*c).radius*(*c).radius

)

方法与 circle 绑定时,需要完成值的拷贝,效率比较低。因此为了提高效率,通常会将方法与结构体的指针类型绑定,此时传入的是地址。因为c是指针,因此访问字段的标准方式是(*c).radius,(*c).radius 等价于 c.radius,因此可以输入为 return 3.14* c.radius*c.radius

进行调用时,首先创建一个circle的变量,传入数值7,标准调用方式如下:

var c circle

c.radius =5.0

res2 :=(&c). area()

fmt.Print1n("面积=",res2)

因为是c指针,所有在调用时,需要添加一个&,同样的道理,在取值的时候,要对值进行加*处理。但是这种调用方式比较麻烦,因此编译器底层做了优化,会自动的给变量添加上&,从而实现了 c.area() 等价为 (&c).area2()。调用代码可以写作:

var c circle

c.radius =5.0

res2 :=c. area()

fmt.Print1n("面积=",res2)

可以更改变量值检验上述的等价操作是否正确,将传入值7.0改为6.0后,运行查看效果,输入 cd.exercise go run main.go,可以看到输出的结果由78.5变成了113.83999……,值发生了改变,与理论值效果一致。虽然两种调用方式都可以得到正确的返回值,但是两者的机制完全不同。如果写作 c.radius=10,外侧c的值通过 fmt.Println(c.radius=",c.radius)查看有没有发生变化,运行后发现c的值变成了10,因为在进行传输的时候是指针类型,此时c拷贝的不是所有的内容,只是拷贝了地址,因此指针直接指向了 main 函数中的c,所以在函数里对函数进行修改,外侧的值也会发生改变

内存分析图

image.png

说明分析

主函数即代表了一个主栈,它是一个独立的数据空间。主栈中存有c变量,c是一个结构体,它会指向一个数据空间,数据空间里存有字段 radius,值为7.0。紧接着会进行c.area2 的操作,会创建一个新的独立的栈——area2 栈,area2 也是一个独立的数据空间,此时不再时将值进行拷贝。当c与指针完成绑定时,仍然存在c变量,但此时c变量只相当于地址。main 栈本身也含有地址,假设 main 栈中的地址为0X11122,即会在 area2 栈就会将地址拷贝进来area栈中的c是一个指针,所以 area2 栈中c指向main 栈中的地址。按照原理来说,由于c是地址,所以不可以直接访问 radius 的值,按照标准应该是以(*)的格式进行访问,但是由于编译器的优化,会将(*)在底层进行添加,因此此时也是可以直接访问的。接下来进行运算 return 3.14*(*c).radius*(*c).radius,此时的值就是在 main 栈中获取的,这里与之前所讲的都不一样,没有所谓的结构体的数据空间。

为了打消顾虑,可以检验一下计算所需要的值是从哪里获取的,先将主栈里c的值取出,输入 fmt.Printf("main c 结构体变量地址 =%\n",&c),添加\n是为了便于查看。因为c本身就是一个指针,所以应该将它的内容取出,代码为 fmt.Printf("c是*Circle 指向的地址 =%p",c),不需要再利用&了,因为此时c本身就是一个地址,若此时通过上述代码取出的地址和已知的地址一致,即可证明上述结论正确。运行后发现,输出的地址地区与所知地址一样。

 

相关文章
|
2月前
|
JavaScript 编译器 API
【C++ 函数和过程 进阶篇】全面掌握C++函数返回值:从入门到精通的实战指南
【C++ 函数和过程 进阶篇】全面掌握C++函数返回值:从入门到精通的实战指南
122 1
|
2月前
|
存储 Java 程序员
|
2月前
|
XML Java 数据库连接
谈谈Java反射:从入门到实践,再到原理
谈谈Java反射:从入门到实践,再到原理
85 0
|
缓存 Java
认真阅读完这篇文章熟练掌握阿里巴巴规范创建Java线程池
认真阅读完这篇文章熟练掌握阿里巴巴规范创建Java线程池
716 0
|
1月前
|
SQL 存储 NoSQL
数据库原理速览:核心知识集萃与复习指南
数据库原理速览:核心知识集萃与复习指南
25 2
|
2月前
|
编译器 C++
【C++进阶(八)】C++继承深度剖析
【C++进阶(八)】C++继承深度剖析
|
9月前
|
机器学习/深度学习 人工智能 算法
这篇科普让你Get所有大模型的基础核心知识点
本文介绍了AI大模型的概念和发展历程。AI大模型是指具有1亿以上参数的机器学习模型,通过在大规模数据集上进行预训练,可以直接支撑各类应用。大模型的发展经历了从萌芽期到AI1.0时期,再到AI2.0时期的飞跃,目前最新发布的大模型参数已经达到了千亿甚至万亿级别。国内外的公司都在积极研发和应用大模型,如OpenAI、Google、Facebook、Microsoft等。国内也有百度、阿里巴巴、万维、商汤科技等公司发布了自己的大模型产品。大模型的建造离不开算力资源、算法人才、数据积累等核心要素。此外,文章还列举了一些与大模型相关的专业名词,如算法、模型参数、训练数据、Token等。
|
7月前
|
SQL Kubernetes Java
深度剖析FlinkX(纯钧)源码
深度剖析FlinkX(纯钧)源码
106 0
|
存储 Kubernetes 监控
k8s学习之路【02.基础概念介绍】
k8s学习之路【02.基础概念介绍】
|
存储 安全 编译器
【C++系列(合集)】特性多又复杂?不存在!——这篇C++大全直接干碎(超级大全,精讲)(一)
【C++系列(合集)】特性多又复杂?不存在!——这篇C++大全直接干碎(超级大全,精讲)