函数

函数构成了要执行的代码,在go语言中,函数的基本组成为:关键字 func,函数名,参数列表,函数体和返回语句.

函数定义:


用一个简单的加法函数例子来进行详细说明:

func aaa(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 ) int {
	//...
}



函数调用


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


import “mymath”// 假设Add被放在一个叫mymath的包中
// …
c := mymath.Add(1, 2)

Java程序员这里需要记住:小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用
也就是说:小写字母开头的函数相当于 private 修饰符,大写字母开头的函数相当于 public 修饰符


#### 不定参数 这里我们介绍不定参数的用法,合适的使用不定参数可以让代码易用,尤其是输入输出,日志函数等.

1:不定参数列表
不定参数是指函数传入的参数个数为不确定数,想做到这点,首先要将函数定义为接收不定参数类型:
例子:

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

这段代码的意思是,函数 arglist() 接收不定数量的参数,但是这些参数的类型必须全部都是 int 类型,所有我们可以这样调用:

arglist(1, 3, 7) 
arglist(1, 3, 7, 13)

从内部机理来说,这种 …type本质上就是一个数组切片,也就是 []type,这也是为什么可以使用 for 循环进行遍历,假设没有 …type,开发者将不得不这样写:

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

从实现的角度来看完全没有任何的影响,该怎么写就这么写,但从调用来看,就完全不同了:

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

你就会发现我们不得不加上 []int 来构建一个数组切片,但是有了这个 …type,我们就不需要自己处理了!




任意类型的不定参数传递

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

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

例子:

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语句时,会返回对应的返回值变量的值.
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值,比如下面的代码表示调用者在读文件的时候不想关心Read()函数返回的错误码:

n, _ := f.Read(buf)