Go-函数

773 阅读1分钟

Go 语言可以很方便的自定义函数,其中有特殊的函数 main 函数。main 函数必须出现在 main 包里,且只能出现一次。当 Go 程序运行时候会自动调用 main 函数开始整个程序的执行。main 函数不可接收任何参数,也不返回任何结果。

函数的定义

在 Go 语言中,函数的基本组成包括:关键字 func、函数名、参数列表、返回值、函数体和返回语句,这里我们用一个简单的加法函数来对函数的定义进行说明。

package add

func Add(a int, b int) (num int){
    return a + b
}

函数的调用

函数调用非常简单,先将被调用函数所在的包导入,就可以直接使用该函数了。注意需要把包文件夹放到 $GOPATH 目录中,实例如下:

package main

import (
    "add" //导入 add 包
    "fmt"
)

func main(){
    c := add.Add(1, 2) //调用 add 包中的 add 函数
    fmt.Println(c)
}

与 C/C++ 和 JAVA 不同,Go 语言的函数和方法可以有多个返回值,这是 Go 提供的一个优美的特性,示例如下:

package Divide
import "errors"

func divide (a int, b int) (num int, err error){ //定义两个返回值
    if b == 0 {
        err = errors.New("被除数不能为零!")
        return
    }
    return a / b, nil   //支持多个返回值
}

匿名函数

在 Go 语言中,你可以在代码里随时定义匿名函数,匿名函数由一个不带函数名的函数声明和函数体组成,示例如下:

func (a, b, c int) bool {
    return a * b < c
}

你可以将匿名函数直接赋值给一个变量,也可以直接调用运行,示例如下:

x := func (a, b, c int) bool {
    return a * b < c
}

func (a, b, c int) bool {
    return a * b < c
} (1, 2, 3) //小括号内直接给参数列表表示函数调用

类型转换

Go 语言提供了一种在不同但相互兼容的类型之间相互转换的方式,这种转换非常有用并且是安全的。但是需要注意的是在数值之间进行转换可能造成其他问题,如精度丢失或者错误的结果。以下是类型转换的语法:

  • resultOfType := Type(expression)

几个例子:

x := int16(2345)        // 声明一个类型为int16的整数,其值为2345
y := int32(x)           // 将int16类型的整数转换为int32类型
a := uint16(65000)       // 声明一个类型为uint16类型的整数
b := int16(a)           // 转换为int16类型,虽然能转换成功,但是由于65000超过in16类型的范围,会导致结果错误,b的值为 -536

另外在 Go 语言中可以通过 type 关键字声明类型,如 type StringsSlice []string 将 []string(string 类型的切片)声明为 StringSlice 类型。

类型断言

说到类型断言就需要先了解下 Go 语言中的接口。在 Go 语言中接口是一个自定义类型。它声明了一个或者多个方法。任何实现了这些方法的对象(类型)都满足这个接口。

接口是完全抽象的,不能实例化。interface{} 类型表示一个空接口,任何类型都满足空接口。也就是说 interface{} 类型的值可以用于表示任意 Go 语言类型的值。

这里的空接口有点类似于 Python 语言中的 object 实例。既然 interface{} 可以用于表示任意类型,那有的时候我们需要将 interface{} 类型转换为我们需要的类型,这个操作称为类型断言。

一般情况下只有我们希望表达式是某种特定类型的值时才使用类型断言。Go 语言中可以使用以下语法:

resultOfType, boolean := expression.(Type):安全的类型断言。resultOfType := expression.(Type):非安全的类型断言,失败时程序会产生异常。

创建源文件 type_t.go,输入以下源文件:

package main

import (
    "fmt"
)

func main() {
    x := uint16(65000)
    y := int16(x) // 将 x转换为int16类型
    fmt.Printf("type and value of x is: %T and %d\n", x, x) // %T 格式化指令的作用是输出变量的类型
    fmt.Printf("type and value of y is: %T and %d\n", y, y)

    var i interface{} = 99 // 创建一个interface{}类型,其值为99
    var s interface{} = []string{"left", "right"}
    j := i.(int) // 我们假设i是兼容int类型,并使用类型断言将其转换为int类型
    fmt.Printf("type and value of j is: %T and %d\n", j, j)

    if s, ok := s.([]string); ok { // 创建了影子变量,if的作用域中覆盖了外部的变量s
        fmt.Printf("%T -> %q\n", s, s)
    }
}

运行程序:

$ go run type_t.go
type and value of x is: uint16 and 65000
type and value of y is: int16 and -536
type and value of j is: int and 99
[]string -> ["left" "right"]