go語言入門教程02-go常用庫+編譯consul

go常用庫使用教程

go idea環境搭建

插件安裝

idea選擇插件搜索go 安裝
在這裏插入圖片描述

新建項目

idea-File-New-Project 選擇 Go Modules(vgo)
在這裏插入圖片描述
新建的項目根目錄下多了go.mod和go.sum文件,此時可編寫go文件運行程序了,當import模塊時會自動添加到go.mod文件
中,如果未加入可使用快捷鍵alt+回車。

配置GOPATH

go允許項目自定義Project GOPATH和全局Root GOPATH隔離,源代碼就可以新建在Project GOPATH/src下
臨時設置set GOPATH=C:\Go\gopath;C:\Users\GVT\go
或者在idea中Setting-Languages & FrameWorks-Go-GOPATH
在這裏插入圖片描述
一般GOPATH目錄結構爲:
在這裏插入圖片描述

庫介紹

go常用內置庫

文件相關

package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)
/**
字節流讀取
 */
func readByteFile() string{
	file,_:=os.Open("f:/a.json")
	defer file.Close()
	fi, _ :=file.Stat()
	size:=fi.Size()
	b := make([]byte, size)
	file.Read(b)
	return string(b)
}
/**
字符流讀取
 */
func readBufferFile() string{
	file,_:=os.Open("f:/a.json")
	reader:=bufio.NewReader(file)
	defer file.Close()
	var result string="";
	for {
		str,err:=reader.ReadString('\n')
		if(err==io.EOF){
			break;
		}
		result=result+str;
	}
	return result
}
func writeContent(){
	path := "f:/cw.txt"
	file,_:=os.OpenFile(path,os.O_CREATE|os.O_WRONLY,0666)
	defer file.Close()
	result:="hello world\n"
	file.Write([]byte(result))

	writer:=bufio.NewWriter(file);
	writer.WriteString("zs")
	writer.Flush()


}
func main(){
	//獲取臨時目錄
	fmt.Println(os.TempDir())
	//Mkdir 用於創建單個目錄。 MkdirAll用於創建多個目錄
	os.Mkdir("f:/testtt",os.ModePerm)
	//Remove 用於刪除單個目錄下所有文件和目錄,不能刪除子目錄。 RemoveAll用於刪除目錄,包含所有
	os.Remove("f:/testtt")
	return;
	fmt.Println(readByteFile())
	fmt.Println(readBufferFile())
	content,_:=ioutil.ReadFile("f:/a.json")
	fmt.Println(string(content))
	writeContent()
	//io.copy
}

時間相關

package main

import (
	"fmt"
	"time"
)
/**
操作時間
 */
func datetime(){
	now:=time.Now();
	fmt.Println(now.String()) //獲取字符串 2020-05-13 16:45:19.0916627 +0800 CST m=+0.006016001
	fmt.Println(now.UnixNano()) //獲取時間戳 1589359519091662700
	fmt.Println(now.Date()) //獲取年月份  2020 May 13
	fmt.Println(now.Clock()) //獲取時分秒 16 45 19
	time.Sleep(time.Second*1) //休眠10s
	fmt.Println(now.Format("2006-01-02 15:04:05"))//格式化日期

	//操作時間
	timeDur := time.Duration(10)*time.Second + time.Duration(1)*time.Minute
	fmt.Println(now.Add(timeDur).Add(10*time.Hour))
	fmt.Println(now.Add(timeDur).Add(10*time.Hour).After(now))
	//休眠指定時間
	time.Sleep(10*time.Second)
}
/**
定時器
timer只能在時間到了執行一次
 */
func timer(){
	t:=time.NewTimer(2*time.Second)
	defer t.Stop()
	<-t.C  //t.C是 一個chan 到了指定時候自動寫入數據到通道這裏會阻塞等到數據,這樣實現定時器
	fmt.Println("2s時間到了")
}
/**
 timer實現每隔n秒之心過一次
 */
