About the Go language

advantage

Intelligent compiler, and simplified algorithms for resolving dependencies, ultimately providing faster compilation speed support for concurrency: Goroutine, channel type system: composition instead of inheritance, interface to behavior modeling memory managementCopy the code

Go Playground

http://paly.golang.org
Copy the code

Go program development

The project structure

Json -- contains a set of data sources -- matchers rss.go -- searches the matchers for RSS feeds -- search default.go -- searches the default matchers for data feed.go -- Go -- interface used to support different matchers search.go -- main control logic to perform the search main.go -- entry to the programCopy the code

main.go

  package main
  import ( 
      "log" 
      "os" 
      _ "github.com/goinaction/code/chapter2/sample/matchers" 
      "github.com/goinaction/code/chapter2/sample/search" 
  ) 
  
  func init() { 
     log.SetOutput(os.Stdout) 
  } 
  func main() { 
      search.Run("president")
  }
Copy the code

search.go

package search import ( "log" "sync" ) var matchers = make(map[string]Matcher) func Run(searchTerm string) { feeds, err := RetrieveFeeds() if err ! = nil { log.Fatal(err) } results := make(chan *Result) var waitGroup sync.WaitGroup waitGroup.Add(len(feeds)) for _, feed := range feeds { matcher, exists := matchers[feed.Type] if ! exists { matcher = matchers["default"] } go func(matcher Matcher, feed *Feed) { Match(matcher, feed, searchTerm, results) waitGroup.Done() }(matcher, feed) } go func() { waitGroup.Wait() close(results) }() Display(results) } 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 }Copy the code

feed.go

package search import ( "encoding/json" "os" ) const dataFile = "data/data.json" type Feed struct { Name string `json:"site"` URI string `json:"link"` Type string `json:"type"` } func RetrieveFeeds() ([]*Feed, error) { file, err := os.Open(dataFile) if err ! = nil { return nil, err } defer file.Close() var feeds []*Feed err = json.NewDecoder(file).Decode(&feeds) return feeds, err }Copy the code

data.json

  [ { "site" : "npr", 
      "link" : "http://www.npr.org/rss/rss.php?id=1001",
      "type" : "rss" },
    { "site" : "cnn", 
       "link" : "http://rss.cnn.com/rss/cnn_world.rss", 
       "type" : "rss" },
    {"site" : "foxnews", 
       "link" : "http://feeds.foxnews.com/foxnews/world?format=xml",
       "type" : "rss" },
     { "site" : "nbcnews", 
     "link" : "http://feeds.nbcnews.com/feeds/topstories",
     "type" : "rss" } 
   ]
Copy the code

match.go

package search import ( "log" ) type Result struct { Field string Content string } type Matcher interface { Search(feed *Feed, searchTerm string) ([]*Result, error) } func Match(matcher Matcher, feed *Feed, searchTerm string, results chan<- *Result) { searchResults, err := matcher.Search(feed, searchTerm) if err ! = nil { log.Println(err) return } for _, result := range searchResults { results <- result } } func Display(results chan *Result) { for result := range results {  fmt.Printf("%s:\n%s\n\n", result.Field, result.Content) } }Copy the code

default.go

package search 
type defaultMatcher struct{} 
func init() { 
    var matcher defaultMatcher
    Register("default", matcher)  
} 
func (m defaultMatcher) Search(feed *Feed, searchTerm string) ([]*Result, error) { 
    return nil, nil 
 }
Copy the code

rss.go

package matchers import ( "encoding/xml" "errors" "fmt" "log" "net/http" "regexp" "github.com/goinaction/code/chapter2/sample/search" ) type ( 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 struct { XMLName xml.Name `xml:"image"` URL string `xml:"url"` Title string `xml:"title"` Link string `xml:"link"` } 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"` 46 Language string `xml:"language"` ManagingEditor string `xml:"managingEditor"` WebMaster string `xml:"webMaster"` Image image `xml:"image"` Item []item `xml:"item"` } rssDocument struct { XMLName xml.Name `xml:"rss"` Channel channel `xml:"channel"` } ) type rssMatcher struct{} func init() { var matcher rssMatcher search.Register("rss", matcher) } func (m rssMatcher) Search(feed *search.Feed, searchTerm string) ([]*search.Result,error) { var results []*search.Result log.Printf("Search Feed Type[%s] Site[%s] For  Uri[%s]\n", feed.Type, feed.Name, feed.URI) document, err := m.retrieve(feed) if err ! = nil { return nil, err } for _, channelItem := range document.Channel.Item { matched, err := regexp.MatchString(searchTerm, channelItem.Title) if err ! = nil { return nil, err } if matched { results = append(results, &search.Result{ Field: "Title", Content: channelItem.Title, }) } matched, err = regexp.MatchString(searchTerm, channelItem.Description) if err ! = nil { return nil, err } if matched { results = append(results, &search.Result{ Field: "Description", Content: channelItem.Description, }) } } return results, nil } func (m rssMatcher) retrieve(feed *search.Feed) (*rssDocument, error) { if feed.URI == "" { return nil, errors.New("No rss feed URI provided") } resp, err := http.Get(feed.URI) if err ! = nil { return nil, err } defer resp.Body.Close() if resp.StatusCode ! = 200 { return nil, fmt.Errorf("HTTP Response Error %d\n", resp.StatusCode) } var document rssDocument err = xml.NewDecoder(resp.Body).Decode(&document) return &document, err }Copy the code

RSS sample

<rss xmlns:npr="http://www.npr.org/rss/" xmlns:nprml="http://api" <channel> <title>News</title> <link>... </link> <description>... </description> <language>en</language> <copyright>Copyright 2014 NPR - For Personal Use <image>... </image> <item> <title> Putin Says He'll Respect Ukraine Vote But U.S. </title> <description> The White House and State Department have called on the </description>Copy the code

The value of the interface type calls the method

Methods declared using a pointer as a receiver can only be called when the value of the interface type is a pointer. Methods declared using a value as a receiver can only be called when the value of the interface type is a value or a pointer.Copy the code

All the process