Skip to content

1.golang函数

1.1golang函数简介

函数的go语言中的 一级公民,我们吧所有的功能单元都定义在函数中,可以重复使用。函数包含函数的名称、参数列表和返回值类型,这些构成了函数的签名(signature)

go语言中函数特性

1.go语言中有3中函数:普通函数、匿名函数、匿名函数(没有名称的函数)、方法(定义在struct上的函数)

2.go语言中不允许函数重载(overload),即不允许函数同名。

3.go语言中的函数不能嵌套函数,但可以嵌套匿名函数。

4.函数是一个值,可以将函数赋值给变量,使得这个变量也称为函数。

5.函数可以作为参数传递给另一个函数。

6.函数的返回值可以是一个函数

7.函数调用的时候,如果有参数传递给函数,则先拷贝参数的副本,再将副本传递给函数。

8.函数参数可以没有名称。

1.2函数的定义和调用

函数在使用之前必须先定义,可以调用函数来完成某个任务。函数可以重复调用,从而达到代码重用。

函数定义语法

go
func function_name([parameter list]) [return_types]
{
|函数体
}
func function_name([parameter list]) [return_types]
{
|函数体
}
  • 解析

func:函数由 func开始声明

function_name:函数名称,函数名和参数列表一起构成了函数签名。

[parameter list]:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。

return_types:返回类型,函数返回一列值。return_types是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types不是必须的。

函数体:函数定义的代码集合。

go函数调用

当我们要完成某个任务时,可以调用函数来完成。调用函数传递参数,如何有返回值可以获得返回值。

go
func main(){
	w := comp(4, 5)
	fmt.Printf("w: %v\n", w)
}
func main(){
	w := comp(4, 5)
	fmt.Printf("w: %v\n", w)
}

实例

求和函数

go
func sumFunc(a int, b int) (ret int) {
	ret = a + b
	return ret
}
func main() {
	r := sumFunc(1, 2)
	fmt.Printf("r: %v\n", r)
}
func sumFunc(a int, b int) (ret int) {
	ret = a + b
	return ret
}
func main() {
	r := sumFunc(1, 2)
	fmt.Printf("r: %v\n", r)
}

比较函数

go
func comp(a int, b int) (max int) {
	if a > b {
		max = a
	} else {
		max = b
	}
	return max
}
func main() {
	w := comp(4, 5)
	fmt.Printf("w: %v\n", w)
}
func comp(a int, b int) (max int) {
	if a > b {
		max = a
	} else {
		max = b
	}
	return max
}
func main() {
	w := comp(4, 5)
	fmt.Printf("w: %v\n", w)
}

2.golang函数的返回值

函数可以有0或多个返回值,返回值需要指定数据类型,返回值通过 return关键字来指定。

return可以有参数,也可以没有参数,这些返回值可以有名称,也可以没有名称。go中的函数可以有多个返回值。

1.return关键字中指定了参数时,返回值可以不用名称。如果 return省略参数,则返回值部分必须带名称

2.当返回值有名称时,必须使用小括号包围,逗号分割,即使只有一个返回值

3.但即使返回值命名了,return中也可以强制指定其它返回值的名称,也就是说 return的优先级更高

4.命名的返回值是预先声明好的,在函数内部可以直接使用,无需再次声明。命名返回值的名称不能和函数参数名称相同,否则报错提示变量重复定义。

5.return中可以有表达式,但不能出现赋值表达式,这和其它语言可能有所不同。列如 return a+b是正确的。但 return c=a+b是错误的

返回值实例

没有返回值

go
func fm1() {
	fmt.Printf("我没有返回值")
}
func main(){
    fm1()
}
func fm1() {
	fmt.Printf("我没有返回值")
}
func main(){
    fm1()
}

有一个返回值

go

func one(a int, b int) (ret int) {
	ret = a + b
	return ret
}

//或者
func one1(a int, b int) int {
	//ret := a + b
	//或者, 直接 return a+b

	return a + b
}




func main() {
	r := 1 + 2
	fmt.Printf("r: %v\n", r)
}

func one(a int, b int) (ret int) {
	ret = a + b
	return ret
}

//或者
func one1(a int, b int) int {
	//ret := a + b
	//或者, 直接 return a+b

	return a + b
}




func main() {
	r := 1 + 2
	fmt.Printf("r: %v\n", r)
}

多个返回值,且在return中指定返回的内容

go
func two() (name string, age int) {
	name = "hell"
	age = 20
	return name, age
}

func main() {
	name, age := two()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}
func two() (name string, age int) {
	name = "hell"
	age = 20
	return name, age
}

