go語言功能代碼

1、數據類型轉換

package main

import (
    "fmt"
    "strconv"
)

func main() {
    //int到string
    str := strconv.Itoa(int(1))
    fmt.Println("int轉string", str)
    //int64到string
    str2 := strconv.FormatInt(int64(1), 10)
    fmt.Println("int64轉string", str2)
    //float64轉string formatFloat只能接收float64若是想用float32須要強轉float64(float32(0.8))
    //下面是參數說明
    // 'b' (-ddddp±ddd,二進制指數)
    // 'e' (-d.dddde±dd,十進制指數)
    // 'E' (-d.ddddE±dd,十進制指數)
    // 'f' (-ddd.dddd,沒有指數)
    // 'g' ('e':大指數,'f':其它狀況)
    // 'G' ('E':大指數,'f':其它狀況)
    str3 := strconv.FormatFloat(float64(0.8), 'f', -1, 32)
    fmt.Println("float32轉string", str3)
    //string到int  有異常的都不進行處理這個後面說
    i, _ := strconv.Atoi("10")
    fmt.Println("strin轉int", i)
    //string 到int64
    i64, _ := strconv.ParseInt("123", 10, 64)
    fmt.Println("strin轉int64", i64)
    //string轉float64 若是想轉float32 用float32(fl32)強轉一下就能夠
    fl32, _ := strconv.ParseFloat("3.1415926535", 32/64)
    fmt.Println("strin轉float64", fl32)
}

2、時間類型轉換

package main

import (
    "fmt"
    "time"
)

func main() {
    //獲取當前時間
    now := time.Now()
    //時間轉化爲string
    //在go語言裏將日期格式化並非yyyy-MM-dd HH:ss:mm 而是用"2006-01-02 15:04:05具體含義以下
    //月份 1,01,Jan,January
    //日  2,02,_2
    //時  3,03,15,PM,pm,AM,am
    //分  4,04
    //秒  5,05
    //年  06,2006
    //周幾 Mon,Monday
    //時區時差表示 -07,-0700,Z0700,Z07:00,-07:00,MST
    //時區字母縮寫 MST
    timeStr := now.Format("2006-01-02 15:04:05")
    fmt.Println("日期類型當前時間: ", now)
    fmt.Println("字符串類型當前時間: ", timeStr)
    //string轉化爲時間
    date, _ := time.Parse("2006-01-02 15:04:05", "2017-08-29 08:37:18")
    fmt.Println("string轉日期:", date)
    //判斷兩個時間前後
    trueOrFalse := date.After(now)
    if trueOrFalse == true {
        fmt.Println("2017-08-29 08:37:18在", timeStr, "以後")
    } else {
        fmt.Println("2017-08-29 08:37:18在", timeStr, "以前")
    }
    // ParseDuration parses a duration string.
    // A duration string is a possibly signed sequence of decimal numbers,
    // each with optional fraction and a unit suffix,
    // such as "300ms", "-1.5h" or "2h45m".
    //  Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
    // -表明時間以前,不加表明時間以後 m表示分鐘,如20分鐘前
    m, _ := time.ParseDuration("-20m")
    m1 := now.Add(m)
    fmt.Println("10分鐘以前:", m1)
    // h表明小時 一天以前爲-24h
    h, _ := time.ParseDuration("-8h")
    h1 := now.Add(h)
    fmt.Println("8小時以前", h1)
    //    // 一天前
    d, _ := time.ParseDuration("-24h")
    d1 := now.Add(d)
    fmt.Println(d1)
    //計算兩個時間差幾秒
    sec := now.Sub(m1)
    fmt.Println(sec.Seconds(), "")
    //計算兩個時間差幾分鐘
    minutes := now.Sub(m1)
    fmt.Println(minutes.Minutes(), "分鐘")
    //計算兩個時間差幾小時
    hours := now.Sub(h1)
    fmt.Println(hours.Hours(), "小時")
    //計算兩個時間差幾天
    day := now.Sub(d1)
    fmt.Println(day.Hours()/24, "")
    //注意:splite3數據庫中字段若是是datetime類型獲取數據時格式轉換會有問題
    //如2017-08-29 08:37:18這樣的時間從數據庫獲取後會變成2017-08-29T08:37:18Z
    //進行格式轉化以後不能比較,因此須要將T和Z替換爲" "
    //不知道其餘數據庫有沒有這樣的問題
}

