init
init內容
本書推薦將map對映(或者叫註冊)之類的準備工作放在init裡面,Golang會保證init中的函式在main函式呼叫之前執行完畢。例如:
// init registers the default matcher with the program.
func init() {
var matcher defaultMatcher
Register("default", matcher)
}
// Register is called to register a matcher for use by the program.
func Register(feedType string, matcher Matcher) {
if _, exists := matchers[feedType]; exists {
log.Fatalln(feedType, "Matcher already registered")
}
log.Println("Register", feedType, "matcher")
matchers[feedType] = matcher
}
或者也可以註冊資料庫驅動:
// init is called prior to main.
func init() {
d = new(PostgresDriver)
sql.Register("postgres", d)
}
如何使用init
我們使用下劃線識別符號作為別名匯入包,完成了這個呼叫。這種方法可以讓編譯器在匯入未被引用的包時不報錯,而且依舊會定位到包內的init函式。程式碼如下:
import (
_ "December15/sample/matchers"
"December15/sample/search"
)
或者這樣使用資料庫
package main
import (
"database/sql"
_ "github.com/goinaction/code/chapter3/dbdriver/postgres"
)
// main is the entry point for the application.
func main() {
sql.Open("postgres", "mydb")
}
結構型別
golang中沒有類的概念,這裡的結構型別的作用就相當於java裡面的類,例如這裡定義了4個類:
type (
// item defines the fields associated with the item tag
// in the rss document.
item struct {
XMLName xml.Name `xml:"item"`
PubDate string `xml:"pubDate"`
Title string `xml:"title"`
Description string `xml:"description"`
Link string `xml:"link"`
GUID string `xml:"guid"`
GeoRssPoint string `xml:"georss:point"`
}
// image defines the fields associated with the image tag
// in the rss document.
image struct {
XMLName xml.Name `xml:"image"`
URL string `xml:"url"`
Title string `xml:"title"`
Link string `xml:"link"`
}
// channel defines the fields associated with the channel tag
// in the rss document.
channel struct {
XMLName xml.Name `xml:"channel"`
Title string `xml:"title"`
Description string `xml:"description"`
Link string `xml:"link"`
PubDate string `xml:"pubDate"`
LastBuildDate string `xml:"lastBuildDate"`
TTL string `xml:"ttl"`
Language string `xml:"language"`
ManagingEditor string `xml:"managingEditor"`
WebMaster string `xml:"webMaster"`
Image image `xml:"image"`
Item []item `xml:"item"`
}
// rssDocument defines the fields associated with the rss document.
rssDocument struct {
XMLName xml.Name `xml:"rss"`
Channel channel `xml:"channel"`
}
)
空結構實現介面
本書推薦在不需要維護任何狀態的時候,用空結構體來實現介面,比如:
cxtype rssMatcher struct{}
func (m rssMatcher) Search(feed *search.Feed, searchTerm string) ([]*search.Result, error) {
...
}
網路請求
Golang可以非常分方便的進行網路請求,例如:
// retrieve performs a HTTP Get request for the rss feed and decodes the results.
func (m rssMatcher) retrieve(feed *search.Feed) (*rssDocument, error) {
if feed.URI == "" {
return nil, errors.New("No rss feed uri provided")
}
// Retrieve the rss feed document from the web.
resp, err := http.Get(feed.URI)
if err != nil {
return nil, err
}
// Close the response once we return from the function.
defer resp.Body.Close()
// Check the status code for a 200 so we know we have received a
// proper response.
if resp.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Response Error %d\n", resp.StatusCode)
}
// Decode the rss feed document into our struct type.
// We don't need to check for errors, the caller can do this.
var document rssDocument
err = xml.NewDecoder(resp.Body).Decode(&document)
return &document, err
}
搜尋匹配可以這樣用正則搞
for _, channelItem := range document.Channel.Item {
// Check the title for the search term.
matched, err := regexp.MatchString(searchTerm, channelItem.Title)
if err != nil {
return nil, err
}
// If we found a match save the result.
if matched {
results = append(results, &search.Result{
Field: "Title",
Content: channelItem.Title,
})
}
至此完成了本書前兩章的對golang語法和語言結構的概覽,下一章將開始對打包和工具鏈的介紹。
參考:Kennedy W , Ketelsen B , Martin E S . Go in action. 2016.