Go语言学习


1,函数

1.1 函数的定义

Go支持匿名函数和闭包,Go的函数类似Python可以返回多个值。Go也是静态编译型的语言。先来看看Go的函数定于格式:

func 函数名(参数表...) [(返回值...)] {
    //函数体
}

注意:

  1. 返回值在参数表后定义,如果只有一个返回值,那么返回值两边的括号是不要的,如果没有返回值那么返回值这一项可以省略。
  2. 函数体的开始大括号必须在行尾,这是强制的,类似的if, switch中的也是如此。
  3. 如果函数名大写字母开头,那么就是对外可见的(exported, public)。如果是小写字母那么就是包内(package level)私有的。

1.2 成员函数定义

func (t *type) 函数名(参数表...) [(返回值...)] {
    //函数体
}

这样就可以为type定义一个成员函数了。

1.3 函数的嵌套

你可以在一个函数体内定义匿名函数甚至你可以定义匿名函数,然后用变量去引用这个匿名函数。但是你不可以在函数体内嵌套定义一个具名函数。

func main() {
    func () {
        fmt.Println("anonymous func is ok")
    }()

    var foo = func () {
        fmt.Println("using a variable to refer anonymous func is ok")
    }
    foo()

    func notAllow() {
        fmt.Println("you can not define named func")
    }
}

匿名函数在这里有值(value type)的语义。你可以像对待一个值那样去对待匿名函数(当参数传递,作为函数返回值)。但是具名函数不享有这种优待。相对于JavaScript或Lisp这样的语言,他缺少了“可以在任意位置定义函数”的能力。在Go中,匿名函数有这种能力。

2,构建系统(build)

2.1 GOPATH

当前的项目目录要添加到GOPATH中,你可以用$go env来检查你当你的环境变量,包括GOPATH。

如果,你想列出当前目录下所有的包(packages),可以使用

$go list ./…

当你GOPATH设置过了以后,你所有以go开头的命令,都是以GOPATH指定的项目目录为起始目录的。

比如:

$go test algorithm/bubblesort #目录为[项目ROOT]src/algorithm/bubblesort,go test是找src目录下的还有test的包

3,三个点(…)

对于定义不定参数数量的函数需要三个点…:

func(a, b int, z float64, opt ...interface{})

最后一个为任意类型的的不定参数,用...来标明。

还有个时常用到…的地方是对数组切片添加元素,当添加的元素是数组或数组切片类型的,append(arr, …T)需要将元素“打散”以当做不定参数来传递,这时也要用到...:

s2 := append(s1, 3, 5, 7)  //一个一个传递
s3 := append(s2, s0...)    //将数组“打散传递”

4,goroutine

goroutine是Go语言在语言级别对并发的支持。并发执行体的粒度从系统到轻量级线程分别有:进程,线程,轻量级线程。goroutine应该算是轻量级线程,在我的电脑上(Win7, Intel i7)可以在3s内创建大约300,000个goroutine。

对于并发来说最大的问题是同步和通信,在Go语言中同步和通信是通过语言内置的channel来近乎完美解决的。channel不仅仅是goroutine通信的方式,也通过自动阻塞这种方式达到了同步的目的。channel可以作为函数的参数传来传去,channel这个参数在使用上像一个引用类型。他可以跨“函数”传递消息。然而实际上他是值类型,channel是函数通信的边界,你不能通过channel来执行还有副作用的赋值操作——当然,除了你通过传递一个指针硬要这么做。

package main 
import "fmt"

func intGenerator(ch chan int) {
    for i := 0; i < 10; i++ {
        ch <- i    //pass the i to the channel
    }
    close(ch)  //close the channel
}

func main() {
    var ch chan int = make(chan int)
    go intGenerator(ch)
    for {
        val, ok := <-ch  //if channel closed, the ok will be false
        if ok {
            fmt.Println(val)  
        } else {
            return
        }
    }
}
published at April 3, 2013, 8 a.m.

Comments:

Sharing your thoughts: