函数
函数构成了要执行的代码,在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)