mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-24 15:18:57 +00:00
ch5-3: fmt code
This commit is contained in:
parent
66fc5f98d2
commit
11aa8aeaf6
122
ch5/ch5-03.md
122
ch5/ch5-03.md
@ -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 {
|
||||||
doc, err := html.Parse(resp.Body)
|
err = fmt.Errorf("parsing HTML: %s", err)
|
||||||
resp.Body.Close()
|
return
|
||||||
if err != nil {
|
}
|
||||||
err = fmt.Errorf("parsing HTML: %s", err)
|
words, images = countWordsAndImages(doc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
words, images = countWordsAndImages(doc)
|
func countWordsAndImages(n *html.Node) (words, images int) { /* ... */ }
|
||||||
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,err(Go會將返迴值 words和images在函數體的開始處,根據它們的類型,將其初始化爲0),最後一處return等價於 return words,image,nil。基於以上原因,不宜過度使用bare return。
|
當一個函數有多處return語句以及許多返迴值時,bare return 可以減少代碼的重複,但是使得代碼難以被理解。舉個例子,如果你沒有仔細的審査代碼,很難發現前2處return等價於 return 0,0,err(Go會將返迴值 words和images在函數體的開始處,根據它們的類型,將其初始化爲0),最後一處return等價於 return words,image,nil。基於以上原因,不宜過度使用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。
|
||||||
|
Loading…
Reference in New Issue
Block a user