3、配置文件讀取  

package main

import (
    "flag"
    "sync"

    "github.com/larspensjo/config"
)

var Conf_Main_Topic = "DEFAULT"

var (
    //config.ini爲配置文件格式爲 key=value
    configFile = flag.String("configfile", "config.ini", "General configuration file")
)
var commonConf = make(map[string]string)
var lock sync.RWMutex

func LoadCommonConfiguration() {
    lock.Lock()
    defer lock.Unlock()
    cfg, err := config.ReadDefault(*configFile)
    if err != nil {
        //....
    }
    commonConf = make(map[string]string)
    if cfg.HasSection(Conf_Main_Topic) {
        section, err := cfg.SectionOptions(Conf_Main_Topic)
        if err != nil {
            //....
        }
        for _, v := range section {
            options, err := cfg.String(Conf_Main_Topic, v)
            if err != nil {
                //....
            }
            commonConf[v] = options
        }
    }
}

//經過GetConf方法將key傳入獲取value值
func GetConf(key string) string {
    lock.RLock()
    defer lock.RUnlock()
    return commonConf[key]
}

4、Json與Map轉換

package main

import (
    "encoding/json"
    "strings"
    //    "github.com/bitly/go-simplejson" // for json get
)

//把兩層嵌套結構的json格式的數據組轉成map(map中不含interface結構)
func NoInterfaceJsonToMap(input string) (map[string]map[string]interface{}, error) {
    result := make(map[string]map[string]interface{})
    err := json.Unmarshal([]byte(input), &result)
    if err != nil {
        return nil, err
    }
    return result, nil
}
func MapToJson(input map[string]interface{}) (string, error) {
    result, err := json.Marshal(input)
    if err != nil {
        //        panic(err)
        return "", err
    }
    return string(result), nil
}

func MapMapToJson(input map[string]map[string]interface{}) (string, error) {
    result, err := json.Marshal(input)
    if err != nil {
        return "", err
    }
    return string(result), nil
}

func JsonToMap(input string) (map[string]interface{}, error) {
    result := make(map[string]interface{})
    err := json.Unmarshal([]byte(input), &result)
    if err != nil {
        return nil, err
    }
    return result, nil
}

func BoltKeyValueToJson(key, value string, delimeter string) (string, error) {
    keys := []string{key}
    values := []string{value}
    return BoltKeyValuesToJson(keys, values, delimeter)
}
func BoltKeyValuesToJson(keys, values []string, delimeter string) (string, error) {
    mapResult := make(map[string]interface{})
    for i := range keys {
        key := strings.Split(keys[i], delimeter)
        value := values[i]
        cur := mapResult
        for j := range key {
            if j == len(key)-1 {
            } else if j == len(key)-2 {
                if cur[key[j]] == nil {
                    cur[key[j]] = map[string]string{key[len(key)-1]: value}
                } else {
                    cur[key[j]].(map[string]string)[key[len(key)-1]] = value
                }
            } else {
                if cur[key[j]] == nil {
                    cur[key[j]] = make(map[string]interface{})
                }
                cur = cur[key[j]].(map[string]interface{})
            }
        }
    }
    return MapToJson(mapResult)
}

5、經過JSON數據發送Email

package main

import (
    "bytes"
    "errors"
    "fmt"
    "io/ioutil"
    "net/http"
    "strconv"
    "strings"
)

func HttpPostByJSON(accessUrl string, json string, redo int) error {
    fmt.Println(json)
    fmt.Println("post write json bytes:" + strconv.Itoa(len(json)))
    for j := 1; j <= redo; j++ {
        req_new := bytes.NewBuffer([]byte(json))
        request, err := http.NewRequest("POST", accessUrl, req_new)
        if err == nil {
            request.Header.Set("Content-Type", "application/json;charset=UTF-8")
            client := http.Client{}
            response, err1 := client.Do(request)
            if err1 == nil {
                body, err := ioutil.ReadAll(response.Body)
                if err != nil {
                    fmt.Println("Unknown error in sending Email")
                } else {
                    resp := string(body)
                    if strings.Contains(resp, "\"code\":\"200\"") {
                        return nil
                    } else {
                        fmt.Println(string(body))
                    }
                }
            } else {
                fmt.Println(err1)
            }
        } else {
            fmt.Println(err)
        }
    }
    return errors.New("Fail to send email notification")
}

