方法和函数区别说明|学习笔记

简介: 快速学习方法和函数区别说明

开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:方法和函数区别说明】学习笔记,与课程紧密联系,让用户快速学习知识。

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


方法和函数区别说明

 

内容介绍:

一、区别1

二、区别2

三、区别3

 

一、区别1

调用方式不一样

函数的调用方式:

函数名(实参列表)

方法的调用方式:

变量(与方法绑定类型的变量)方法名(实参列表)

 

二、区别2

对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然

对于普通函数,如果接收者是值类型,只可以进行值类型的传入,而不能进行指针类型的传入;反之如果接收者是指针类型,则只可以进行指针类型的传入,即只可以传入地址,而不可以进行类型的传入。

下面进行举例说明:

新建一个文件夹,命名为 methodvsfunc,在文件夹中新建一个文件 main.go。输入共用代码:

package main

import (

"fmt”"

)

假设现有一个结构体 type Person struct,输入字段 name{Name string}。写入一个函数,例如 test01,然后为其定义一个类型 func teste1(p Person){,并将其输出fmt.Println(p. Name)}。在主函数中定义一个 person,并将其赋值为 tom,代码为:

func main(){

p:=Person{"tom"}

然后再调用这个函数test01(p),因为该函数是结构体类型而不是指针类型,因此传入p就可以,输入cd chapter10 cd methodvsfunc go run main.go,运行后得到tom,与理论结果一致。此时要注意因为上述函数写入的是person,因此就不能传地址了test01(&p),如果传入地址,代码肯定会报错。所以我们得出一个结论是对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递。

核心代码:

package main

import (

“fmt”

)

type Person struct{

Name string

}

func test01(p Person){

fmt.Print1n(p.Name)

}

func main(){

P :=Person{"tom"}

test01(p)

反之亦然,进行举例说明,如果上述函数传入的是指针func test02(p *Person){

,进行调用时只能输入一个地址,代码为

func main(){

P :=Person{"tom"}

test02(&p1)

输入cd chapter10 cd methodvsfunc go run main.go完成运行,结果仍为tom,如果调用时输入test02(p),它也会没有报错了,说明此处有一个严格的规定,对于函数来说,如果接收者是指针,就只能传输地址,而如果接收者是值类型,则只能传输值,但是方法与函数不一样。

核心代码:

package main

import (

“fmt”

)

type Person struct{

Name string

}

func test02(p *Person){

fmt.Print1n(p.Name)

}

func main(){

P :=Person{"tom"}

test02(&p)

 

三、区别3

对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以

为person定义方法,有两种调用方法,一种是值类型调用,func (p Person) teste3(){fmt.Print1n("teste3()=”,p.Name)},进行调用时可以直接通过 p.teste03();一种是指针类型,调用时可以通过,运行发现输出为 tom,输入也可以进行调用,因为此时编译器底层进行了优化,也就是说虽然对 person 进行了绑定,但是输入地址也能够调用 test03,但是传入进去之后仍然进行值的拷贝,运行之后观察效果,可以看到打印出两个 tom,即虽然在调用时填入了地址 func (p Person) test03() {中的p不会指向外面的p,仍然会进行值的拷贝。此处极其容易混淆,意味着面试题中也会经常出现该类型题目,例如曾经的一道面试题,如果此时增添以下代码:p.Name = "jack",利用 p.test03进行调用。由于该方法进行了值拷贝,那么这个地方的改变肯定不会影响到外面的 tom,即 test03的输出结果为 Jack,而主函数的输出结果仍为 tom,输入 fmt.Print1n("main() p.name=", p.Name)进行验证,输出结果与理论效果一致。注意输入(&p).test03()进行调用时,只是形式上传入了地址,但是本质仍然是值拷贝。即编译器在做优化时会将 (&p).test03()改成 p.test03()的形式。

核心代码:

func (p Person) test03() {

p.Name = "jack"

fmt.Println("test03() ="",p.Name) //此时输出为jack

}

p.test03()

fmt.Print1n("main() p.name=", p.Name)//此时输出为tom

(&p).test03()//从形式上是传入地址,但是本质仍然是值拷贝

同样反过来也是一样的,创建test04,把它改成指针类型后,它也可以通过值类型或者是地址类型进行调用,为了显示出区别,将 test04的name 改成 marry,此时是与指针类型绑定的方法,按照正规的方法应该输入 (&p).test04()进行调用,因为是指针类型,调用时 test 与 main 函数都会输出 marry;而通过 p.test04()进行调用也是可以的,因为底层的编译器会进行优化处理,将 p.test04()等价于 (&p).test04(),运行后发现输出效果是一样的。同样的道理,p.test04()等价于(&p).test04,从形式上是传入值类型,但是本质仍然是地址拷贝,其关键的原因在于 test04 中与其绑定的类型为指针类型,因此在调用时的本质仍然是地址拷贝

核心代码:

func (p*Person) test04(){

p.Name = "mary"

fmt.Print1n("test03()=",p.Name)//此时输出为mary

}

(&p).test04()

fmt.Print1n("main() p.name=", p.Name)//此时输出为mary

p.test04()// 等价于 (&p).test04 //从形式上是传入值类型,但是本质仍然是地址拷贝

总结

对于普通的函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然;但是如果是定义一个方法,接受者为值类型时,既可以用值类型进行调用,也可以用指针类型进行调用,但是最终决定权取决于func()(接收者)中的内容,如果接收者是值类型,则在调用时无论是以值类型进行调用,还是以指针类型进行调用,调用的本质都是进行值的拷贝;反之,如果接收者是指针类型,则在调用时无论是以值类型进行调用,还是以指针类型进行调用,调用的本质都是进行地址的拷贝。其实最初golang的设计者这样的构思主要是为了使用方便,但在后来的实际应用中发现,这样的设计理念反而更加容易混淆概念。

相关文章
|
24天前
|
安全 编译器 C语言
宏函数与函数的区别
宏函数和函数都是编程中常用的代码复用方式。宏函数由预处理器处理,在编译前将调用处替换为定义的内容,通常用于简单的文本替换,不进行类型检查;而函数由编译器处理,支持参数传递、返回值和类型检查,更加灵活和安全。
|
6月前
|
存储 Java
Java数组与带参数方法:定义、调用及实践
Java数组与带参数方法:定义、调用及实践
72 1
|
6月前
|
Rust Java Serverless
函数与方法的区别
函数与方法的区别,当然是有区别。 不管是java、rust还是go,他们都是不一样的。
67 1
|
6月前
|
Python
什么是函数?函数分为几种? 区别是什么?
什么是函数?函数分为几种? 区别是什么?
|
6月前
|
JavaScript 前端开发 Java
函数和方法有区别吗?
函数和方法有区别吗?
70 0
|
Dart 前端开发 JavaScript
dart中将方法当做参数传递时的注意事项
众所周知,Dart是一门面向对象的语言,比Java更纯粹,Dart中的方法也是对象,也有类型Function。这意味着方法可以被分配给对象,也可以当做参数传递给其他方法。
|
程序员 Scala 开发者
函数(方法)的调用机制|学习笔记
快速学习函数(方法)的调用机制。
函数(方法)的调用机制|学习笔记
|
网络协议 测试技术 Go
方法的调用和传参机制 | 学习笔记
快速学习方法的调用和传参机制
方法的调用和传参机制 | 学习笔记
|
Java
java函数的基本概念,作用与语法
java函数的基本概念,作用与语法
223 0