大漠知秋的加油站

  • 首页
大漠知秋的加油站
你就当我的烂笔头吧
  1. 首页
  2. Golang
  3. 正文

函数

2019年1月3日 1151点热度 0人点赞 0条评论

  函数构成代码执行的逻辑结构。在 Go 语言中,函数的基本组成为:关键字 func、函数名、参数列表、返回值、函数体和返回语句。

函数的定义

  这里生命一个最简单的加法函数来说明一下:

package mymath
import "errors"
func Add(a int, b int) (ret int, err error) {
    if a < 0 || b < 0 { // 假设这个函数只支持两个非负数字的加法
        err = errors.New("Should be non-negative numbers!")
        return
    }

    return a + b, nil // 支持多重返回值
}

  如果参数列表中若干个相邻的参数类型的相同,比如上面例子中的 a 和 b,则可以在参数列表中省略前面变量的类型声明,如下所示:

func Add(a, b int) (ret int, err error) {
    // ...
}

  如果不想给返回的多个返回值起变量名的话,也可以这样写:

func Add(a, b int) (int, error) {
    // ...
}

  如果返回值列表中多个返回值的类型相同,也可以用同样的方式合并。如果函数只有一个返回值,也可以这么写:

func Add(a, b int) int {
    // ...
}

函数调用

  函数调用非常方便,只要事先导入了该函数所在的包,就可以直接按照如下所示的方式调用函数:

import "mymath"// 假设Add被放在一个叫mymath的包中

// ...
c := mymath.Add(1, 2)

  在 Go 语言中,函数支持多重返回值。利用函数的多重返回值和错误处理机制,我们可以很容易地写出优雅美观的 Go 代码。

  Go 语言中函数名字的大小写不仅仅是风格,更直接体现了该函数的可见性,这一点尤其需要注意。对于很多注意美感的程序员(尤其是工作在 Linux 平台上的 C 程序员)而言,这里的函数名的首字母大写可能会让他们感觉不太适应,在自己练习的时候可能会顺手改成全小写,比如写成 add_xxx 这样的 Linux 风格。很不幸的是,如果这样做了,你可能会遇到莫名其妙的编译错误,比如你明明导入了对应的包,Go 编译器还是会告诉你无法找到 add_xxx 函数。

  因此需要先牢记这样的规则:小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用。

  这个规则也适用于类型和变量的可见性。

不定参数

  合适地使用不定参数,可以让代码简单易用,尤其是输入输出类函数,比如日志函数等。

不定参数类型

  不定参数是指函数传入的参数个数为不定数量。为了做到这点,首先需要将函数定义为接受不定参数类型:

func myfunc(args ...int) {
    for _, arg := range args {
        fmt.Println(arg)
    }
}

  这段代码的意思是,函数 myfunc() 接受不定数量的参数,这些参数的类型全部是 int,所以它可以用如下方式调用:

myfunc(2, 3, 4)
myfunc(1, 3, 7, 13)

  形如 ...type 格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数。它是一个语法糖(syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说,使用语法糖能够增加程序的可读性,从而减少程序出错的机会。

  从内部实现机理上来说,类型 ...type 本质上是一个数组切片,也就是 []type,这也是为什么上面的参数 args 可以用 for 循环来获得每个传入的参数。

  假如没有 ...type 这样的语法糖,开发者将不得不这么写:

func myfunc2(args []int) {
    for _, arg := range args {
        fmt.Println(arg)
    }
}

  从函数的实现角度来看,这没有任何影响,该怎么写就怎么写。但从调用方来说,情形则完全不同:

myfunc2([]int{1, 3, 7, 13})

  你会发现,我们不得不加上 []int{} 来构造一个数组切片实例。但是有了 ...type 这个语法糖,我们就不用自己来处理了。

不定参数的传递

  假设有另一个变参函数叫做 myfunc3(args ...int),下面的例子演示了如何向其传递变参:

func myfunc(args ...int) {
    // 按原样传递
    myfunc3(args...)
    // 传递片段,实际上任意的int slice都可以传进去
    myfunc3(args[1:]...)
}

任意类型的不定参数

  之前的例子中将不定参数类型约束为 int,如果你希望传任意类型,可以指定类型为 interface{}。下面是 Go 语言标准库中 fmt.Printf() 的函数原型:

func Printf(format string, args ...interface{}) {
    // ...
}

  用 interface{} 传递任意类型数据是 Go 语言的惯例用法。使用 interface{} 仍然是类型安全的,这和 C/C++ 不太一样。关于它的用法,线面代码示范了如何分派传入 interface{} 类型的数据。

package main

import "fmt"

func MyPrintf(args ...interface{}) {
    for _, arg := range args {
        switch arg.(type) {
            case int:
                fmt.Println(arg, "is an int value.")
            case string:
                fmt.Println(arg, "is a string value.")
            case int64:
                fmt.Println(arg, "is an int64 value.")
            default:
                fmt.Println(arg, "is an unknown type.")
        }
    }
}

func main() {
    var v1 int = 1
    var v2 int64 = 234
    var v3 string = "hello"
    var v4 float32 = 1.234
    MyPrintf(v1, v2, v3, v4)
}

  该程序的输出结果为:

1 is an int value.
234 is an int64 value.
hello is a string value.
1.234 is an unknown type.

多返回值

  与 C、C++ 和 Java 等开发语言的一个极大不同在于,Go 语言的函数或者成员的方法可以有多个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码,比如 File.Read() 函数就可以同时返回读取的字节数和错误信息。如果读取文件成功,则返回值中的n为读取的字节数,err 为 nil,否则 err 为具体的出错信息:

func (file *File) Read(b []byte) (n int, err Error)

  同样,从上面的方法原型可以看到,我们还可以给返回值命名,就像函数的输入参数一样。返回值被命名之后,它们的值在函数开始的时候被自动初始化为空。在函数中执行不带任何参数的 return 语句时,会返回对应的返回值变量的值。

  Go 语言并不需要强制命名返回值,但是命名后的返回值可以让代码更清晰,可读性更强,同时也可以用于文档。

  如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线 _ 来跳过这个返回值,比如下面的代码表示调用者在读文件的时候不想关心 Read() 函数返回的错误码:

n, _ := f.Read(buf)

  参考:《Go语言编程》

标签: Golang 函数
最后更新:2019年12月26日

大漠知秋

唯黄昏而思烛明,唯覆雪始念日暖,唯放手方知情真,今困苦而怀峥嵘,今飘零而涌乡愁,今孑然而徒唏嘘,唏嘘成愁。

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

文章目录
  • 函数的定义
  • 函数调用
  • 不定参数
    • 不定参数类型
    • 不定参数的传递
    • 任意类型的不定参数
  • 多返回值

COPYRIGHT © 2023 大漠知秋的加油站. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

豫ICP备16029200号-2