6、文件讀寫刪除操做

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)
func FileExist(filename string) bool {
    _, err := os.Stat(filename)
    if os.IsNotExist(err) {
        return false
    }
    fmt.Println(err)
    return err == nil || os.IsExist(err)
}

func ReadFileByLine(filename string) []string {
    if !FileExist(filename) {
        return []string{}
    }
    f, err := os.Open(filename)
    fmt.Println(err)
    defer f.Close()
    rd := bufio.NewReader(f)
    result := []string{}
    for {
        line, err := rd.ReadString('\n')
        if err == nil || io.EOF == err {
            line = strings.TrimSpace(line)
            if len(line) > 0 {
                result = append(result, line)
            }
        }
        if io.EOF == err {
            break
        }
        fmt.Println(err)
    }
    return result
}

func WriteFileByLine(filename string, data []string) {
    f, err := os.Create(filename)
    fmt.Println(err)
    defer f.Close()
    wt := bufio.NewWriter(f)
    for i := range data {
        _, err := wt.WriteString(data[i])
        if io.EOF == err {
            break
        }
        fmt.Println(err)
    }
    wt.Flush()
}

func DeleteFile(filename string) {
    if FileExist(filename) {
        err := os.Remove(filename)
        fmt.Println(err)
    }
}

7、go執行linux和windows命令操做

package main

import (
    "errors"
    "fmt"
    "os/exec"
    "runtime"
    "strings"
)

func runInLinux(cmd string) string {
    fmt.Println("Running Linux Cmd:" + cmd)
    result, err := exec.Command("/bin/sh", "-c", cmd).Output()
    if err != nil {
        fmt.Println(err.Error())
    }
    return strings.TrimSpace(string(result))
}

func runInWindows(cmd string) string {
    fmt.Println("Running Win Cmd:" + cmd)
    result, err := exec.Command("cmd", "/c", cmd).Output()
    if err != nil {
        fmt.Println(err.Error())
    }
    return strings.TrimSpace(string(result))
}

func RunCommand(cmd string) string {
    if runtime.GOOS == "windows" {
        return runInWindows(cmd)
    } else {
        return runInLinux(cmd)
    }
}

func RunLinuxCommand(cmd string) string {
    if runtime.GOOS == "windows" {
        return ""
    } else {
        return runInLinux(cmd)
    }
}

func runInLinuxWithErr(cmd string) (string, error) {
    fmt.Println("Running Linux Cmd:" + cmd)
    result, err := exec.Command("/bin/sh", "-c", cmd).Output()
    if err != nil {
        fmt.Println(err.Error())
    }
    return strings.TrimSpace(string(result)), err
}

func runInWindowsWithErr(cmd string) (string, error) {
    fmt.Println("Running Win Cmd:" + cmd)
    result, err := exec.Command("cmd", "/c", cmd).Output()
    if err != nil {
        fmt.Println(err.Error())
    }
    return strings.TrimSpace(string(result)), err
}

func RunCommandWithErr(cmd string) (string, error) {
    if runtime.GOOS == "windows" {
        return runInWindowsWithErr(cmd)
    } else {
        return runInLinuxWithErr(cmd)
    }
}

func RunLinuxCommandWithErr(cmd string) (string, error) {
    if runtime.GOOS == "windows" {
        return "", errors.New("could not run in windows OS")

    } else {
        return runInLinuxWithErr(cmd)
    }
}

8、異常處理

Golang 有2個內置的函數 panic() 和 recover(),用以報告和捕獲運行時發生的程序錯誤,與 error 不一樣,panic-recover 通常用在函數內部。必定要注意不要濫用 panic-recover,可能會致使性能問題,我通常只在未知輸入和不可靠請求時使用。html

golang 的錯誤處理流程:當一個函數在執行過程當中出現了異常或遇到 panic(),正常語句就會當即終止,而後執行 defer 語句,再報告異常信息,最後退出 goroutine。若是在 defer 中使用了 recover() 函數,則會捕獲錯誤信息,使該錯誤信息終止報告。linux

