函数声明
func name(parameter-list) (result-list) {
body
}
递归
菲波那契数列示例:
func fib(x int) int {
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}
多返回值
两个值交换,很方便。
i, j = j, i
错误
对于那些将运行失败看作是预期结果的函数,它们会返回一个额外的返回值,通常是最后一个,来传递错误信息。如果导致失败的原因只有一个,额外的返回值可以是一个布尔值,通常被命名为 ok。比如,cache.Lookup 失败的唯一原因是 key 不存在,那么代码可以按照下面的方式组织:
value, ok := cache.Lookup(key)if !ok {
// ...cache[key] does not exist...
}
通常,导致失败的原因不止一种,尤其是对 I/O 操作而言,用户需要了解更多的错误信息。因此,额外的返回值不再是简单的布尔类型,而是 error 类型。
内置的 error 是接口类型。我们将在第七章了解接口类型的含义,以及它对错误处理的影响。现在我们只需要明白 error 类型可能是 nil 或者 non-nil。nil 意味着函数运行成功,non-nil 表示失败。对于 non-nil 的 error 类型,我们可以通过调用 error 的 Error 函数或者输出函数获得字符串类型的错误信息。
resp, err := http.Get(url)
if err != nil{
fmt.Println(err)
return nill, err
}
Deferred 函数
defer 语句经常被用于处理成对的操作,如打开、关闭、连接、断开连接、加锁、释放锁。通过 defer 机制,不论函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。释放资源的 defer 应该直接跟在请求资源的语句后。
示例:
func title(url string) error {
resp, err := http.Get(url)if err != nil {
return err
}
defer resp.Body.Close()
ct := resp.Header.Get("Content-Type")
if ct != "text/html" && !strings.HasPrefix(ct,"text/html;") {
return fmt.Errorf("%s has type %s, not text/html",url, ct)
}
doc, err := html.Parse(resp.Body)
if err != nil {
return fmt.Errorf("parsing %s as HTML: %v", url,err)
}
// ...print doc's title element...
return nil
}
有了defer,就不用在后续的return之前再去反复调用resp.Body.Close()
了。