func main() {
	name, age := two()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}

多个返回值,返回值名称没有被使用

go
func f3() (name string, age int) {
	name = "hell"
	age = 20
	 return //等同于  return name, age
}

func main() {
	name, age := two()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}
func f3() (name string, age int) {
	name = "hell"
	age = 20
	 return //等同于  return name, age
}

func main() {
	name, age := two()
	fmt.Printf("name: %v\n", name)
	fmt.Printf("age: %v\n", age)
}

return覆盖命名返回值,返回值名称没有被使用

go
func two() (name string, age int) {
	n := "ha"
	a := 30
    //如果是上面这样写,return必须写返回值
	return n, a
}

func main() {
	n, a := two()
	fmt.Printf("name: %v\n", n)
	fmt.Printf("age: %v\n", a)
}
func two() (name string, age int) {
	n := "ha"
	a := 30
    //如果是上面这样写,return必须写返回值
	return n, a
}

func main() {
	n, a := two()
	fmt.Printf("name: %v\n", n)
	fmt.Printf("age: %v\n", a)
}

Go中经常会使用其中一个返回值作为函数是否执行成功、是否有错误信息的判断条件。例如:value,existsreturn value,okreturn value,err

当函数的返回值过多时,例如有4个以上的返回值,应该将这些返回值收集到容器中,然后以返回容器的方式去返回。例如,同类型的返回值可以放进slice中,不同类型的返回值可以放进map中。

但函数有多个返回值时,如果其中某个或某几个返回值不想使用,可以通过下划线 _来丢弃这些返回值。例如下面的 f1函数两个返回值,调用该函数时,丢弃了第二个返回值b,只保留了第一个返回值a赋值给了变量 a

go
func f1()(int ,int){
    return 1,2
}
func main(){
    _, x:=f1()
    fmt.Printf(x)
}
func f1()(int ,int){
    return 1,2
}
func main(){
    _, x:=f1()
    fmt.Printf(x)
}

3.golang函数的参数

  • 无参无返回值函数
  • 有一个参数的函数
  • 有两个参数的函数
  • 有一个返回值的函数
  • 有多个返回值的函数

go函数可以有0或多个参数,参数需要指定 数据类型

声明函数时的参数参数列表叫做 形参,调用时传递的参数叫做 实参

go语言是通过传值的方式传参的,意味着传递给函数的是拷贝后的副本,所以函数内部访问、修改的也是这个副本。

go语言可以使用 变长参数,有时候并不能确定参数的个数,可以使用变长参数,可以在函数定义语句的参数部分使用 ARGS...TYPE的方式。这时会将 ...代表的参数全部保存到一个名为ARGS的slice中,注意这些参数的数据类型都是TYPE。

3.1实例

形参,实参

go
// 形参
func one1(a int, b int) int {
	//ret := a + b
	//或者, 直接 return a+b

	return a + b
}

func main(){
    // 实参
    r = one1(2, 4)
	fmt.Printf("r: %v\n", r)
}
// 形参
func one1(a int, b int) int {
	//ret := a + b
	//或者, 直接 return a+b

	return a + b
}

func main(){
    // 实参
    r = one1(2, 4)
	fmt.Printf("r: %v\n", r)
}

按值传递

go
//copy
func f1copy(a int) {
	a = 100
    fmt.Printf("a: %v\n", a)
}

func main() {
	x := 200
	f1copy(x)
	fmt.Printf("x: %v\n", x)
}
//copy
func f1copy(a int) {
	a = 100
    fmt.Printf("a: %v\n", a)
}

func main() {
	x := 200
	f1copy(x)
	fmt.Printf("x: %v\n", x)
}

从运行结果可以看到,调用函数f1copy后, a的值并没有被改变,说明参数传递是拷贝了一个副本,也就是拷贝了一份新的内容进行运算

mapsliceinterfacechannel这些数据类型本身就是指针类型的,所以计算是拷贝传值也是拷贝的指针,拷贝后的参数仍然指向底层数据结构,所以修改它们 可能会影响外部数据结构的值。

go
//map
func f1map(s []int) {
	s[0] = 1000
}

func main() {
	s := []int{1, 2, 3}
	f1map(s)
	fmt.Printf("s: %v\n", s)
}
//运行结果,调用函数后,slice内容被改变了
s: [1000 2 3]
//map
func f1map(s []int) {
	s[0] = 1000
}

func main() {
	s := []int{1, 2, 3}
	f1map(s)
	fmt.Printf("s: %v\n", s)
}
//运行结果,调用函数后,slice内容被改变了
s: [1000 2 3]

变长参数