package main
import (
 "log"
 "strconv"
)
//捕獲因未知輸入致使的程序異常
func catch(nums ...int) int {
 defer func() {
  if r := recover(); r != nil {
   log.Println("[E]", r)
  }
 }()
 return nums[1] * nums[2] * nums[3] //index out of range
}
//主動拋出 panic,不推薦使用,可能會致使性能問題
func toFloat64(num string) (float64, error) {
 defer func() {
  if r := recover(); r != nil {
   log.Println("[W]", r)
  }
 }()
 if num == "" {
  panic("param is null") //主動拋出 panic
 }
 return strconv.ParseFloat(num, 10)
}
func main() {
 catch(2, 8)
 toFloat64("")
}

go語言有異常的返回會有兩個返回參數包括值跟error,判斷error是否爲nil進行相應處理就能夠最好不要panicgit

10、數據庫操做

package main

import (
    "database/sql"
    "errors"
    "fmt"
    "sync"

    _ "github.com/mattn/go-sqlite3"
)

var db *sql.DB
var dbLock sync.Mutex

func main() {
    //查詢調用RunQuery或者RunQueryWithErr
    //?爲佔位符對應相應參數
    rows := RunQuery("select age from table where id = ? and name = ?", 1, "abc")
    //也可使用struct構建對象,獲取數據庫字段時須要用sql.Null...不然取空值會報錯
    var age sql.NullInt64
    var ages []Int64

    //若是有多條返回值用for循環遍歷,若是肯定只有一條能夠用if,這裏只有一條因此用if,也能夠將if改成for
    if rows.Next() {
        err := rows.Scan(&age)
        if err != nil {
            //........
        }
        //sql.NullInt64中有兩個方法Int64和Valid,Valid用來判斷值是否爲空返回值爲true、false
        //Int64爲實際值,sql.NullInt64對象若是爲空Int64值爲0
        if age.Valid {
            //對獲取到的age作操做
            fmt.Println(age.Int64)
        }
    }
    //sqlite3中使用完rows以後必定要調用close釋放鎖,不然繼續調用數據庫語句會報數據庫被鎖的異常
    rows.Close()
    //sqlite3中查詢和增刪改不能同時進行,也會報數據庫被鎖的異常
    //須要在查詢以後統一進行增刪改操做,增刪改調用ExecSQL或ExecSqlWithErr
}

func OpenDB() {
    var err error
    //foo.db爲數據庫名字
    db, err = sql.Open("sqlite3", "./foo.db?_txlock=exclusive")
    fmt.Println(err)
    _, err = db.Exec("PRAGMA synchronous = OFF;")
    fmt.Println(err)
}

func CloseDB() {
    if db != nil {
        err := db.Close()
        db = nil
        fmt.Println(err)
    }
}

func ExecSQL(query string, args ...interface{}) sql.Result {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        OpenDB()
    }
    if query == "" {
        panic("Empty sql input")
    }
    fmt.Println("Running Exec:")
    fmt.Println(query)
    fmt.Println(args...)
    res, err := db.Exec(query, args...)
    fmt.Println(err)
    return res
}

func RunQuery(query string, args ...interface{}) *sql.Rows {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        OpenDB()
    }
    if query == "" {
        panic("Empty sql input")
    }
    fmt.Println("Running Query:")
    fmt.Println(query)
    fmt.Println(args...)
    res, err := db.Query(query, args...)
    fmt.Println(err)
    return res
}
//多條語句的事物操做
func ExecTransaction(querys []string, args [][]string) {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        OpenDB()
    }
    tx, err := db.Begin()
    fmt.Println(err)
    fmt.Println("Running Trans:")
    for index, query := range querys {
        if query == "" {
            panic("Empty sql input")
        }
        oldArgs := args[index]
        newArgs := make([]interface{}, len(oldArgs))
        for i, v := range oldArgs {
            newArgs[i] = interface{}(v)
        }
        fmt.Println(query)
        fmt.Println(newArgs...)
        _, err := tx.Exec(query, newArgs...)
        fmt.Println(err)
    }
    err = tx.Commit()
    fmt.Println(err)
}

func OpenDBWithErr() error {
    var err error
    db, err = sql.Open("sqlite3", "./pjm.db?_txlock=exclusive")
    if err != nil {
        return err
    }
    _, err = db.Exec("PRAGMA synchronous = OFF;")
    return err
}

func CloseDBWithErr() error {
    if db != nil {
        err := db.Close()
        db = nil
        return err
    }
    return nil
}

