关于Go Package

Go Packages 主要用来把相关的functions, variables, 和constants 组织到一起,这样你就可以很方便的迁移Packages和把它们用到自己的程序中。

注意除了main package, Go packages 不是自治程序,不能被编译成可执行文件。它们必须直接或者间接的被main package调用才能使用。
如果你直接执行一个没个package:

$ go run aPackage.go
go run: cannot run non-main package

关于Go function

匿名函数(anonymous functions)
匿名函数可以在内部定义,而不需要使用函数名,匿名函数通常被用来实现一些不需要太多代码的功能。在Go中 一个函数可以返回一个匿名函数,或者使用匿名函数作为它的其中一个参数。另外,匿名函数可以通过变量来访问。注意,在函数式编程术语中,匿名函数也称为闭包。
匿名函数具有较小的实现和功能集中点,这被认为是一种很好的做法。但是如果匿名函数没有功能集中点,那么你可能需要考虑使用常规函数。
注意不要在没有特殊需求的时候使用大量的匿名函数。

Go 函数可以返回多个值

func aFunction() (int, int, float64, float64) {
}

下面会有一个用一个functions.go来展示Go的匿名函数

package mainimport ( "fmt" "os" "strconv")func doubleSquare(x int) (int, int) { //函数返回两个int 类型的值 return x * x, x * x }func main() { arguments := os.Args if len(arguments) != 2 { fmt.Println("The program needs 1 argument!") return } y, err := strconv.Atoi(arguments[1]) if err != nil { fmt.Println(err) return } square := func (s int) int { //square的值为一个匿名函数 return s * s } fmt.Println("The square of", y, "is", square(y)) double := func (s int) int { //double的值为一个匿名函数 return s + s } fmt.Println("The double of", y, "is", double(y)) fmt.Println(doubleSquare(y)) d, s := doubleSquare(y) fmt.Println(d, s)}

上面的square 和 double 都持有一个匿名函数。不好的一点是,在以后的程序中你可以更改square,double或之后其他变量值为匿名函数的变量,这意味着这些变量的含义可以更改或计算成其他内容。

修改值为匿名函数变量的值是不推荐的,因为这可能是导致非常难以排查bug的主要原因。

如上面所示我们可以直接打印doubleSquare()的返回值,也可以给他们分配不同的变量进行打印。

执行functions.go:

$ go run function.go 1 21 The program needs 1 argument!rMacBook:code mtsouk$ go run functions.go 10The square of 10 is 100The double of 10 is 2020 10020 100函数的返回值可以被命名

下面以returnNames.go为例,我们会把returnNames.go的代码分成3部分来进行讲解
Part 1

package mainimport ( "fmt" "os" "strconv")func nameMinMax(x, y int) (min, max int) { if x > y { min = y max = x } else { min = x max = y } return}

在上面这段代码中函数namedMinMax并没有再return中指明返回值,但是由于我们在函数中定义了和函数返回值同名的变量,所以该函数会按照名称对应关系返回。

Part2

func minMax(x, y int) (min, max int) { if x > y { min = y max = x } else { min = x max = y } return min, max}

在这段代码中我们在return 后面指定了返回值 mix,max。 注意改return中 min和max的顺序一定要先min,再max,因为该函数中 return并不是按照函数中的变量名和函数返回中的变量名对应关系返回的。

Part3: 即 returnNames.go的最后一段代码

func main() { arguments := os.Args if len(arguments) < 3 { fmt.Println("The program needs at least 2 arguments!") return } a1, _ := strconv.Atoi(arguments[1]) a2, _ := strconv.Atoi(arguments[2]) fmt.Println(minMax(a1, a2)) min, max := minMax(a1, a2) fmt.Println(min, max) fmt.Println(nameMinMax(a1, a2)) min, max = nameMinMax(a1, a2) fmt.Println(min, max)}

下面执行returnNames.go:

$ go run returnNames.go -20 1-20 1-20 1-20 1-20 1指针可以作为函数的参数

下面以ptrFun.go进行讲解

package mainimport "fmt"func getPtr(v *float64) float64 { return *v * *v}func main() { x := 12.2 fmt.Println(getPtr(&x)) x = 12 fmt.Println(getPtr(&x))}

上面的函数接收一个指针作为其参数,你可以使用"&"符号来获得一个变量的指针(变量的内存地址)。
执行ptrFun.go

$ go run main.go148.83999999999997144

如果你传入的不是指针,而是常规的12,即getPtr(12.12),程序回报下面错误:

$ go run ptrFun.go# command-line-arguments./ptrFun.go:15:21: cannot use 12.12 (type float64) as type *float64 in argument to getPtr函数可以返回指针

下面以returnPtr.go为例:

package mainimport "fmt"func returnPtr(x int) *int { y := x * x return &y}func main() { sq := returnPtr(10) fmt.Println("sq:", *sq) // "*" 用来获取存储在sq内存地址中的值 fmt.Println("sq:", sq) // 该print会返回sq变量的内存地址,而不是int值}

上面代码中我们定义了returnPtr函数,该函数返回一个init类型的指针。注意我们需要在return后面 &y来返回y变量的内存地址。

$ go run returnPtr.gosq: 100sq: 0xc420014088函数的返回值可以是函数

下面以returnFunction.go为例:

package mainimport "fmt"func funReturnFun() func() int { //该函数的返回值为匿名函数 i := 0 return func() int { i ++ return i * i }}func main() { //下面调用两次funReturnFun(),并把他们的返回值(匿名函数)分别赋值给i,j //在下面的print中你会看到i,和 j是两个完全独立的变量,没有任何关联 i := funReturnFun() j := funReturnFun()//下面分通过i()和j()的方式调用了3次i变量,和2次j变量。//注意i 和 j 都是通过调用 funRetrunFun()函数创建的,但是他们是完全独立的,不会共享任何东西。也不会互相干扰 fmt.Println("1:", i()) fmt.Println("2", i()) fmt.Println("j1", j()) fmt.Println("j2", j()) fmt.Println("3:", i())}

下面执行returnFunction.go

$ go run returnFunction.go1: 12: 4j1: 1j2: 43: 9函数接收其他函数作为参数

下面以funFun.go进行讲解

package mainimport "fmt"func function1(i int) int { // 声明函数function1 return i + i}func function2(i int) int { //声明函数function2 return i * i}func funFun(f func(int) int,v int ) int { //该函数接收一个函数作为它的第一个参数,一个int类型作为第二个参数 return f(v) //把函数的第二个参数传给第一个参数函数}func main() { fmt.Println("function1:", funFun(function1, 123)) //funciton1作为functFun的第一个参数 fmt.Println("function2", funFun(function2, 123)) //funciton1作为functFun的第一个参数 fmt.Println("Inline:", funFun(func(i int) int { return i * i * i }, 123)) //一个函数作为参数

运行上面的代码

$ go run funFun.gofunction1: 246function2: 15129Inline: 1860867