go
func argFunc(args ...int) {
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}

func main() {
	argFunc(1, 2, 3, 4)
	argFunc(7, 8, 9)
}
func argFunc(args ...int) {
	for _, v := range args {
		fmt.Printf("v: %v\n", v)
	}
}

func main() {
	argFunc(1, 2, 3, 4)
	argFunc(7, 8, 9)
}

4.函数类型和函数变量

可以使用 type关键字来定义一个函数类型,语法:

go
type fun func(int,int)int

fun --->起名字
type fun func(int,int)int

fun --->起名字

上面语句定义了个 fun函数类型,它是一种函数类型,这种函数接收连个 int类型的参数并且返回一个 int类型的返回值

go
func sum(a int, b int)int{
	return a + b
}

func max(a int, b int) int{
    if a > b {
        return a
    }else{
        return b
    }
}
func sum(a int, b int)int{
	return a + b
}

func max(a int, b int) int{
    if a > b {
        return a
    }else{
        return b
    }
}

下面定义一个 fun函数类型,吧 summax复制给它

go
func Sum(a int, b int) int {
	return a + b
}

func Max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}
func main() {
	type f11 func(int, int) int
	var ff f11
	ff = Sum
	r := ff(1, 3)
	fmt.Printf("r: %v\n", r)
  
    ff = Max
	r = Max(1, 3)
	fmt.Printf("r: %v\n", r)
}
func Sum(a int, b int) int {
	return a + b
}

func Max(a int, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}
func main() {
	type f11 func(int, int) int
	var ff f11
	ff = Sum
	r := ff(1, 3)
	fmt.Printf("r: %v\n", r)
  
    ff = Max
	r = Max(1, 3)
	fmt.Printf("r: %v\n", r)
}

5.高阶函数

go语言的函数,可以作为函数的参数,传递给另外一个函数,作为另外一个函数的返回值返回。

5.1函数作为参数

go
func sayHello(name string) {
	fmt.Printf("hello,%s", name)
}

func test(name string, f func(string)) {
	f(name)
}

func main() {
	test("tom", sayHello)
}
func sayHello(name string) {
	fmt.Printf("hello,%s", name)
}

func test(name string, f func(string)) {
	f(name)
}

func main() {
	test("tom", sayHello)
}

5.2go语言函数作为返回值

go
func add(x, y int) int {
	return x + y
}
func sub(x, y int) int {
	return x - y
}
func cal(oper string) func(int, int) int {
	switch oper {
	case "+":
		return add
	case "-":
		return sub
	default:
		return nil
	}
}
func main() {
	f := cal("+")
	r := f(1, 2)
	fmt.Printf("r: %v\n", r)
	f = cal("-")
	r = f(3, 2)
	fmt.Printf("r: %v\n", r)
}
func add(x, y int) int {
	return x + y
}
func sub(x, y int) int {
	return x - y
}
func cal(oper string) func(int, int) int {
	switch oper {
	case "+":
		return add
	case "-":
		return sub
	default:
		return nil
	}
}
func main() {
	f := cal("+")
	r := f(1, 2)
	fmt.Printf("r: %v\n", r)
	f = cal("-")
	r = f(3, 2)
	fmt.Printf("r: %v\n", r)
}

6.匿名函数

go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用。

所谓匿名函数就是,没有名称的函数。

go
func(参数列表)(返回值)
func(参数列表)(返回值)

当然可以既没有参数,可以没有返回值

  • 实例
go
func main(){
    max := func(a int, b int)int {
        if a > b{
            return a
        }else{
            return b
        }
    }
    r:=max(1,2)
    fmt.Printf(r)
}

//或者,自己调用自己
func main(){
    r:=func(a int, b int)int{
        if a >b{
            return a
        }else{
            return b
        }
    }(1,2)
    fmt.Printf(r)
}
func main(){
    max := func(a int, b int)int {
        if a > b{
            return a
        }else{
            return b
        }
    }
    r:=max(1,2)
    fmt.Printf(r)
}

//或者,自己调用自己
func main(){
    r:=func(a int, b int)int{
        if a >b{
            return a
        }else{
            return b
        }
    }(1,2)
    fmt.Printf(r)
}
  • 在函数内部做一些运算
go
func test1(){
    name := "tom"
    age := "20"
    //
    f1 := func()string{
        return name + age
    }
    msg:=f1()
    fmt.Printf("msg:%v\n",msg)
}
func test1(){
    name := "tom"
    age := "20"
    //
    f1 := func()string{
        return name + age
    }
    msg:=f1()
    fmt.Printf("msg:%v\n",msg)
}