Go 函数方法

Wesley13
• 阅读 483

      在 Go 语言中,函数和方法不太一样,有明确的概念区分。其他语言中,比如 PHP 函数就是方法,方法

就是函数,但在 Go 语言中,函数是不属于任何结构体、类型的方法,也就是说函数是没有接收者的;而方法

是有接收者的,我们所说的方法要么属于一个结构体的,要么属于一个新定义的类型的

函数

函数和方法,虽然概念不同,但是定义非常相似。函数的定义声明没有接收者,如下示例:

package main

import "fmt"

// 定义一个求两数之和的函数
func add(a,b int) int  {
    return a + b
}

func main() {
    sum := add(1,2)
    fmt.Println(sum)
}

  上面的例子中,我们定义了一个 add 函数,它的函数签名是 func add(a,b int) int ,没有接收者,直接定义在 go 

的一个包之下,可以直接用,例子中的这个函数名是小写的 add,所以它的作用域只有当前包,不能被其他包使用,

如果我们把函数名以大写开头,可以被其他包调用,这也是 Go 中大小写的作用

方法 方法的声明和函数类似,她们的区别是:方法在定义的时候在 func 和 方法名之间有一个参数,这个参数就是方

法的接收者,这样我们定义的这个方法就和接收者绑定在一起了吧,称之为这个接收者的方法:

// 定义一个结构体
type person struct {
    name string
}

func (p person) String() string  {
    return "the person name is " + p.name
}

  上面的这个例子中,func 和 方法名 String 之间的参数(p person) 就是接收者,现在我们说,类型 person 有了一个方法

String,现在看下如何使用:

func main()  {
    p := person{name : "张三"}

    fmt.Println(p.String())
}

  Go 语言中接收者分为两种类型,值接受者和指针接收者。我们上面的例子中,就是值类型接收者的示例

       使用值类型接收者定义的方法,在调用的时候,使用的其实就是值接受者的一个副本,所以对该值的任何操作,不会影响

原来的值

package main

import "fmt"

type person struct {
    name string
}

func (p person) String() string {
    return "the person name is " + p.name
}

func (p person) modify()  {
    p.name = "李四"
}

func main()  {
    p := person{"张三"}
    // 值类型接收者
    p.modify()

    fmt.Println(p.String())
}

  上面的例子中,打印出来的值是 "张三",对其进行的修改无效。如果我们使用一个指针作为接收者,那么就会起作用了,

因为指针接收者传递的是一个指向原值指针的拷贝,指针的副本,指向的还是原来类型的值,所以修改时,同时也会影响原

来类型变量的值

package main

import "fmt"

type person struct {
    name string
}

func (p person) String() string {
    return "the person name is " + p.name
}

func (p *person) modify()  {
    p.name = "李四"
}

func main()  {
    p := person{"张三"}
    // 值类型接收者
    p.modify()

    fmt.Println(p.String())
}

    在调用方法的时候,传递的接收者本质上都是副本,只不过一个是值副本,另一个是指向这个值指针的副本。指针具有

指向原值的特性,所以修改了指针指向的值,也就修改了原有的值。我们可以简单的理解为值接收者使用的是值的副本来调用

方法,而指针接收者使用的是实际值调用方法

         上面的例子中我们发现,在调用指针接收者方法的时候,使用的也是一个值的变量,并不是一个指针,修改如下:

p := person{"张三"}
(&p).modify()

  这样也是可以的,如果我们没有强制使用指针进行调用,Go 编译器会帮我们取指针,同样的,如果是一个值接收者的方法

使用指针也可以调用,Go 编译器会自动解引,如下:

p := person{"张三"}
fmt.Println((&p).String())

  所以,方法的调用既可以是值也可以是指针

多值返回

Go 语言支持函数方法的多值返回,也就是说我们定义的函数方法支持可以返回多个值,比如标准库里的很多方法,都是返回两

个值,第一个是函数需要返回的值,第二个是出错时返回的错误信息

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    file , err := os.Open("/usr/tmp")

    if err != nil {
        log.Fatal(err)
        return
    }

    fmt.Println(file)
}

  如果返回的值,我们不想使用,可以使用 _ 进行忽略:

file , _ := os.Open("/usr/tmp/")

  多个值返回的定义也非常简单,如下示例:

func add(a,b int) (int,error) {
     return a + b, nil
}

  函数方法声明定义的时候,采用逗号分隔,因为是多个返回,还要用括号扩起来,返回的值还是使用 return 关键字,以逗号分隔,和

声明的顺序一致

可变参数

