手记

你可能不知道的一些Go Packages知识


关于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 main

import (

    "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 10

The square of 10 is 100

The double of 10 is 20

20 100

20 100

函数的返回值可以被命名

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

Part 1

package main

import (

    "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 main

import "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.go

148.83999999999997

144

如果你传入的不是指针,而是常规的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 main

import "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.go

sq: 100

sq: 0xc420014088

函数的返回值可以是函数

下面以returnFunction.go为例:

package main

import "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.go

1: 1

2: 4

j1: 1

j2: 4

3: 9

函数接收其他函数作为参数

下面以funFun.go进行讲解

package main

import "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.go

function1: 246

function2: 15129

Inline: 1860867

©著作权归作者所有:来自51CTO博客作者woahjknes的原创作品,如需转载,请注明出处,否则将追究法律责任


0人推荐
随时随地看视频
慕课网APP