Go語言專案實戰:基於開源資料的成語查詢
業務需求
- 命令列鍵入一行詩句啟動應用:idiom.exe -cmd start -poem 大王派我來巡山
- 將詩句中的每個字丟入【模糊查詢管道】
- 另外再建立【精確查詢管道】和【結束管道】,分別儲存【成語】(大鵬展翅、佔山為王、龜派氣功…)和【結束指令】(fuckoff)
- 時鐘每秒隨機讀入一條管道資料:
如果是【模糊查詢管道】:起協程進行模糊查詢,並彙總資料在記憶體
如果是【精確查詢管道】:起協程進行精確查詢,並彙總資料在記憶體
如果是【結束指令】:停止查詢,將記憶體中的資料持久化為json並退出;
命令列引數獲取工具
import (
"fmt"
"flag"
)
/*
argInfos 要獲取的命令列引數們 例如:[3]interface{}{"cmd","預設命令","要執行的命令"}
retValuesMap 以map的形式返回使用者在命令列輸入的值 [cmd:getmoney amount:666 to:張三]
*/
func GetCmdlineArgs(argInfos ...[3]interface{}) (retValuesMap map[string]interface{}) {
fmt.Printf("type=%T,value=%v\n", argInfos, argInfos)
//初始化返回結果
retValuesMap = map[string]interface{}{}
//預定義【使用者可能輸入的各種型別的指標】
var strValuePtr *string
var intValuePtr *int
//預定義【使用者可能輸入的各種型別的指標】的容器
//使用者可能輸入好幾個string型的引數值,存放在好幾個string型的指標中,將這些同種型別的指標放在同種型別的map中
//例如:flag.Parse()了以後,可以根據【strValuePtrsMap["cmd"]】拿到【存放"cmd"值的指標】
var strValuePtrsMap = map[string]*string{}
var intValuePtrsMap = map[string]*int{}
/* var floatValuePtr *float32
var floatValuePtrsMap []*float32
var boolValuePtr *bool
var boolValuePtrsMap []*bool*/
//遍歷使用者需要接受的所有命令定義
for _, argArray := range argInfos {
/*
先把每個命令的名稱和用法拿出來,
這倆貨都是string型別的,所有都可以通過argArray[i].(string)輕鬆愉快地獲得其字串
一個叫“cmd”,一個叫“你想幹嘛”
"cmd"一會會用作map的key
*/
//[3]interface{}
//["cmd" "未知型別" "你想幹嘛"]
//["gid" 0 "要查詢的商品ID"]
//上面的破玩意型別[string 可能是任意型別 string]
nameValue := argArray[0].(string) //拿到第一個元素的string值,是命令的name
usageValue := argArray[2].(string) //拿到最後一個元素的string值,是命令的usage
//判斷argArray[1]的具體型別
switch argArray[1].(type) {
case string:
//得到【存放cmd的指標】,cmd的值將在flag.Parse()以後才會有
//cmdValuePtr = flag.String("cmd", argArray[1].(string), "你想幹嘛")
strValuePtr = flag.String(nameValue, argArray[1].(string), usageValue)
//將這個破指標以"cmd"為鍵,存在【專門放置string型指標的map,即strValuePtrsMap】中
strValuePtrsMap[nameValue] = strValuePtr
case int:
//得到【存放gid的指標】,gid的值將在flag.Parse()以後才會有
//gidValuePtr = flag.String("gid", argArray[1].(int), "商品ID")
intValuePtr = flag.Int(nameValue, argArray[1].(int), usageValue)
//將這個破指標以"gid"為鍵,存在【專門放置int型指標的map,即intValuePtrsMap】中
intValuePtrsMap[nameValue] = intValuePtr
}
}
/*
程式執行到這裡,所有不同型別的【存值指標】都放在對相應型別的map中了
flag.Parse()了以後,可以從map中以引數名字獲取出【存值指標】,進而獲得【使用者輸入的值】
*/
//使用者輸入完了,解析,【使用者輸入的值】全都放在對應的【存值指標】中
flag.Parse()
/*
遍歷各種可能型別的【存值指標的map】
*/
if len(strValuePtrsMap) > 0 {
//從【cmd存值指標的map】中拿取cmd的值,還以cmd為鍵存入結果map中
for k, vPtr := range strValuePtrsMap {
retValuesMap[k] = *vPtr
}
}
if len(intValuePtrsMap) > 0 {
//從【gid存值指標的map】中拿取gid的值,還以gid為鍵存入結果map中
for k, vPtr := range intValuePtrsMap {
retValuesMap[k] = *vPtr
}
}
//返回結果map
return
}
定義成語資料模型
import "fmt"
//成語
type Idiom struct {
Title string
Spell string
Content string
Sample string
Derivation string
}
//列印成語資料
func PrintIdiom(idiom Idiom) {
if idiom.Title != "" {
fmt.Printf("Title:%s\n", idiom.Title)
fmt.Printf("Spell:%s\n", idiom.Spell)
fmt.Printf("Sample:%s\n", idiom.Sample)
fmt.Printf("Derivation:%s\n", idiom.Derivation)
fmt.Printf("Content:%s\n", idiom.Content)
} else {
fmt.Println("未找到成語!")
}
}
定義成語資料模型和JSON的互化工具
import (
"encoding/json"
"os"
"fmt"
)
//將模糊查詢的json轉化為go資料
func ParseJson2Idioms(jsonStr string) (idiomsMap map[string]Idiom) {
idiomsMap = make(map[string]Idiom)
//將json轉換為go資料
tempMap := make(map[string]interface{})
json.Unmarshal([]byte(jsonStr), &tempMap)
//fmt.Println(tempMap)
dataSlice := tempMap["showapi_res_body"].(map[string]interface{})["data"].([]interface{})
//fmt.Printf("type=%T,value=%v",dataSlice,dataSlice)
for _, v := range dataSlice {
title := v.(map[string]interface{})["title"].(string)
idiom := Idiom{Title: title}
idiomsMap[title] = idiom
}
return
}
//將精確查詢的json轉化為go資料
func ParseJson2Idiom(jsonStr string) Idiom {
idiom := Idiom{}
tempMap := make(map[string]interface{})
json.Unmarshal([]byte(jsonStr), &tempMap)
dataMap := tempMap["showapi_res_body"].(map[string]interface{})["data"].(map[string]interface{})
for k, v := range dataMap {
valueStr := v.(string)
switch k {
case "title":
idiom.Title = valueStr
case "spell":
idiom.Spell = valueStr
case "samples":
idiom.Sample = valueStr
case "derivation":
idiom.Derivation = valueStr
case "content":
idiom.Content = valueStr
}
}
return idiom
}
//將go資料寫出到json檔案
func WriteIdioms2File(idiomsMap map[string]Idiom, path string) {
fmt.Println("WriteIdioms2File")
dstFile, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
defer dstFile.Close()
encoder := json.NewEncoder(dstFile)
err := encoder.Encode(idiomsMap)
if err != nil {
fmt.Println("寫出json檔案失敗,err=", err)
return
}
fmt.Println("寫出json檔案成功!")
}
//讀入json檔案為go資料
func ReadIdiomsFromFile(dstPath string) (idiomsMap map[string]Idiom, err error) {
idiomsMap = make(map[string]Idiom)
//讀入json檔案資料
dstFile, _ := os.OpenFile(dstPath, os.O_RDONLY|os.O_CREATE, 0666)
defer dstFile.Close()
decoder := json.NewDecoder(dstFile)
err = decoder.Decode(&idiomsMap)
if err != nil {
fmt.Println("載入資料失敗!err=", err)
} else {
fmt.Println("成功載入資料!")
fmt.Println("idiomsMap=", idiomsMap)
}
return
}
定義網路工具
import (
"net/http"
"fmt"
"io/ioutil"
)
//獲取模糊查詢的url
func GetAmbiguousUrl(keyword string,page string)(url string){
return "http://route.showapi.com/1196-1?showapi_appid=19988&showapi_sign=968ad4fcc2144e41b5c366838d1b0ec4&keyword="+keyword+"&page="+page+"&rows=20"
}
//獲取精確查詢的url
func GetAccurateUrl(keyword string)(url string){
return "http://route.showapi.com/1196-2?showapi_appid=19988&showapi_sign=968ad4fcc2144e41b5c366838d1b0ec4&keyword="+keyword
}
//從url拿到json資料
func GetJson(url string) (jsonStr string, err error) {
//獲得網路資料
resp, err := http.Get(url)
if err != nil {
fmt.Println("http請求失敗,err=", err)
return
}
//延時關閉網路IO資源
defer resp.Body.Close()
//resp.Body實現了Reader介面,對其進行資料讀入
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("讀取網路資料失敗,err=", err)
return
}
//將網路資料轉化為字串輸出
jsonStr = string(bytes)
//fmt.Println(jsonStr)
return
}
//模糊查詢
func DoAmbiguousQuery(keyword string,page string,chanAccurate chan<- string) {
//先拿到json
url := GetAmbiguousUrl(keyword, page)
jsonStr, _ := GetJson(url)
//將json轉化為成語集合
idiomsMap := ParseJson2Idioms(jsonStr)
//將成語集合寫入記憶體資料
for title,idiom := range idiomsMap{
dbDataMap[title] = idiom
}
//將成語的名字寫入精確管道
for title,_ := range idiomsMap{
chanAccurate<- title
}
/* chanAccurate<- "大鵬展翅"
chanAccurate<- "隔壁老王"
chanAccurate<- "龜派氣功"
chanAccurate<- "我很牛逼"
chanAccurate<- "來咬我呀"
fmt.Println("DoAmbiguousQuery",keyword,page)
*/
}
//精確查詢
func DoAccurateQuery(keyword string) {
//fmt.Println("DoAccurateQuery",keyword)
//拿到json
url := GetAccurateUrl(keyword)
jsonStr, _ := GetJson(url)
//將json轉化為一個Idiom物件
idiom := ParseJson2Idiom(jsonStr)
//將Idiom物件存入總集合,覆蓋原來的粗糙物件
dbDataMap[idiom.Title] = idiom
}
主調模組
import (
"fmt"
"time"
"os"
)
const DB_PATH = "d:/temp/idioms-v2.0.json"
var (
//資料管道
chanAmbiguous = make(chan string, 20)
chanAccurate = make(chan string, 20)
chanQuit = make(chan string, 0)
//全域性記憶體資料
dbDataMap = make(map[string]Idiom)
)
func main0() {
//讀入命令列引數
//idiom.exe -cmd start -poem 大王派我來巡山
cmdInfo := [3]interface{}{"cmd","未知命令","你打算幹什麼"}
poemInfo := [3]interface{}{"poem","絞盡果汁想不出","用於啟動的一行詩句"}
retValuesMap := GetCmdlineArgs(cmdInfo,poemInfo)
cmd := retValuesMap["cmd"].(string)
poem := retValuesMap["poem"].(string)
fmt.Println(cmd, poem)
//將讀入的詩句打碎丟入模糊管道
for _, v := range poem {
keyword := fmt.Sprintf("%c", v)
chanAmbiguous <- keyword
}
//三選一讀入管道資料,週期性執行
go func() {
ticker := time.NewTicker(time.Second)
for {
<-ticker.C
select {
case keyword := <-chanAmbiguous:
go DoAmbiguousQuery(keyword,"1",chanAccurate)
case keyword := <-chanAccurate:
go DoAccurateQuery(keyword)
case <-chanQuit:
WriteIdioms2File(dbDataMap, DB_PATH)
os.Exit(0)
}
}
}()
//定時20秒結束主程式
timer := time.NewTimer(20 * time.Second)
<-timer.C
chanQuit <- "OVER"
}
學院Go語言視訊主頁
https://edu.csdn.net/lecturer/1928
[清華團隊帶你實戰區塊鏈開發]
(https://ke.qq.com/course/344443?tuin=3d17195d)
掃碼獲取海量視訊及原始碼 QQ群:721929980
相關文章
- go語言實戰教程:實戰專案資源匯入和專案框架搭建Go框架
- 基於go語言gin框架的web專案骨架Go框架Web
- go語言實戰教程:Redis實戰專案應用GoRedis
- Go語言專案實戰:多人聊天室Go
- Go語言專案實戰:併發爬蟲Go爬蟲
- MySQL — 資料查詢語言MySql
- 有哪些值得學習的 Go 語言開源專案?Go
- go語言實戰教程之管理員查詢功能、退出功能Go
- go語言教程哪裡有?go 語言優秀開源專案彙總Go
- 資料庫查詢語言(DQL)資料庫
- [分享] Go 語言開源專案 Drone 搭配 GitLab 安裝GoGitlab
- Go 語言實戰 GraphQLGo
- GO 語言 Web 開發實戰一GoWeb
- 關係型資料庫查詢語言 SQL 和圖資料庫查詢語言 nGQL 對比資料庫SQL
- MySql中的資料查詢語言(DQL)三:連線查詢MySql
- 有Go語言實戰培訓班嗎?go語言開發環境搭建Go開發環境
- SQL語言基礎(子查詢)SQL
- Go語言SQL操作實戰GoSQL
- go語言實戰教程:專案檔案配置和專案初始化執行Go
- Go 語言開源 Excelize 基礎庫影片教程GoExcelize
- 優秀的 Spring Boot 語言開源專案Spring Boot
- 2020 年 HackerEarth 調查:Go 語言成為最受歡迎的語言(內含 Go 語言圖譜下載)Go
- 基於 go 語言開發部署的部落格 免費開源供參考Go
- SQL語言基礎(高階查詢)SQL
- 基於Dart語言的開源後端框架:UpperDart後端框架
- SQL語言(結構化查詢語言)SQL
- 滴滴基於Go語言的DevOps重塑之路Godev
- 帶讀 |《Go in Action》(中文:Go語言實戰) 語法和語言結構概覽(三)Go
- 帶讀 |《Go in Action》(中文:Go語言實戰)語法和語言結構概覽 (二)Go
- Go 語言實戰: 編寫可維護 Go 語言程式碼建議Go
- 非常適合GO語言新手學習的《Go語言從入門到實戰——簡明高效的Go語言實戰指南》課程——推薦分享Go
- 從零開始——GO語言基礎語法Go
- Go 語言專案程式碼品質Go
- Drone 搭配 Kubernetes 部署 Go 語言專案Go
- Go 語言—資料結構和演算法專案推薦Go資料結構演算法
- Go語言基於go module方式管理包(package)GoPackage
- SQL語言基礎(資料控制語言)SQL
- go語言資料型別-基礎型別Go資料型別