ch5-3: fmt code

This commit is contained in:
chai2010 2016-01-04 13:34:32 +08:00
parent 66fc5f98d2
commit 11aa8aeaf6

View File

@ -4,43 +4,38 @@
下面的程序是findlinks的改進版本。脩改後的findlinks可以自己發起HTTP請求這樣我們就不必再運行fetch。因爲HTTP請求和解析操作可能會失敗因此findlinks聲明了2個返迴值鏈接列表和錯誤信息。一般而言HTML的解析器可以處理HTML頁面的錯誤結點構造出HTML頁面結構所以解析HTML很少失敗。這意味着如果findlinks函數失敗了很可能是由於I/O的錯誤導致的。 下面的程序是findlinks的改進版本。脩改後的findlinks可以自己發起HTTP請求這樣我們就不必再運行fetch。因爲HTTP請求和解析操作可能會失敗因此findlinks聲明了2個返迴值鏈接列表和錯誤信息。一般而言HTML的解析器可以處理HTML頁面的錯誤結點構造出HTML頁面結構所以解析HTML很少失敗。這意味着如果findlinks函數失敗了很可能是由於I/O的錯誤導致的。
``` ```Go
gopl.io/ch5/findlinks2 gopl.io/ch5/findlinks2
func main() { func main() {
for _, url := range os.Args[1:] { for _, url := range os.Args[1:] {
links, err := findLinks(url) links, err := findLinks(url)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "findlinks2: %v\n", fmt.Fprintf(os.Stderr, "findlinks2: %v\n", err)
err) continue
continue }
} for _, link := range links {
for _, link := range links { fmt.Println(link)
fmt.Println(link) }
} }
}
} }
// findLinks performs an HTTP GET request for url, parses // findLinks performs an HTTP GET request for url, parses the
the
// response as HTML, and extracts and returns the links. // response as HTML, and extracts and returns the links.
func findLinks(url string) ([]string, error) { func findLinks(url string) ([]string, error) {
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
resp.Body.Close() resp.Body.Close()
return nil, fmt.Errorf("getting %s: %s", url, return nil, fmt.Errorf("getting %s: %s", url, resp.Status)
resp.Status) }
} doc, err := html.Parse(resp.Body)
doc, err := html.Parse(resp.Body) resp.Body.Close()
if err != nil {
resp.Body.Close() return nil, fmt.Errorf("parsing %s as HTML: %v", url, err)
if err != nil { }
return nil, fmt.Errorf("parsing %s as HTML: %v", return visit(nil, doc), nil
url, err)
}
return visit(nil, doc), nil
} }
``` ```
@ -50,26 +45,28 @@ return visit(nil, doc), nil
調用多返迴值函數時,返迴給調用者的是一組值,調用者必鬚顯式的將這些值分配給變量: 調用多返迴值函數時,返迴給調用者的是一組值,調用者必鬚顯式的將這些值分配給變量:
``` ```Go
links, err := findLinks(url) links, err := findLinks(url)
``` ```
如果某個值不被使用可以將其分配給blank identifier: 如果某個值不被使用可以將其分配給blank identifier:
``` ```Go
links, _ := findLinks(url) // errors ignored links, _ := findLinks(url) // errors ignored
``` ```
一個函數內部可以將另一個有多返迴值的函數作爲返迴值下面的例子展示了與findLinks有相同功能的函數兩者的區别在於下面的例子先輸出參數 一個函數內部可以將另一個有多返迴值的函數作爲返迴值下面的例子展示了與findLinks有相同功能的函數兩者的區别在於下面的例子先輸出參數
``` ```Go
func findLinksLog(url string) ([]string, error) { func findLinksLog(url string) ([]string, error) {
log.Printf("findLinks %s", url) log.Printf("findLinks %s", url)
return findLinks(url) return findLinks(url)
} }
``` ```
當你調用接受多參數的函數時可以將一個返迴多參數的函數作爲該函數的參數。雖然這很少出現在實際生産代碼中但這個特性在debug時很方便我們隻需要一條語句就可以輸出所有的返迴值。下面的代碼是等價的 當你調用接受多參數的函數時可以將一個返迴多參數的函數作爲該函數的參數。雖然這很少出現在實際生産代碼中但這個特性在debug時很方便我們隻需要一條語句就可以輸出所有的返迴值。下面的代碼是等價的
``` ```Go
log.Println(findLinks(url)) log.Println(findLinks(url))
links, err := findLinks(url) links, err := findLinks(url)
log.Println(links, err) log.Println(links, err)
@ -77,7 +74,7 @@ log.Println(links, err)
準確的變量名可以傳達函數返迴值的含義。尤其在返迴值的類型都相同時,就像下面這樣: 準確的變量名可以傳達函數返迴值的含義。尤其在返迴值的類型都相同時,就像下面這樣:
``` ```Go
func Size(rect image.Rectangle) (width, height int) func Size(rect image.Rectangle) (width, height int)
func Split(path string) (dir, file string) func Split(path string) (dir, file string)
func HourMinSec(t time.Time) (hour, minute, second int) func HourMinSec(t time.Time) (hour, minute, second int)
@ -87,35 +84,34 @@ func HourMinSec(t time.Time) (hour, minute, second int)
如果一個函數將所有的返迴值都顯示的變量名那麽該函數的return語句可以省略操作數。這稱之爲bare return。 如果一個函數將所有的返迴值都顯示的變量名那麽該函數的return語句可以省略操作數。這稱之爲bare return。
``` ```Go
// CountWordsAndImages does an HTTP GET request for the // CountWordsAndImages does an HTTP GET request for the HTML
HTML // document url and returns the number of words and images in it.
// document url and returns the number of words and images func CountWordsAndImages(url string) (words, images int, err error) {
in it. resp, err := http.Get(url)
func CountWordsAndImages(url string) (words, images int, if err != nil {
err error) { return
resp, err := http.Get(url) }
if err != nil { doc, err := html.Parse(resp.Body)
return resp.Body.Close()
if err != nil {
err = fmt.Errorf("parsing HTML: %s", err)
return
}
words, images = countWordsAndImages(doc)
return
} }
doc, err := html.Parse(resp.Body) func countWordsAndImages(n *html.Node) (words, images int) { /* ... */ }
resp.Body.Close()
if err != nil {
err = fmt.Errorf("parsing HTML: %s", err)
return
}
words, images = countWordsAndImages(doc)
return
}
func countWordsAndImages(n *html.Node) (words, images int)
{ /* ... */ }
``` ```
bare return 按照返迴值列表的次序返迴所有的返迴值在上面的例子中每一個return語句等價於 按照返迴值列表的次序返迴所有的返迴值在上面的例子中每一個return語句等價於
```
```Go
return words, images, err return words, images, err
``` ```
當一個函數有多處return語句以及許多返迴值時bare return 可以減少代碼的重複但是使得代碼難以被理解。舉個例子如果你沒有仔細的審査代碼很難發現前2處return等價於 return 0,0,errGo會將返迴值 words和images在函數體的開始處根據它們的類型將其初始化爲0最後一處return等價於 return wordsimagenil。基於以上原因不宜過度使用bare return。 當一個函數有多處return語句以及許多返迴值時bare return 可以減少代碼的重複但是使得代碼難以被理解。舉個例子如果你沒有仔細的審査代碼很難發現前2處return等價於 return 0,0,errGo會將返迴值 words和images在函數體的開始處根據它們的類型將其初始化爲0最後一處return等價於 return wordsimagenil。基於以上原因不宜過度使用bare return。
練習 **5.5** 實現countWordsAndImages。參考練習4.9如何分詞) **練習 5.5** 實現countWordsAndImages。參考練習4.9如何分詞)
練習 **5.6** 脩改gopl.io/ch3/surface (§3.2) 中的corner函數將返迴值命名併使用bare return。
**練習 5.6** 脩改gopl.io/ch3/surface (§3.2) 中的corner函數將返迴值命名併使用bare return。