func timerContinue(){
	t:=time.NewTimer(2*time.Second)
	defer t.Stop()
	for {
		<-t.C //t.C是 一個chan 到了指定時候自動寫入數據到通道這裏會阻塞等到數據,這樣實現定時器
		fmt.Println("2s時間到了")
		//重置重新等待2s
		t.Reset(2*time.Second)
	}
}
/**
 ticker每隔n秒自動執行
 */
func ticker(){
	t:=time.NewTicker(2*time.Second)
	defer t.Stop()
	for {
		<-t.C //t.C是 一個chan 到了指定時候自動寫入數據到通道這裏會阻塞等到數據,這樣實現定時器
		fmt.Println("2s時間到了")
	}
}
func main(){
	timerContinue()

}

正則相關

package main

import (
	"fmt"
	"regexp"
)

func main() {
	rege,_ :=regexp.Compile("[0-9]{11}")
	fmt.Println(rege.MatchString("13537643253")) //匹配字符串
	rege1,_ :=regexp.Compile(`age=(\d+)`) //替換字符串
	fmt.Println(rege1.ReplaceAllString("hello,age=80","aa=$1"))

}

線程相關

線程操作
package main

import (
	"fmt"
	"time"
)

func async() {
	fmt.Println("子線程打印結果")
}
func addTest(i int, j int, ch *int) {
	*ch = i + j;
}
func chanelTest(i int, j int, ch chan int) {
	ch <- i + j;
}
func main() {
	//可能子線程來不及調用就退除主線程 子線程打印結果不一定會出現
	go async()
	fmt.Println("父線程打印結果")
	//如果sleep了基本上只要線程運行時間不超過暫停時間都能打印
	time.Sleep(time.Second * 1)
	i, j := 5, 6
	resu := 0
	// go直接調用時異步 沒辦法保證addTest執行完成了到後面所有resu可能是0也可能是11,但執行到後面肯定是11
	go addTest(i, j, &resu)
	fmt.Println(resu)
	time.Sleep(time.Second * 1)
	fmt.Println(resu)
	//通道 保證同步
	ch := make(chan int)
	go chanelTest(i, j, ch)
	result := <-ch
	fmt.Println(result)

	//帶緩衝區通道
	ch1 := make(chan int, 2)
	// 因爲 ch 是帶緩衝的通道,我們可以同時發送兩個數據
	// 而不用立刻需要去同步讀取數據
	ch1 <- 1
	ch1 <- 2
	// 獲取這兩個數據
	fmt.Println(<-ch1)
	fmt.Println(<-ch1)
	//緩衝區只有兩個 獲取第三次永遠獲取不到直接all goroutines are asleep - deadlock!
	//panic("會報錯,打斷程序運行。但是不會阻止defer運行")
	fmt.Println(<-ch1)
}

waitgroup
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
)

func main() {
	urls:=[]string{
		"http://www.baidu.com",
		"http://www.qq.com",
	}
	var wg sync.WaitGroup
	for _,url:= range urls{
		//wg加1表示開始1個任務
		wg.Add(1)
		go func(url string) {
			//完成一個 wg自動-1
			defer wg.Done()
			resp,_:=http.Get(url)
			bytes, _ := ioutil.ReadAll(resp.Body)
			fmt.Println(string(bytes))
		}(url)
	}
	//等待wg的值==0 就停止等待 相當於java中CountDownLatch
	wg.Wait()
}

