Golang 函数与指针|Go主题月

函数

函数就是一段基本的代码块,通常用来对须要重复执行的代码进行复用。在 go 中,函数是『一等公民』,这与 js 相似,也就是能够将函数当作一个变量进行传递。编程

函数声明

因为是强类型语言,与 js 不一样,在函数声明的过程当中,须要指定参数与返回值的类型。markdown

func max (n1, n2 int) int {
  var result int
  if n1 >= n2 {
    result = n1
  }
  if n1 < n2 {
    result = n2
  }
  return result
}
复制代码

在声明函数参数和类型的时候,与声明变量相似,能够一次性指定多个参数的类型,也能够分别指定多个参数为不一样类型。闭包

func max (n1 int, n2 int) int {
  ……
}
复制代码

若是函数返回值有多个,在指定返回类型的时候,须要指定每一个返回值的类型。app

func max (n1 int, n2 int) (error, int) {
  ……
  return errors.New(""), result
}
复制代码

上面的代码,表示返回的时候须要返回两个值,第一个值为 error 对象,用来表示执行期间是否出现异常。这种方式也是 Node.js 中常见的 error-first callback 的写法。编程语言

特殊函数

在 go 中,有两个特殊函数:maininit,这两个函数声明以后,通常不须要主动调用,会有自动执行的机制。函数

🔎 func main()

main 函数是 go 语言中默认的入口函数,只能应用于 package main 中,若是在其余的 package 中不会执行。main 函数有以下几点须要注意:oop

  • 不能定义参数;
  • 不能定义返回值;
  • 必须在 package main 中声明;

🔎 func init()

init 函数全部的包启动的时候都会执行,执行时机比 main 函数早,与 main 函数同样,不能定义参数和返回值。ui

package main

import "fmt"

func init() {
	fmt.Println("执行 init 函数\n")
}
func main() {
	fmt.Println("执行 main 函数\n")
}
复制代码

函数调用

函数的调用比较简单,和其余编程语言相似,只须要将函数须要接受的参数传入其中,在执行结束后,就能获得对应的返回值。spa

// 定义 max 函数
func max (n1, n2 int) int {
  var result int
  if n1 >= n2 {
    result = n1
  }
  if n1 < n2 {
    result = n2
  }
  return result
}

func main () {
	var result = max(5, 100)
	fmt.Println("max return", result)
}
复制代码

匿名函数

匿名函数就是一个没有定义函数名的函数,匿名函数能够当成一个值,将其赋值放到某个变量中。这也是以前为何说函数是『一等公民』,就是能够将函数当成一个变量。3d

var max = func (n1, n2 int) int {
  var result int
  if n1 >= n2 {
    result = n1
  }
  if n1 < n2 {
    result = n2
  }
  return result
}
var result = max(5, 100)
fmt.Println("max return", result)
复制代码

当即执行函数

因为 go 中的函数是 『一等公民』,能够在声明以后当即执行,就是在函数声明结束后,直接加上一个括号,表示该函数会当即执行,执行以后的结果能够经过变量进行接收。

import "math"

var Pi = func () float64 {
  return math.Pi
}()

fmt.Println("PI =",Pi)
复制代码

闭包

闭包就是可以读取其余函数内部变量的函数。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。 ——百度百科

上面的描述来自百度百科,初次看概念比较难理解,若是站在使用的角度来讲,闭包就是在一个函数调用后,返回另外一个匿名函数,并保持当前函数内的局部变量,能够给匿名函数引用。

下面咱们能够简单实现一个迭代器函数,该函数接受一个切片,返回一个匿名函数,该匿名函数每次执行,都会取出切片的一个值,直到所有读取。

func generate(slice []int) func() (bool, int) {
	i := 0
	length := len(slice)
	return func () (bool, int) {
		if i >= length {
			return true, 0
		}
		var result = slice[i]
		i++
		return false, result
	}
}

func main() {
	slice := []int{1, 2, 3, 4, 5}
	nextNum := generate(slice)
	done, result := nextNum()
  // 直到 done 不等于 false,才中止
	for done == false {
		fmt.Println(result, done)
		done, result = nextNum()
	}
  fmt.Println(result, done)
}
复制代码

指针

咱们前面常说的变量指的通常是一个值,指针是指向该变量存储在内存的位置。指针也能够存储在一个变量中,该变量称为『指针变量』。

指针变量声明

声明指针变量时,须要指针指向哪种类型,由于不一样类型的值在内存占用的空间大小不同,仅仅知道内存地址仍是不够,还须要知道该变量在内存中占用多大空间。声明指针变量只须要在类型前,加上 * 便可。

var point *int // 声明 int 类型的指针
复制代码

指针变量赋值

给指针变量赋值,须要在对应类型的变量前加上&符号,表示取出该变量的地址。

var i = 1
var point *int
point = &i
复制代码

值传递与引用传递

通常状况下,咱们传入函数的参数仅为变量的值,这样的传递被称为值传递,在函数内对参数修改也不会影响到外部变量。

func addOne(slice []int, number int) {
	slice = append(slice, number)
	fmt.Println("inner slice =",  slice)
}

slice := []int{1, 2, 3}
addOne(slice, 100)
fmt.Println("outer slice =",  slice)
复制代码

上述代码中,咱们写了一个函数,会对传入的切片追加一个值,调用以后,咱们会发现外部切片的值并无发生变量。

若是须要外部变量的值会跟随函数调用发生变化,就须要将变量的指针传入函数中,这样的传递被称为引用传递。这样在函数中修改参数就会影响到外部的变量了。

// 此时 slice 为指针变量
func addOne(slice *[]int, number int) {
  // 经过 *slice 能够取出 slice 指针对应的值
	*slice = append(*slice, number)
	fmt.Println("inner slice =",  *slice)
}

slice := []int{1, 2, 3}
addOne(&slice, 100)
fmt.Println("outer slice =",  slice)
复制代码

相关文章
相关标签/搜索