• Welcome to Journal web site.

我是 PHP 程序员

- 开发无止境 -

Next
Prev

5、函数和方法

Data: 2020-01-08 10:49:27Form: JournalClick: 2

函数声明

func 变量名(传入变量 传入数据类型) (返回数据){

}

  • 方法名字:首字母是否大写决定了作用域
  • 传入变量 与 返回数据非必填项,当传入参数不确定数量时可用三个点 … 代替
    func xxxx(a ...interface{}) (n int, err error)
  • 传入变量数据类型不填时,系统会自动根据数据判断类型,但返回数据一旦定义必须赋予类型参数
  • 传入多个变量时使用“,”隔开,同类型放一起时只需要声明一次传入参数类型。
  • golang 支持多返回值,切返回值是可以有名字的
  • 多返回数据需要用括号包裹起来,并用“,”隔开后,可直接return 即可返回定义数据,无需再次return 变量名
  • 多返回值不用其中某一项时,可以使用“_”忽略该返回值

匿名函数和闭包

顾名思义,匿名函数就是没有名字的函数,这是它和正常函数的主要区别。

func main() {
    sum2 := func(a, b int) int {
        return a + b
    }
    fmt.Println(sum2(1, 2))
}

有了匿名函数,就可以在函数中再定义函数(函数嵌套),定义的这个匿名函数,也可以称为内部函数。更重要的是,在函数内定义的内部函数,可以使用外部函数的变量等,这种方式也称为闭包

func main() {
    cl := colsure()
    fmt.Println(cl())
    fmt.Println(cl())
    fmt.Println(cl())
}
func colsure() func() int {
    i := 0
    return func() int {
        i++
        return i
    }
}
 

运行这个代码,你会看到输出打印的结果是:

1
2
3

这都得益于匿名函数闭包的能力,让我们自定义的 colsure 函数,可以返回一个匿名函数,并且持有外部函数 colsure 的变量 i。因而在 main 函数中,每调用一次 cl(),i 的值就会加 1。

 

方法

不同于函数的方法
在 Go 语言中,方法和函数是两个概念,但又非常相似,不同点在于方法必须要有一个接收者,这个接收者是一个类型,这样方法就和这个类型绑定在一起,称为这个类型的方法。
在下面的示例中,type Age uint 表示定义一个新类型 Age,该类型等价于 uint,可以理解为类型 uint 的重命名。其中 type 是 Go 语言关键字,表示定义一个类型。

type Age uint //定义方法名与传入数据类型
func (age Age) String(){    //传入数据与调用方法
    fmt.Println("the age is",age)
}
func main() {
    age := Age(25) //传入数据
    age.String()  //执行方法,输出结果
}

示例中方法 String() 就是类型 Age 的方法,类型 Age 是方法 String() 的接收者。

和函数不同,定义方法时会在关键字 func 和方法名 String 之间加一个接收者 (age Age) ,接收者使用小括号包围。

 

方法的值类型接收者和指针类型接收者

方法的接收者除了可以是值类型(比如上一小节的示例),也可以是指针类型。
定义的方法的接收者类型是指针,所以我们对指针的修改是有效的,如果不是指针,修改就没有效果

type Age uint
func (age Age) String() {
    fmt.Println("the age is", age)
}
// Age加上星号就是指针类型接受者
//不加星号数据将依然还是25
func (age *Age) Modify() {
    *age = Age(30)
}
func main() {
    age := Age(25)
    age.String()    //输出25
    age.Modify()    //指针修改调用为30
    age.String()    //输出30
}
 

提示:在调用方法的时候,传递的接收者本质上都是副本,只不过一个是这个值副本,一是指向这个值指针的副本。指针具有指向原有值的特性,所以修改了指针指向的值,也就修改了原有的值。我们可以简单地理解为值接收者使用的是值的副本来调用方法,而指针接收者使用实际的值来调用方法

 

示例中调用指针接收者方法的时候,使用的是一个值类型的变量,并不是一个指针类型,其实这里使用指针变量调用也是可以的,如下面的代码所示:

(&age).Modify() //指针变量调用,效果同 age.Modify()
  • 如果使用一个值类型变量调用指针类型接收者的方法,Go 语言编译器会自动帮我们取指针调用,以满足指针接收者的要求。

  • 同样的原理,如果使用一个指针类型变量调用值类型接收者的方法,Go 语言编译器会自动帮我们解引用调用,以满足值类型接收者的要求。

总之,方法的调用者,既可以是值也可以是指针,不用太关注这些,Go 语言会帮我们自动转义,大大提高开发效率,同时避免因不小心造成的 Bug。

Name:
<提交>