• Go实例解析


    Go语言包的加载顺序如图

    可以通过如下实例详细了解

    代码来源于《Go实战》
    代码地址:https://github.com/goinaction/code

    项目代码结构

    程序架构

    首先分析main文件
    main.main.go

    package main
    
    import (
    	"log"
    	"os"
    
    	_ "github.com/goinaction/code/chapter2/sample/matchers" // 对包做初始化操作,但是不使用包里的标志符。调用包里所有的init函数
    	"github.com/goinaction/code/chapter2/sample/search"
    )
    
    // init is called prior to main.
    func init() {
    	// Change the device for logging to stdout.
    	log.SetOutput(os.Stdout)
    }
    
    // main is the entry point for the program.
    func main() {
    	// Perform the search for the specified term.
    	search.Run("president")
    }
    

    在执行main文件之前,会首先加载matchers、search包里的init函数和包级别的常量变量定义

    加载matchers包的变量常量定义和init函数

    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:"lasteBuildDate"`
    		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 struct {
    		XMLName xml.Name `xml:"rss"`
    		Channel channel  `xml:"channel"`
    	}
    )
    
    type rssMatcher struct{}
    
    func init() {
    	var matcher rssMatcher
    	search.Register("rss", matcher)
    }
    

    加载search包的常量变量定义和init函数

    const dataFile = "data/data.json"
    
    type Feed struct {
    	Name string `json:"site"`
    	URI  string `json:"link"`
    	Type string `json:"type"`
    }
    type Result struct {
    	Field   string
    	Content string
    }
    
    type Matcher interface {
    	Search(feed *Feed, searchTerm string) ([]*Result, error)
    }
    var matchers = make(map[string]Matcher)
    
    type defaultMatcher struct{}
    
    func init() {
    	var matcher defaultMatcher
    	Register("default", matcher)
    }
    

    在回到main函数,首先执行search.Run()的函数,

    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 {
    		log.Printf("%v", *feed)
    		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)
    }
    

    在Run函数中,执行RetrieveFeeds()函数

    func RetrieveFeeds() ([]*Feed, error) {
    	//打开配置文件
    	file, err := os.Open(dataFile)
    	if err != nil {
    		return nil, err
    	}
    
    	defer file.Close()
    
    	var feeds []*Feed
    	//解析json格式到Feed结构体
    	err = json.NewDecoder(file).Decode(&feeds)
    	return feeds, err
    }
    

    执行匹配

    func Match(matcher Matcher, feed *Feed, searchTerm string, results chan<- *Result) {
    	searchResults, err := matcher.Search(feed, searchTerm)
    	if err != nil {
    		log.Println(err)
    		return
    	}
    
    	//将匹配到的结果写入chan
    	for _, result := range searchResults {
    		results <- result
    	}
    }
    

    执行搜索

    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]
    ", 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")
    	}
    
    	//http获取uri返回
    	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
    ", resp.StatusCode)
    	}
    
    	//将结果解析到xml格式的struct
    	var document rssDocument
    	err = xml.NewDecoder(resp.Body).Decode(&document)
    	return &document, err
    }
    

    最后展示结构

    func Display(results chan *Result) {
    	//从chan中读取,会阻塞直到chan close
    	for result := range results {
    		log.Printf("%s:
    %s
    
    ", result.Field, result.Content)
    	}
    }
    
  • 相关阅读:
    Oracle EBS OM 发放订单
    Oracle EBS 创建 RMA
    Oracle EBS OM 保留订单
    Oracle EBS OM 删除订单行
    Oracle EBS OM 登记订单
    [转]Form中控制Tab画布不同标签间切换的方法
    [转]Form Builder:app_field.clear_dependent_fields和APP_FIELD.set_dependent_field的用法
    [整理]:oracle spool 用法
    ORA-20000:ORU-10027:buffer overflow,limit of 2000 bytes.
    [Form Builder]:CREATE_GROUP Built-in
  • 原文地址:https://www.cnblogs.com/promenader/p/9967826.html
Copyright © 2020-2023  润新知