信號sig
package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	fmt.Println(os.Getpid())
	//定義通道 是信號類型
	cb:=make(chan os.Signal)
	//定義一個信號監聽,signal.Notify(cb)監聽所有信號,下面指定監聽interrupt信號ctrl+c觸發
	signal.Notify(cb,syscall.SIGINT)
	//阻塞等待一個信號 <-cb可以不給變量賦值,下面是賦值
	//使用 go run sig.go運行 ctrl+c收到一個interrupt的信號 linux下可以使用kill -l查看信號 使用kill -s 信號id 進程號發送信號
	s:=<-cb
	fmt.Println(s)
}
/**
信號類型(kill -l)
個平臺的信號定義或許有些不同。下面列出了POSIX中定義的信號。
Linux 使用34-64信號用作實時系統中。
命令 man 7 signal 提供了官方的信號介紹。
在POSIX.1-1990標準中定義的信號列表
信號	值	動作	說明
SIGHUP	1	Term	終端控制進程結束(終端連接斷開)
SIGINT	2	Term	用戶發送INTR字符(Ctrl+C)觸發
SIGQUIT	3	Core	用戶發送QUIT字符(Ctrl+/)觸發
SIGILL	4	Core	非法指令(程序錯誤、試圖執行數據段、棧溢出等)
SIGABRT	6	Core	調用abort函數觸發
SIGFPE	8	Core	算術運行錯誤(浮點運算錯誤、除數爲零等)
SIGKILL	9	Term	無條件結束程序(不能被捕獲、阻塞或忽略)
SIGSEGV	11	Core	無效內存引用(試圖訪問不屬於自己的內存空間、對只讀內存空間進行寫操作)
SIGPIPE	13	Term	消息管道損壞(FIFO/Socket通信時,管道未打開而進行寫操作)
SIGALRM	14	Term	時鐘定時信號
SIGTERM	15	Term	結束程序(可以被捕獲、阻塞或忽略)
SIGUSR1	30,10,16	Term	用戶保留
SIGUSR2	31,12,17	Term	用戶保留
SIGCHLD	20,17,18	Ign	子進程結束(由父進程接收)
SIGCONT	19,18,25	Cont	繼續執行已經停止的進程(不能被阻塞)
SIGSTOP	17,19,23	Stop	停止進程(不能被捕獲、阻塞或忽略)
SIGTSTP	18,20,24	Stop	停止進程(可以被捕獲、阻塞或忽略)
SIGTTIN	21,21,26	Stop	後臺程序從終端中讀取數據時觸發
SIGTTOU	22,22,27	Stop	後臺程序向終端中寫數據時觸發

在SUSv2和POSIX.1-2001標準中的信號列表:
信號	值	動作	說明
SIGTRAP	5	Core	Trap指令觸發(如斷點,在調試器中使用)
SIGBUS	0,7,10	Core	非法地址(內存地址對齊錯誤)
SIGPOLL	 	Term	Pollable event (Sys V). Synonym for SIGIO
SIGPROF	27,27,29	Term	性能時鐘信號(包含系統調用時間和進程佔用CPU的時間)
SIGSYS	12,31,12	Core	無效的系統調用(SVr4)
SIGURG	16,23,21	Ign	有緊急數據到達Socket(4.2BSD)
SIGVTALRM	26,26,28	Term	虛擬時鐘信號(進程佔用CPU的時間)(4.2BSD)
SIGXCPU	24,24,30	Core	超過CPU時間資源限制(4.2BSD)
SIGXFSZ	25,25,31	Core	超過文件大小資源限制(4.2BSD)
 */

context
package main

import (
	"context"
	"fmt"
	"time"
)

func add(context context.Context,p1 int) int {
	var result int=0
	for i:=0;;i++ {
		//golang 的 select 的功能和 select, poll, epoll 相似,就是監聽 IO 操作,當 IO 操作發生時,觸發相應的動作。
		select{
		    //發現存在canel()動作就是有io動作 此時會觸發
			case <-context.Done():
				return result
			default:
		}
		time.Sleep(100*time.Millisecond)
		result=result+1
	}
	return result;
}
/**
   模擬一個累加的動作,超過2s自動取消這個累加線程
 */
func testContextCanel(){
	//context表示上下文,canel是一個取消方法調用會發送一個通道數據 context.Done就會存在io操作,監聽到這個動作就應該自定義取消邏輯
	contenxt,canel:=context.WithCancel(context.Background())
	go func() {
		//模擬2s後就調用取消
		time.Sleep(2*time.Second)
		canel()
	}()
	fmt.Println(add(contenxt,1))
}
/**
  上面testContextCanel簡潔版
 */
func testContextTimeout(){
	//context表示上下文,當超過指定時間自動調用會發送一個通道數據 context.Done就會存在io操作,監聽到這個動作就應該自定義取消邏輯
	contenxt,canel:=context.WithTimeout(context.Background(),2*time.Second)
	//可以在超時前手動去取消 這裏不需要
	defer canel()
	fmt.Println(add(contenxt,1))
}
/**
  上面testContextCanel簡潔版 deanline傳入的是時間 timeout傳入的間隔時間
 */
