Go函数和⽅法的区别
在Go语⾔中,函数和⽅法不太⼀样,有明确的概念区分。其他语⾔中,⽐如Java,⼀般来说函数就是⽅法,⽅法就是函数,但是
在Go语⾔中,函数是指不属于任何结构体、类型的⽅法,也就是说函数是没有接收者的;⽽⽅法是有接收者的,我们说的⽅法要么是
属于⼀个结构体的,要么属于⼀个新定义的类型的。
⼀、函数
函数和⽅法虽然概念不同,但是定义⾮常相似。函数的定义声明没有接收者,所以我们直接在go⽂件⾥,go包之下定义声明即可。
funcmain(){
sum:=add(1,2)
n(sum)
}
funcadd(a,bint)int{
returna+b
}
例⼦中,我们定义了add就是⼀个函数,它的函数签名是funcadd(a,bint)int,没有接收者,直接定义在go的⼀个包之下,可以直接调
⽤,⽐如例⼦中的main函数调⽤了add函数。例⼦中的这个函数名称是⼩写开头的add,所以它的作⽤域只属于所声明的包内使⽤,不能被
其他包使⽤,如果我们把函数名以⼤写字母开头,该函数的作⽤域就⼤了,可以被其他包调⽤。这也是Go语⾔中⼤⼩写的⽤处,⽐如Java
中就有专门的关键字来声明作⽤域private、protect、public等。如下例⼦中定义的Add⽅法就可以被其他包调⽤。
/*
提供的常⽤库,有⼀些常⽤的⽅法,⽅便使⽤
*/
packagelib
//⼀个加法实现:返回a+b的值
funcAdd(a,bint)int{
returna+b
}
⼆、⽅法
⽅法的声明和函数类似,他们的区别是:⽅法在定义的时候,会在func和⽅法名之间增加⼀个参数,这个参数就是接收者,这样我们
定义的这个⽅法就和接收者绑定在了⼀起,称之为这个接收者的⽅法。
typepersonstruct{
namestring
}
func(pperson)String()string{
return"thepersonnameis"+
}
留意例⼦中,func和⽅法名之间增加的参数(pperson),这个就是接收者。现在我们说,类型person有了⼀个String⽅法,现在我们看下
如何使⽤它。
funcmain(){
p:=person{name:"张三"}
n(())
}
调⽤的⽅法⾮常简单,使⽤类型的变量进⾏调⽤即可,类型变量和⽅法之前是⼀个.操作符,表⽰要调⽤这个类型变量的某个⽅法的意
思。Go语⾔⾥有两种类型的接收者:值接收者和指针接收者。我们上⾯的例⼦中,就是使⽤值类型接收者的⽰例。使⽤值类型接收者定义
的⽅法,在调⽤的时候,使⽤的其实是值接收者的⼀个副本,所以对该值的任何操作,不会影响原来的类型变量。
funcmain(){
p:=person{name:"张三"}
()//值接收者,修改⽆效
n(())
}
typepersonstruct{
namestring
}
func(pperson)String()string{
return"thepersonnameis"+
}
func(pperson)modify(){
="李四"
}
以上例⼦,打印出来的值还是张三,对其进⾏的修改⽆效。如果我们使⽤⼀个指针作为接收者,那么就会其作⽤了,因为指针接收者传
递的是⼀个指向原值指针的副本,指针的副本,指向的还是原来类型的值,所以修改时,同时也会影响原来类型变量的值。
funcmain(){
p:=person{name:"张三"}
()//指针接收者,修改有效
n(())
}
typepersonstruct{
namestring
}
func(pperson)String()string{
return"thepersonnameis"+
}
func(p*person)modify(){
="李四"
}
在调⽤⽅法的时候,传递的接收者本质上都是副本,只不过⼀个是这个值副本,⼀是指向这个值指针的副本。指针具有指向原有值的特
性,所以修改了指针指向的值,也就修改了原有的值。我们可以简单的理解为值接收者使⽤的是值的副本来调⽤⽅法,⽽指针接收者使⽤实
际的值来调⽤⽅法。在上⾯的例⼦中,有没有发现,我们在调⽤指针接收者⽅法的时候,使⽤的也是⼀个值的变量,并不是⼀个指针,如果
我们使⽤下⾯的也是可以的。
p:=person{name:"张三"}
(&p).modify()//指针接收者,修改有效
这样也是可以的。如果我们没有这么强制使⽤指针进⾏调⽤,Go的编译器⾃动会帮我们取指针,以满⾜接收者的要求。同样的,如果
是⼀个值接收者的⽅法,使⽤指针也是可以调⽤的,Go编译器⾃动会解引⽤,以满⾜接收者的要求,⽐如例⼦中定义的String()⽅法,也可
以这么调⽤:
p:=person{name:"张三"}
n((&p).String())
总之,⽅法的调⽤,既可以使⽤值,也可以使⽤指针,我们不必要严格的遵守这些,Go语⾔编译器会帮我们进⾏⾃动转义的,这⼤⼤
⽅便了我们开发者。不管是使⽤值接收者,还是指针接收者,⼀定要搞清楚类型的本质:对类型进⾏操作的时候,是要改变当前值,还是要
创建⼀个新值进⾏返回?这些就可以决定我们是采⽤值传递,还是指针传递。
三、多值返回
Go语⾔⽀持函数⽅法的多值返回,也就说我们定义的函数⽅法可以返回多个值,⽐如标准库⾥的很多⽅法,都是返回两个值,第⼀个
是函数需要返回的值,第⼆个是出错时返回的错误信息,这种的好处,我们的出错异常信息再也不⽤像Java⼀样使⽤⼀个Exception这么重
的⽅式表⽰了,⾮常简洁。
funcmain(){
file,err:=("/usr/tmp")
iferr!=nil{
(err)
return
}
n(file)
}
如果返回的值,我们不想使⽤,可以使⽤_进⾏忽略。
file,_:=("/usr/tmp")
多个值返回的定义也⾮常简单,看个例⼦。函数⽅法声明定义的时候,采⽤逗号分割,因为时多个返回,还要⽤括号括起来。返回的值
还是使⽤return关键字,以逗号分割,和返回的声明的顺序⼀致。
funcadd(a,bint)(int,error){
returna+b,nil
}
四、可变参数
函数⽅法的参数,可以是任意多个,这种我们称之为可以变参数,⽐如我们常⽤的n()这类函数,可以接收⼀个可变的参数。
funcmain(){
n("1","2","3")
}
可以变参数,可以是任意多个。我们⾃⼰也可以定义可以变参数,可变参数的定义,在类型前加上省略号…即可。如下例⼦中我们⾃
⼰定义了⼀个接受可变参数的函数,效果和n()⼀样。可变参数本质上是⼀个数组,所以我们向使⽤数组⼀样使⽤它,⽐如例⼦中
的forrange循环。
funcmain(){
print("1","2","3")
}
funcprint(a...interface{}){
for_,v:=rangea{
(v)
}
n()
}
本文发布于:2022-12-07 04:31:19,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/88/57406.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |