帶讀 |《Go in Action》(中文:Go語言實戰) 語法和語言結構概覽(三)

LiberHome發表於2022-12-22

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.

相關文章