func testContextDeadLine(){
	//context表示上下文,當超過指定時間自動調用會發送一個通道數據 context.Done就會存在io操作,監聽到這個動作就應該自定義取消邏輯
	contenxt,canel:=context.WithDeadline(context.Background(),time.Now().Add(2*time.Second))
	//可以在超時前手動去取消 這裏不需要
	defer canel()
	fmt.Println(add(contenxt,1))
}
func main() {
	testContextDeadLine()
}

mysql

package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql" //引入驅動包
)
type UserRole struct {
	UserId    int64
	RoleId  int64
}
func getDB() (*sql.DB){
	db, _ := sql.Open("mysql", "root:Qjkj2018@tcp(192.168.1.230:3306)/ums_docker_dev")
	return db
}
/**
查詢sql
 */
func query(){
	var user UserRole
	DB:=getDB()
	defer DB.Close()
	//設置數據庫最大連接數
	DB.SetConnMaxLifetime(100)
	//設置上數據庫最大閒置連接數
	DB.SetMaxIdleConns(10)
	//驗證連接
	if err := DB.Ping(); err != nil {
		fmt.Println("open database fail")
		return
	}
	rows, e := DB.Query("select user_id as UserId,role_id as RoleId from user_role_rel")
	defer rows.Close()
	if e == nil {
		errors.New("query incur error")
	}
	for rows.Next(){
		//字段名稱必須和數據庫返回的列名完全相同,所有sql上用as指定別名
		e := rows.Scan(&user.UserId, &user.RoleId)
		if e == nil{
			//json對應實體字段必須是大寫,才能轉換成對應字段 否則爲nil
			result, _ := json.Marshal(user)
			fmt.Println(string(result))
		}
	}
}
/**
執行sql
 */
func execute(sql string) int64{
	DB:=getDB()
	defer DB.Close()
	result,_:=DB.Exec(sql)
	affectRow,_:=result.RowsAffected()
	return affectRow
}
/**
預處理防止sql注入
 */
func executeFmt(sql string,args ...interface{}) int64{
	DB:=getDB()
	defer DB.Close()
	stmt,_:=DB.Prepare(sql)
	result,_:=stmt.Exec(args...)
	affectRow,_:=result.RowsAffected()
	return affectRow
}
func main() {
	query()
	fmt.Println(execute("delete from user_role_rel where user_id=-1"));
	fmt.Println(executeFmt("delete from user_role_rel where user_id=?","-1"))
}

json

package main

import (
	"encoding/json"
	"fmt"
)

type Product struct {
	Name      string
	Price     float64
	test int  //注意首字母小寫字段無法轉換爲json字段
}
func main() {
	p:=Product{
		Name:"zs",
	}
	p.Price=100
	fmt.Println(p.Name)
	//對象轉換成json字節數組
	result,_:=json.Marshal(p)
	fmt.Println(string(result))
	p1:=Product{}
	//將字節數組轉換爲json
	json.Unmarshal(result,&p1) //傳入引用才能獲取真實的對象,否則返回是沒有賦值的空對象
	fmt.Println(p1.Price)
}

hash

package main

import (
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
)
/**
  md5
 */
func hash_md5(str string){
	md:=md5.New()
	md.Write([]byte(str))
	fmt.Println(hex.EncodeToString(md.Sum(nil)))
}
/**
  shaXX系列
    sha1
    sha256
    sha512
 */
func hash_sha1(str string){
	md:=sha1.New()
	md.Write([]byte(str))
	fmt.Println(hex.EncodeToString(md.Sum(nil)))
}
/**
  對稱加密系列 :des,aes
  非對稱加密 rsa
  簽名 dsa 暫不列出
 */


func main() {
	hash_md5("hello")
	hash_sha1("hello")
}

go常用第三方庫

mitchellh命令行幫助