函数方法的参数可以是任意多个,这种我们称之为可变参数,比如我们常用的 fmt.Println() 这类函数,可以接收可变参数

func main() {
    fmt.Println("1","2","3","4")
}

  自己定义一个可接收可变参数的函数,如果可变参数的类型是一样的则可以使用省略号 ... 代替:

func print(a ...interface{})  {
    for _,v := range a{
        fmt.Println(v)
    }
}

  可变参数本质上是一个数组,所以我们可以像数组一样使用它

点赞
收藏
评论区
推荐文章
九路 九路
3年前
一篇文章彻底弄懂go语言方法的本质
Go语言不支持经典的面向对象语法元素,比如:类、对象、继承等。但Go语言也有方法(method)。和函数相比,Go语言中的方法在声明形式上仅仅多了一个参数,Go称之为receiver参数。而receiver参数正是方法与类型之间的纽带。Go方法的一般声明形式如下:gofunc(receiverT/T)MethodName(参数列表)
Wesley13 Wesley13
3年前
java Lambda表达式
简介  Lambda可以理解为简洁的表示可传递的匿名函数,包括:参数列表、函数主体、返回类型、抛出的异常列表(可以不存在)。  函数式接口:定义一个抽象方法的接口(接口可以拥有默认方法:default)。  函数式接口有什么用?    Lambda可以以内联的形式为函数式接口的抽象方法提供实现。虽然内部类也可以实现,但lambda表达
Wesley13 Wesley13
3年前
java入门(3)
函数和方法如果我们经常要进行一些相似的处理过程,就可以把这个处理过程封装为函数。函数可以被多次重复调用,从而实现代码重用和隔离的目的。在面向对象的语言中,函数经常和对象绑定在一起,为区分起见,这时它被称为方法。因为java是完全面向对象的,函数必须从属于某个类。所以java中的函数都被称为方法。如果方法前以s
go语言中,数组与切片的区别?
切片是Go语言核心的数据结构,然而刚接触Go的程序员经常在切片的工作方式和行为表现上被绊倒。比如,明明说切片是引用类型但在函数内对其做的更改有时候却保留不下来,有时候却可以。究其原因是因为我们很多人用其他语言的思维来尝试猜测Go语言中切片的行为,切片这个内置类型在Go语言底层有其单独的类型定义,而不是我们通常理解的其他语言中数组的概念。文章
Stella981 Stella981
3年前
Go语言中的方法(Method Sets)
物以类聚,人以群分。事物必以类分,以形命名。开始一个个学习Go语言中有哪些数据类型,以及这些类型的特点。Go语言中的方法是函数之外一个特别的概念。在Go语言的参考中说:Atypemayhaveamethodsetassociatedwithit(§Interfacetypes,§Methoddeclarations).
Easter79 Easter79
3年前
Swift讲解专题十二——方法
Swift讲解专题十二——方法一、引言      方法只是一个术语,其实就是将函数与特定的类型结合,类、结构体、枚举都可以定义方法,方法又分为实例方法和类型方法,类型方法类似于ObjectiveC中的类方法。Swift和ObjectiveC的一大不同是,ObjectiveC只有在类中可以定义方法。
Wesley13 Wesley13
3年前
go 的匿名函数和闭包
匿名函数匿名函数是指不需要定义函数名的一种函数实现方式。在Go语言中,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是,Go语言支持随时在代码里定义匿名函数。匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:!(https://
Wesley13 Wesley13
3年前
JAVA自学笔记05
JAVA自学笔记051、方法1)方法就是完成特定功能的代码块,类似C语言中的函数。2)格式:修饰符返回值类型方法名(参数类型参数名1,参数类型参数名2,…){函数体;return返回值;}①修饰符:对于初学者使用publicstatic②返回值类型:方法结果的类型③方
Stella981 Stella981
3年前
CI等MVC框架中为什么不能有index控制器的原因
因为类名称是index而方法又是index,这样index函数就是php4中的构造函数,即实例化类时,直接执行这个函数而没有执行父类的构造函数,也就没有初始化CI核心类。所以会提示没有定义属性或方法了。用index类名也可以,在publicfunctionindex()方法前加上,调用父类的构造方法publicfunction\_\
小万哥 小万哥
7个月前
C++ 类方法解析:内外定义、参数、访问控制与静态方法详解
C类方法类方法,也称为成员函数,是属于类的函数。它们用于操作或查询类数据,并封装在类定义中。类方法可以分为两种类型:类内定义方法:直接在类定义内部声明和定义方法。类外定义方法:在类定义内部声明方法,并在类外部单独定义方法。类内定义方法在类定义内部可以直