func ExecSQLWithErr(query string, args ...interface{}) (sql.Result, error) {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        err := OpenDBWithErr()
        if err != nil {
            return nil, err
        }
    }
    if query == "" {
        return nil, errors.New("Empty sql input")
    }
    fmt.Println("Running Exec With Err:")
    fmt.Println(query)
    fmt.Println(args...)
    return db.Exec(query, args...)
}

func RunQueryWithErr(query string, args ...interface{}) (*sql.Rows, error) {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        err := OpenDBWithErr()
        if err != nil {
            return nil, err
        }
    }
    if query == "" {
        return nil, errors.New("Empty sql input")
    }
    fmt.Println("Running Query With Err:")
    fmt.Println(query)
    fmt.Println(args...)
    return db.Query(query, args...)
}

func ExecTransactionWithErr(querys []string, args [][]string) error {
    dbLock.Lock()
    defer dbLock.Unlock()
    if db == nil {
        err := OpenDBWithErr()
        if err != nil {
            return err
        }
    }
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    fmt.Println("Running Trans With Err:")
    for index, query := range querys {
        if query == "" {
            return errors.New("Empty sql input")
        }
        oldArgs := args[index]
        newArgs := make([]interface{}, len(oldArgs))
        for i, v := range oldArgs {
            newArgs[i] = interface{}(v)
        }
        fmt.Println(query)
        fmt.Println(newArgs...)
        _, err := tx.Exec(query, newArgs...)
        if err != nil {
            return err
        }
    }
    return tx.Commit()
}

11、go語言web編程

package main

import (
    "fmt"
    "html/template"
    "log"
    "net/http"
    "strings"
)

func sayhelloName(w http.ResponseWriter, r *http.Request) {
    r.ParseForm() //解析url傳遞的參數,對於POST則解析響應包的主體(request body)
    //注意:若是沒有調用ParseForm方法,下面沒法獲取表單的數據
    fmt.Println(r.Form) //這些信息是輸出到服務器端的打印信息
    fmt.Println("path", r.URL.Path)
    fmt.Println("scheme", r.URL.Scheme)
    fmt.Println(r.Form["url_long"])
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, "Hello astaxie!") //這個寫入到w的是輸出到客戶端的
}

func login(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) //獲取請求的方法
    //Handler裏面是不會自動解析form的,必須顯式的調用r.ParseForm()後,才能對這個表單數據進行操做
    r.ParseForm()
    if r.Method == "GET" {
        t, _ := template.ParseFiles("login.html")
        t.Execute(w, nil)
    } else {
        //請求的是登錄數據,那麼執行登錄的邏輯判斷
        fmt.Println("username:", r.Form["username"])
        fmt.Println("password:", r.Form["password"])
        //獲取username的值須要[0]
        if r.Form["username"][0] == "abc" {
            //若是username爲abc跳轉到user.html頁面打印abc=====
            t, _ := template.ParseFiles("./user.html")
            //t.Execute第二個參數能夠傳各類類型的數據到頁面
            t.Execute(w, "abc=====")
        } else if r.Form["username"][0] == "efg" {
            t, _ := template.ParseFiles("./userMap.html")
            result := map[string]string{}
            result["key"] = "value"
            //返回map
            t.Execute(w, result)
        } else {
            t, _ := template.ParseFiles("./userMaps.html")
            result := []map[string]string{}
            m1 := map[string]string{}
            m2 := map[string]string{}
            m3 := map[string]string{}
            m1["a1"] = "111"
            m1["a2"] = "222"
            m1["a3"] = "333"
            m1["a4"] = "444"
            m2["a1"] = "555"
            m2["a2"] = "666"
            m2["a3"] = "777"
            m2["a4"] = "888"
            m3["a1"] = "999"
            m3["a2"] = "123"
            m3["a3"] = "456"
            m3["a4"] = "789"
            result = append(result, m1, m2, m3)
            //返回多個map
            t.Execute(w, result)
        }
    }
}