框架是個人開發的命令行程序框架,作者還成立了公司(HashiCorp),其公司的產品也採用這個CLI框架
框架的思路是:把命令和執行方法以map的形式記錄在內部,然後根據用戶輸入的命令,決定執行哪個方法。實際上記錄的是命令字符串和CommandFactory,由CommandFactory創建Command然後執行。

框架默認支持version和help兩個功能。

目前在註冊中心Consul, Vault, Terraform, and Nomad.中有使用該框架。

package main

import (
	"fmt"
	"log"
	"os"
	"github.com/mitchellh/cli"
)

func main() {
	/**
		go run cli.go
		I am foo command
		Usage: app [--version] [--help] <command> [<args>] 這裏會顯示app名稱也就是NewCLI第一個參數
	    go run cli.go --version 就會顯示後面定義的版本號參數
	 */
	c := cli.NewCLI("app", "1.0.100")
	// go run cli.go aa bb  後面所有的參數 比如 aa 和bb
	c.Args = os.Args[1:]
	ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr,Reader:os.Stdin}
	//打印內容到輸出流
	ui.Output("打印到界面")
	//打印到ErrorWriter
	//ui.Error("出錯了")
	//用戶交互輸入內容
	commd,_:=ui.Ask("請輸入您的命令:")
	fmt.Println(commd)
	c.Commands = map[string]cli.CommandFactory{
		"foo": fooCommandFactory,
		//"bar": barCommandFactory,
	}

	exitStatus, err := c.Run()
	if err != nil {
		log.Println(err)
	}

	os.Exit(exitStatus)
}
/**
  定義命名適配工廠,返回實際執行命令的對象
  對象包含3個方法 幫助,執行,摘要
 */
func fooCommandFactory() (cli.Command, error) {
	fmt.Println("I am foo command")
	return new(FooCommand), nil
}
type FooCommand struct{}
/**
幫助方法 比如 go run cli.go foo --help 就會執行這個方法
 */
func (f *FooCommand) Help() string {
	return "help foo"
}
/**
參數執行方法 比如 go run cli.go foo 就會執行這個方法
args就是所有參數 go run cli.go foo aa bb  參數是aa和bb
 */
func (f *FooCommand) Run(args []string) int {
	fmt.Println("Foo Command is running")
	return 1
}
/**
摘要方法 不加入任何參數時 列表所有參數 參數摘要在參數後
F:\code\go\liblearn>go run cli.go
I am foo command
Usage: app [--version] [--help] <command> [<args>]

Available commands are:
    foo    foo command Synopsis

 */
func (f *FooCommand) Synopsis() string {
	return "foo command Synopsis"
}

beego web開發

beego 相比於martini revel等其他優秀golang框架 來說就是 beego爲 web開發人員提供了非常完善的組件(session,log,router, filter, validation, orm …), 並且中文文檔豐富, 是一個非常好的goweb入門框架,
使用javaspring的開發人員入門go,非常適合使用beego。

beego腳手架安裝

下載bee腳手架生成工具:https://github.com/beego/bee/releases

如window下 下載後拷貝到 go的bin目錄即可

beego生成代碼

設置項目GOPATH後執行命令:

bee new beego

生成目錄結構
在這裏插入圖片描述

具體開發請參考:https://beego.me/quickstart

gin web開發

Gin 是一個 go 寫的 web 框架,具有高性能的優點。官方地址:https://github.com/gin-gonic/gin
性能相對來說強於beego,實際卻沒有http包構建的一半性能。

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.Writer.Write([]byte("hello"))
	})
	r.Run(":8888") // listen and serve on 0.0.0.0:8080
}

編譯運行consul

克隆最新源碼:go clone https://github.com/hashicorp/consul.git
使用idea工具打開 sync go module
選擇main.go,添加項目參數:

agent -server -ui -bootstrap-expect=1 -data-dir=F:/code/go/consul-master/datadir -node=agent-1 -client=0.0.0.0 -bind=192.168.40.77 -datacenter=dc1

–bind是綁定本機的ip地址
–data-dir指定存儲數據目錄
在這裏插入圖片描述
運行後訪問:
http://localhost:8500正常啓動

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章