func main() {
    http.HandleFunc("/", sayhelloName)       //設置訪問的路由
    http.HandleFunc("/login", login)         //設置訪問的路由
    err := http.ListenAndServe(":9090", nil) //設置監聽的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

login.html頁面github

<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
    用戶名:<input type="text" name="username">
    密碼:<input type="password" name="password">
    <input type="submit" value="登錄">
</form>
</body>
</html>
user.html頁面
go語言中頁面獲取值必須加{{  }}
<html>
<head>
<title></title>
</head>
<body>
從後臺獲取的值爲: {{.}}
</body>
</html>

userMap.html頁面golang

<html>
<head>
<title></title>
</head>
<body>
從後臺獲取的值爲: {{.key}}
</body>
</html>

userMaps.html頁面web

<html>
<head>
<title></title>
</head>
<body>
{{range $index,$re :=.}}
{{$re.a1}}</br>
{{$re.a2}}</br>
{{$re.a3}}</br>
{{$re.a4}}</br>
{{end}}
</body>
</html>

12、分頁實現

//分頁方法,根據傳遞過來的頁數,每頁數,總數,返回分頁的內容 7個頁數 前 1,2,3,4,5 後 的格式返回,小於5頁返回具體頁數
func Paginator(page, prepage int, nums int64) map[string]interface{} {

    var firstpage int //前一頁地址
    var lastpage int  //後一頁地址
    //根據nums總數,和prepage每頁數量 生成分頁總數
    totalpages := int(math.Ceil(float64(nums) / float64(prepage))) //page總數
    if page > totalpages {
        page = totalpages
    }
    if page <= 0 {
        page = 1
    }
    var pages []int
    switch {
    case page >= totalpages-5 && totalpages > 5: //最後5頁
        start := totalpages - 5 + 1
        firstpage = page - 1
        lastpage = int(math.Min(float64(totalpages), float64(page+1)))
        pages = make([]int, 5)
        for i, _ := range pages {
            pages[i] = start + i
        }
    case page >= 3 && totalpages > 5:
        start := page - 3 + 1
        pages = make([]int, 5)
        firstpage = page - 3
        for i, _ := range pages {
            pages[i] = start + i
        }
        firstpage = page - 1
        lastpage = page + 1
    default:
        pages = make([]int, int(math.Min(5, float64(totalpages))))
        for i, _ := range pages {
            pages[i] = i + 1
        }
        firstpage = int(math.Max(float64(1), float64(page-1)))
        lastpage = page + 1
        //fmt.Println(pages)
    }
    paginatorMap := make(map[string]interface{})
    paginatorMap["pages"] = pages
    paginatorMap["totalpages"] = totalpages
    paginatorMap["firstpage"] = firstpage
    paginatorMap["lastpage"] = lastpage
    paginatorMap["currpage"] = page
    return paginatorMap
}

html頁面sql

 <div class="am-cf">
  共{{.totals}}條記錄 共記{{.paginator.totalpages}} 頁 當前頁  {{.paginator.currpage}}
  <div class="am-fr">
    <ul class="am-pagination">
    <li class=""><a href="/clubadmin/topics/{{.paginator.firstpage}}">«</a></li> 
    {{range $index,$page := .paginator.pages}}
      <li  {{if eq $.paginator.currpage $page }}class="am-active"{{end}}><a href="/clubadmin/topics/{{$page}}">{{$page}}</a></li>  
    {{end}}
      <li><a href="/clubadmin/topics/{{.paginator.lastpage}}">»</a></li>
    </ul>
  </div>
</div>

交替打印數字和字母

問題描述

使用兩個 goroutine 交替打印序列,一個 goroutinue 打印數字, 另一個goroutine打印字母, 最終效果以下 12AB34CD56EF78GH910IJ 。數據庫

解題思路

問題很簡單,使用 channel 來控制打印的進度。使用兩個 channel ,來分別控制數字和字母的打印序列, 數字打印完成後經過 channel 通知字母打印, 字母打印完成後通知數字打印,而後周而復始的工做。編程

實際編碼

runtime.GOMAXPROCS(runtime.NumCPU())
chan_n := make(chan bool)
chan_c := make(chan bool, 1)
done := make(chan struct{})

go func() {
  for i := 1; i < 11; i += 2 {
    <-chan_c
    fmt.Print(i)
    fmt.Print(i + 1)
    chan_n <- true
  }
}()

go func() {
  char_seq := []string{"A","B","C","D","E","F","G","H","I","J","K"}
  for i := 0; i < 10; i += 2 {
    <-chan_n
    fmt.Print(char_seq[i])
    fmt.Print(char_seq[i+1])
    chan_c <- true
  }
  done <- struct{}{}
}()

chan_c <- true
<-done

代碼執行結果:json

12AB34CD56EF78GH910IJ

隨機抽獎

問題描述

用戶隨機抽獎,數據結構以下所示:

// map中,key表明名稱,value表明成交單數
var users map[string]int64 = map[string]int64{
  "a": 10,
  "b": 6,
  "c": 3,
  "d": 12,
  "f": 1,
}

解決思路

從map中選取隨機用戶,拿到這個編碼問題,有點懵逼,但仔細一想,只需把關注用戶的區間,轉變一下數據結構即解題。 把map轉成array,思考起來就簡單多了,原有問題變成了從0至n-1中選取一個數字,數字對應的用戶即中獎用戶。

實際編碼

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func GetAwardUserName(users map[string]int64) (name string) {
  sizeOfUsers := len(users)
  award_index := rand.Intn(sizeOfUsers)

  var index int
  for u_name, _ := range users {
    if index == award_index {
      name = u_name
      return
    }
    index += 1
  }
  return
}

func main() {
  var users map[string]int64 = map[string]int64{
    "a": 10,
    "b": 6,
    "c": 3,
    "d": 12,
    "e": 20,
    "f": 1,
  }

  rand.Seed(time.Now().Unix())
  award_stat := make(map[string]int64)
  for i := 0; i < 1000; i += 1 {
    name := GetAwardUserName(users)
    if count, ok := award_stat[name]; ok {
      award_stat[name] = count + 1
    } else {
      award_stat[name] = 1
    }
  }

  for name, count := range award_stat {
    fmt.Printf("user: %s, award count: %d\n", name, count)
  }

  return
}

代碼執行結果:

user: f, award count: 178
user: d, award count: 152
user: b, award count: 159
user: e, award count: 182
user: c, award count: 170
user: a, award count: 159

權重抽獎

問題描述

數據結構和上面一致,只是問題發生變化,須要更加用戶的成單數來抽獎,用戶成單越多,中獎機率越高,結構以下所示:

// map中,key表明名稱,value表明成交單數
var users map[string]int64 = map[string]int64{
  "a": 10,
  "b": 6,
  "c": 3,
  "d": 12,
  "f": 1,
}

解決思路

這一題是上一題的延伸,加了訂單數進去,作爲權重來爲用戶抽獎。此題和上面的問題如此的類似,可把上面的問題, 理解成全部的用戶權重都相同的抽獎,而此題是權重不一樣的抽獎。解決此問題,依舊是把map轉爲數組來思考, 把各用戶的權重,從前到後依次拼接到數軸上,數軸的起點到終點即時中獎區間,而隨機數落到的那個用戶的區間,那個用戶即爲中獎用戶。

實際編碼

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func GetAwardUserName(users map[string]int64) (name string) {
  type A_user struct {
    Name   string
    Offset int64
    Num    int64
  }

  a_user_arr := make([]*A_user, 0)
  var sum_num int64
  for name, num := range users {
    a_user := &A_user{
      Name:   name,
      Offset: sum_num,
      Num:    num,
    }
    a_user_arr = append(a_user_arr, a_user)
    sum_num += num
  }

  award_num := rand.Int63n(sum_num)

  for index, _ := range a_user_arr {
    a_user := a_user_arr[index]
    if a_user.Offset+a_user.Num > award_num {
      name = a_user.Name
      return
    }
  }
  return
}

func main() {
  var users map[string]int64 = map[string]int64{
    "a": 10,
    "b": 5,
    "c": 15,
    "d": 20,
    "e": 10,
    "f": 30,
  }

  rand.Seed(time.Now().Unix())
  award_stat := make(map[string]int64)
  for i := 0; i < 10000; i += 1 {
    name := GetAwardUserName(users)
    if count, ok := award_stat[name]; ok {
      award_stat[name] = count + 1
    } else {
      award_stat[name] = 1
    }
  }

  for name, count := range award_stat {
    fmt.Printf("user: %s, award count: %d\n", name, count)
  }

  return
}

代碼執行結果:

user: c, award count: 1667
user: f, award count: 3310
user: e, award count: 1099
user: d, award count: 2276
user: b, award count: 549
user: a, award count: 1099
相關文章
相關標籤/搜索