最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang單元測試、go協(xié)程和管道示例詳解

 更新時間:2025年11月01日 11:10:59   作者:星云愛編程  
在Go語言中并發(fā)編程是一種核心特性,這篇文章主要介紹了Golang單元測試、go協(xié)程和管道的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

1.單元測試

1.1基本介紹

Go語言中自帶有一個輕量級的測試框架testing和自帶的go test命令來實現(xiàn)單元測試和性能測試,testing框架和其他語言中的測試框架類似,可以基于這個框架寫針對相應函數(shù)的測試用例,也可以基于該框架寫相應的壓力測試用例。

通過單元測試,可以解決如下問題:

  1. 確保每個函數(shù)是可運行,并且運行結果是正確的
  2. 確保寫出來的代碼性能是好的
  3. 單元測試能及時的發(fā)現(xiàn)程序設計或實現(xiàn)的邏輯錯誤,使問題及早暴露,便于問題的定位解決,而性能測試的重點在于發(fā)現(xiàn)程序設計上的一些問題,讓程序能夠在高并發(fā)的情況下還能保持穩(wěn)定

1.2單元測試編寫步驟

(1)創(chuàng)建測試文件

測試文件以*test.go結尾,例如:math_test.go

(2)編寫測試函數(shù)

測試函數(shù)以Test開頭,接受*testing.T參數(shù)

func TestAdd(t *testing.T){
	//測試邏輯
}

(3)表格驅動測試

使用結構體切片定義多個測試用例,循環(huán)遍歷執(zhí)行

func TestAdd(t *testing.T){
	//使用結構體切片定義多個測試用例
	tests:=[]struct{
		a,b,want int
	}{
		{1,2,3},
		{3,4,7},
		{5,6,11},
	}
	//循環(huán)遍歷執(zhí)行
	for _,v:=range tests{
		sum:=Add(v.a,v.b)
		if sum != v.want{
			t.Errorf("Add(%d,%d)=%d;want %d\n",v.a,v.b,sum,v.want)
		}
	}
}

 (4)子測試

使用t.Run()分組測試用例,提升可讀性和選擇性運行

func TestAdd(t *testing.T){
	//使用結構體切片定義多個測試用例
	tests:=[]struct{
		name string
		a,b,want int
	}{
		//分組
		{"正數(shù)",1,2,3},
		{"負數(shù)",-3,-4,-7},
		{"零值",0,0,0},
	}
	//循環(huán)遍歷執(zhí)行
	for _,v:=range tests{
		sum:=Add(v.a,v.b)
		if sum != v.want{
			t.Errorf("Add(%d,%d)=%d;want %d\n",v.a,v.b,sum,v.want)
		}
	}
}

(5)錯誤測試

驗證函數(shù)是否返回預期錯誤

func TestDivide(t *testing.T){
	_,err:=Divide(6,0)
	if err ==nil{
		t.Fatal("預期錯誤,并未返回")
	}
	if err.Error()!="除零錯誤"{
		t.Error("錯誤消息不符:%s",err)
	}
}

(6)測試覆蓋率

生成并查看覆蓋率報告

go test -coverprofile=coverage.out
go tool cover -html=coverage.out

(7)初始化和清理

使用TestMain進行全局設置

func TestMain(m *testing.M){
	setup()
	code:=m.Run()
	teardown()
	os.Exit(code)
}

(8)使用t.Cleanup

注冊清理函數(shù)

func TestDB(t *testing.T){
	db:=setupDB()
	t.Cleanup(func(){
		teardownDB(db)
	})
	//測試邏輯
}

(9)模擬依賴

通過接口實現(xiàn)Mock()

type Storage interface{
	Get(id int) string
}

type MockStorage struct{}
func (m*MockStorage)Get(id int)string{
	return "mock"
}

func TestService(t*testing.T){
	s:=&Service{storage:&MockStorage{}}
	//測試邏輯
}

(10)跳過測試

func TestNetwork(t *testing.T){
	if testing.Short(){
		t.Skip("短模式下跳過")
	}
	//網(wǎng)絡相關測試
}

(11)并行測試

使用t.Parallel()加速測試

func TestParallel(t *testing.T){
	t.Parallel()
	//并發(fā)安全測試邏輯
}

1.3總結

  1. 測試用例文件名必須以 test.go結尾。比如 cal tert.go,cal 不是固定的。
  2. 測試用例函數(shù)必須以Test開頭,一般來說就是Test+被測試的函數(shù)名,比如TestAddUpper。TestAddUpper(t *tesing.T)的形參類型必須是 *testing.T【看一下手冊】
  3. 一個測試用例文件中,可以有多個測試用例函數(shù),比如 TestAddUpper
  4. Testsub運行測試用例指令                                                                                        (1)cmd>go test[如果運行正確,無日志,錯誤時,會輸出日志]                            (2)cmd>gotest-v[運行正確或是錯誤,都輸出日志]
  5. 當出現(xiàn)錯誤時,可以使用t.Fatalf來格式化輸出錯誤信息,并退出程序
  6. t.Logf方法可以輸出相應的日志
  7. 測試用例函數(shù),并沒有放在main函數(shù)中,也執(zhí)行了,這就是測試用例的方便之處
  8. PASS表示測試用例運行成功,F(xiàn)AIL表示測試用例運行失敗

1.4單元測試綜合案例

被測代碼文件:mathutil.go

package main

// 計算兩個數(shù)的和
func Add(a, b int) int {
    return a + b
}

// 計算階乘
func Factorial(n int) int {
    if n < 0 {
        return -1
    }
    if n == 0 {
        return 1
    }
    return n * Factorial(n-1)
}

// 判斷是否為素數(shù)
func IsPrime(n int) bool {
    if n < 2 {
        return false
    }
    for i := 2; i*i <= n; i++ {
        if n%i == 0 {
            return false
        }
    }
    return true
}

測試文件:mathutil_test.go

package main

import (
    "testing"
)

func TestAdd(t *testing.T) {
    tests := []struct {
        a, b, expected int
    }{
        {1, 2, 3},
        {-1, 1, 0},
        {0, 0, 0},
        {100, 200, 300},
    }

    for _, tt := range tests {
        result := Add(tt.a, tt.b)
        if result != tt.expected {
            t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
        }
    }
}

func TestFactorial(t *testing.T) {
    tests := []struct {
        n, expected int
    }{
        {0, 1},
        {1, 1},
        {5, 120},
        {10, 3628800},
        {-1, -1},
    }

    for _, tt := range tests {
        result := Factorial(tt.n)
        if result != tt.expected {
            t.Errorf("Factorial(%d) = %d; expected %d", tt.n, result, tt.expected)
        }
    }
}

func TestIsPrime(t *testing.T) {
    tests := []struct {
        n        int
        expected bool
    }{
        {2, true},
        {3, true},
        {4, false},
        {17, true},
        {1, false},
        {0, false},
        {-1, false},
    }

    for _, tt := range tests {
        result := IsPrime(tt.n)
        if result != tt.expected {
            t.Errorf("IsPrime(%d) = %v; expected %v", tt.n, result, tt.expected)
        }
    }
}

運行:在bash下運行

go test -v

2.goroutine

2.1進程和線程說明

  • 進程就是程序程序在操作系統(tǒng)中的一次執(zhí)行過程,是系統(tǒng)進行資源分配和調(diào)度的基本單位
  • 線程是進程的一個執(zhí)行實例,是程序執(zhí)行的最小單元,它是比進程更小的能獨立運行的基本單位。
  • 一個進程可以創(chuàng)建核銷毀多個線程,同一個進程中的多個線程可以并發(fā)執(zhí)行。
  • 一個程序至少有一個進程,一個進程至少有一個線程

2.2進程線程關系示意圖

2.3并發(fā)和并行

  1. 多線程程序在單核上運行,就是并發(fā)
  2. 多線程程序在多核上運行,就是并行
  • 并發(fā):因為是在一個cpu上,比如有10個線程,每個線程執(zhí)行10毫秒(進行輪詢操作),從人的角度看,好像這10個線程都在運行,但是從微觀上看,在某一個時間點看,其實只有一個線程在執(zhí)行,這就是并發(fā)。
  • 并行:因為是在多個cpu上(比如有10個cpu),比如有10個線程,每個線程執(zhí)行10毫秒(各自在不同cpu上執(zhí)行),從人的角度看,這10個線程都在運行,但是從微觀上看,在某一個時間點看,也同時有10個線程在執(zhí)行,這就是并行 

2.4Go協(xié)程和Go主線程

Go主線程(有程序員直接稱為線程/也可以理解成進程):一個Go線程上,可以起多個協(xié)程,你可以這樣理解,協(xié)程是輕量級的線程[編譯器做優(yōu)化]。

Go協(xié)程的特點

  • 有獨立的??臻g
  • 共享程序
  • 堆空間調(diào)度由用戶控制
  • 協(xié)程是輕量級的線程

2.5 goroutine使用案例

使用 go 關鍵字啟動協(xié)程

package main
import(
	"fmt"
	"time"
)

func test(){
	for i:=0;i<10;i++{
		fmt.Printf("test()~%v\n",i)
		time.Sleep(1000*time.Millisecond)//休眠一秒
	}
}

func main(){
	//啟動協(xié)程
	go test()

	for i:=0;i<5;i++{
		fmt.Printf("main()~%v\n",i)
		time.Sleep(1000*time.Millisecond)//休眠一秒
	}
}

說明:

  • 主線程是一個物理線程,直接作用在cpu上的。是重量級的,非常耗費cpu資源
  • 協(xié)程從主線程開啟的,是輕量級的線程,是邏輯態(tài)。對資源消耗相對小。
  • Golang的協(xié)程機制是重要的特點,可以輕松的開啟上萬個協(xié)程。其它編程語言的并發(fā)機制是一般基于線程的,開啟過多的線程,資源耗費大,這里就突顯Golang在并發(fā)上的優(yōu)勢了
  • 當主線程終止時,其他的協(xié)程也將終止

2.6MPG基本介紹

  1. M 代表著一個內(nèi)核線程,也可以稱為一個工作線程。goroutine就是跑在M之上的
  2. P 代表著(Processor)處理器 它的主要用途就是用來執(zhí)行goroutine的,一個P代表執(zhí)行一個Go代碼片段的基礎(可以理解為上下文環(huán)境),所以它也維護了一個可運行的goroutine隊列,和自由的goroutine隊列,里面存儲了所有需要它來執(zhí)行的goroutine。
  3. G 代表著goroutine 實際的數(shù)據(jù)結構(就是你封裝的那個方法),并維護者goroutine 需要的棧、程序計數(shù)器以及它所在的M等信息。
  4. Seched 代表著一個調(diào)度器 它維護有存儲空閑的M隊列和空閑的P隊列,可運行的G隊列,自由的G隊列以及調(diào)度器的一些狀態(tài)信息等。

2.7設置Go運行cpu的個數(shù)

所用到的方法:

 案例:

package main
import (
	"fmt"
	"runtime"
)

func main(){
	//獲取當前(邏輯)cpu的數(shù)量
	num:=runtime.NumCPU()
	//設置num-1的cpu運行go程序
	runtime.GOMAXPROCS(num)
	fmt.Println(num)
}

3.channel(管道)

3.1全局變量+互斥鎖解決資源競爭

案例: 啟動20個協(xié)程求1~20的階乘

package main
import (
	"fmt"
	"sync"
	"time"
)
 
var (
	myMap =make(map[int]int,10)
	//聲明一個全局的互斥鎖
	lock sync.Mutex
)

func test(n int){
	res:=1
	for i:=1;i<=n;i++{
		res*=i
	}
	//這里我們將res放入myMap中
	//加鎖
	lock.Lock()
	myMap[n]=res
	//解鎖
	lock.Unlock()
}

func main(){
	//開啟多個協(xié)程完成求階乘
	for i:=1;i<=20;i++{
		go test(i)
	}

	//休眠5秒
	time.Sleep(5*time.Second)
	//加鎖
	lock.Lock()
	for i,v:=range myMap{
		fmt.Printf("map[%d]=%d\n",i,v)
	}
	//解鎖
	lock.Unlock()
	 
}

3.2channel的介紹

  1. channel本質(zhì)就是一個數(shù)據(jù)結構-隊列
  2. 數(shù)據(jù)是先進先出[FIFO]
  3. 線程安全,多goroutine訪問時,不需要加鎖,就是說channel本身就是線程安全的
  4. channel是類型安全的,只能發(fā)送和接收指定類型的數(shù)據(jù),例如:一個string的channel只能存放string類型數(shù)據(jù)
  5. 無緩沖channel是同步的,發(fā)送和接收操作會阻塞直到另一端準備好
  6. 緩沖channel允許在沒有接收者的情況下發(fā)送有限數(shù)量的數(shù)據(jù)
  7. channel可以通過 close() 函數(shù)關閉,關閉后不能再發(fā)送數(shù)據(jù)

 (1)定義channel

var 名字 chan 類型 

(2)創(chuàng)建channel

ch := make(chan int) // 創(chuàng)建一個無緩沖的int類型channel
ch := make(chan string, 10) // 創(chuàng)建一個緩沖大小為10的string類型channel

(3)發(fā)送和接受數(shù)據(jù)

ch <- 42 // 發(fā)送數(shù)據(jù)到channel
value := <-ch // 從channel接收數(shù)據(jù)
<-ch    //也可以不接受數(shù)據(jù),將數(shù)據(jù)推出

3.3channel的使用案例

(1)基本數(shù)據(jù)類型Chan

package main
import (
	"fmt"
)

func main(){
	//定義一個接受int類型的channel
	var intChan chan int
	//使用channel前需要make
	intChan=make(chan int,4)

	//進channel
	intChan<-1
	intChan<-2
	intChan<-3
	intChan<-4
	// intChan<-5  注意,當我們給channel寫入數(shù)據(jù)時,不能超過其容量

	//看看intChan是什么
	fmt.Printf("intChan 的值是%v,地址為%p,長度為%v,容量為%v\n",intChan,&intChan,len(intChan),cap(intChan))
	
	//從channel中取數(shù)據(jù)
	var num int
	num=<-intChan
	fmt.Println("num=",num)
	fmt.Printf("intChan 的長度為%v,容量為%v\n",len(intChan),cap(intChan))

	//注意:在沒有使用協(xié)程的情況下,如果我們的管道數(shù)據(jù)已經(jīng)全部取出,繼續(xù)取數(shù)據(jù)就會報deadlock
	num2:=<-intChan
	<-intChan  //數(shù)據(jù)出channel 也可以不接受,相當于丟棄
	num3:=<-intChan

	fmt.Printf("num2=%d , num3=%d\n",num2,num3)
	//num2=2 , num3=4
	//數(shù)據(jù)出channel時先進先出的
}

(2)struct管道和map管道:

package main
import (
	"fmt"
)

type Cat struct{
	Name string
	Age int
}

func main(){
	//structChan
	cat1:=Cat{"jav",12}
	cat2:=Cat{"mimi",3}
	var catChan chan Cat
	catChan=make(chan Cat,3)
	catChan<-cat1
	catChan<-cat2
	fmt.Println(<-catChan)
	cat3:=<-catChan
	fmt.Println(cat3)

	//mapChan
	var mapChan chan map[string]string
	mapChan=make(chan map[string]string,5)
	m1:=make(map[string]string,10)
	m1["功法1"]="九幽玄天"
	m1["功法2"]="天罡決"
	mapChan<-m1

	m2:=make(map[string]string)
	m2["神通1"]="古神決"
	m2["神通2"]="呼風喚雨"
	mapChan<-m2
	//輸出
	fmt.Println(<-mapChan)
	fmt.Println(<-mapChan)
}

(3)interface{}類型的chan

package main
import(
	"fmt"
)

type Person struct{
	Name string
	Age int
}
type Dog struct{
	Name string
	Age int
}

func main(){
	//能接受任意類型的管道
	var allChan chan interface{}
	allChan=make(chan interface{},10)//不指定空間10則無法使用
	//定義變量
	num1:=2
	str1:="channel is interesting"
	person1:=Person{"李星云",21}
	dog1:=Dog{"小紅",4}
	//chan接受數(shù)據(jù)
	allChan<-num1
	allChan<-str1
	allChan<-person1
	allChan<-dog1

	//取數(shù)據(jù)
	num2:=<-allChan
	str2:=<-allChan
	person2:=<-allChan
	dog2:=<-allChan
	//打印
	fmt.Printf("num2的類型為%T,值為%v\n",num2,num2)
	fmt.Printf("str2的類型為%T,值為%v\n",str2,str2)
	fmt.Printf("person2的類型為%T,值為%v\n",person2,person2)
	fmt.Printf("dog2的類型為%T,值為%v\n",dog2,dog2)

	//驗證
	// fmt.Println(person2.Name)
	//會報錯,此時是interface{}類型,不能由屬性
	//需類型斷言解決該問題
	person3,ok:=person2.(Person)
	if ok==false{
		fmt.Println("類型斷言失敗")
	}
	fmt.Printf("person3的類型為%T,值為%v\n",person3,person3)
	fmt.Println(person3.Name) 
}

3.4chan的關閉和遍歷

3.4.1chan的關閉

用到的函數(shù):

使用內(nèi)置函數(shù)close可以關閉channel,當channel關閉后,就不能再向channel寫數(shù)據(jù)了,但是仍然可以從該channel讀取數(shù)據(jù)

案例:

package main
import (
	"fmt"
)

func main(){
	var intChan chan int
	intChan=make(chan int,5)
	intChan<-1
	intChan<-2
	intChan<-3
	//關閉管道
	close(intChan)
	//這時不能再寫數(shù)據(jù)到intChan
	//intChan<-4
	//panic: send on closed channel
	//但是可以讀數(shù)據(jù)
	fmt.Println(<-intChan)
}

3.4.3chan的遍歷

channel支持for--range的方式進行遍歷,

請注意兩個細節(jié):

  1. 在遍歷時,如果channel沒有關閉,則回出現(xiàn)deadlock的錯誤
  2. 在遍歷時,如果channel已經(jīng)關閉,則會正常遍歷數(shù)據(jù),遍歷完后,就會退出遍歷。

案例1:沒有close

package main
import (
	"fmt"
)

func main(){
	var intChan chan int =make(chan int,100)

	//遍歷chan,接受數(shù)據(jù)
	for i:=0;i<100;i++{
		intChan<-i*2
	}

	//在遍歷讀數(shù)據(jù)時,如果channel沒有關閉,
	//則會出現(xiàn)fatal error: all goroutines are asleep - deadlock!
	for v:=range intChan{
		fmt.Println(v)
	}
	fmt.Println("遍歷完成~")//不會輸出
}

 案例2:close

package main
import (
	"fmt"
)

func main(){
	var intChan chan int =make(chan int,100)

	//遍歷chan,接受數(shù)據(jù)
	for i:=0;i<100;i++{
		intChan<-i*2
	}

	//在遍歷讀數(shù)據(jù)時,如果channel已經(jīng)關閉,
	//則會正常遍歷數(shù)據(jù),遍歷完數(shù)據(jù)后就會退出遍歷
	close(intChan)
	for v:=range intChan{
		fmt.Println(v)
	}
	fmt.Println("遍歷完成~")//正常輸出
}

3.5goroutine和channel結合

package main
import (
	"fmt"
	_ "time"
)

//writer Data
func writeData(intChan chan int){
	for i:=1;i<=200;i++{
		//放入數(shù)據(jù)
		intChan<-i 
		fmt.Println("writeData.............寫入數(shù)據(jù):",i)
	}
	//關閉
	close(intChan)
}

//read Data
func readData(intChan chan int,exitChan chan bool){
	for{
		v,ok:=<-intChan
		if !ok{
			break
		}
		fmt.Printf("readData 讀到數(shù)據(jù)=%v\n",v)
	}
	//讀完數(shù)據(jù)
	exitChan<-true
	close(exitChan)
}


func main(){
	//創(chuàng)建兩個管道
	intChan := make(chan int,200)
	exitChan := make(chan bool,1)

	go writeData(intChan)
	go readData(intChan,exitChan)

	// time.Sleep(5*time.Second)
	for {
		_,ok:=<-exitChan
		if !ok{
			break
		}
	}
}

3.6管道阻塞的機制

(1)無緩沖管道 :

  • 發(fā)送操作會阻塞,直到有另一個goroutine執(zhí)行接收操作
  • 接收操作會阻塞,直到有另一個goroutine執(zhí)行發(fā)送操作
  • 這種機制實現(xiàn)了goroutine之間的同步

(2)有緩沖管道 :

  • 當緩沖區(qū)未滿時,發(fā)送操作不會阻塞
  • 當緩沖區(qū)為空時,接收操作會阻塞
  • 當緩沖區(qū)滿時,發(fā)送操作會阻塞
  • 這種機制允許一定程度的異步操作

案例:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int) // 無緩沖管道

	go func() {
		time.Sleep(2 * time.Second)
		fmt.Println("準備發(fā)送數(shù)據(jù)")
		ch <- 42
		fmt.Println("數(shù)據(jù)已發(fā)送")
	}()

	fmt.Println("等待接收數(shù)據(jù)")
	value := <-ch
	fmt.Println("接收到數(shù)據(jù):", value)
}

解除阻塞的方式 :

  • 對于發(fā)送操作:有goroutine執(zhí)行接收操作
  • 對于接收操作:有goroutine執(zhí)行發(fā)送操作
  • 使用context或timeout機制取消阻塞
  • 關閉管道(關閉后接收操作不會阻塞,會立即返回零值)

解除阻塞案例:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)

	// 啟動一個goroutine,延遲發(fā)送數(shù)據(jù)
	go func() {
		time.Sleep(2 * time.Second)
		ch <- 42
		fmt.Println("數(shù)據(jù)已發(fā)送")
	}()

	// 主goroutine嘗試接收數(shù)據(jù),會阻塞直到有數(shù)據(jù)
	fmt.Println("等待接收數(shù)據(jù)...")
	value := <-ch
	fmt.Println("接收到數(shù)據(jù):", value)

	// 使用select實現(xiàn)超時解除阻塞
	select {
	case v := <-ch:
		fmt.Println("接收到數(shù)據(jù):", v)
	case <-time.After(1 * time.Second):
		fmt.Println("超時,解除阻塞")
	}

	// 關閉管道解除阻塞
	close(ch)
	v, ok := <-ch
	fmt.Println("從關閉的管道接收:", v, "是否成功:", ok)
}

3.7channel使用細節(jié)

  • 避免向已關閉的channel發(fā)送數(shù)據(jù),這會導致panic
  • 重復關閉channel會導致panic
  • 從已關閉的channel接收數(shù)據(jù)會立即返回零值
  • 使用nil channel會永久阻塞
  • 注意channel的緩沖區(qū)大小,過大會占用過多內(nèi)存
  • 使用 select 語句可以同時處理多個channel操作
  • 對于只讀或只寫channel,可以使用類型約束( <-chan 和 chan<- )
  • 使用 range 可以遍歷channel直到它被關閉

結語

到此這篇關于Golang單元測試、go協(xié)程和管道的文章就介紹到這了,更多相關Go單元測試、go協(xié)程和管道內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 深入理解Golang channel的應用

    深入理解Golang channel的應用

    channel是用于 goroutine 之間的同步、通信的數(shù)據(jù)結構。它為程序員提供了更高一層次的抽象,封裝了更多的功能,這樣并發(fā)編程變得更加容易和安全。本文通過示例為大家詳細介紹了channel的應用,需要的可以參考一下
    2022-10-10
  • Go語言函數(shù)學習教程

    Go語言函數(shù)學習教程

    這篇文章主要介紹了Go語言函數(shù)基本用法,結合實例形式分析了Go語言函數(shù)的格式、定義、使用方法與相關注意事項,需要的朋友可以參考下
    2016-07-07
  • golang 實現(xiàn)struct、json、map互相轉化

    golang 實現(xiàn)struct、json、map互相轉化

    這篇文章主要介紹了golang 實現(xiàn)struct、json、map互相轉化,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang如何調(diào)用Python代碼詳解

    Golang如何調(diào)用Python代碼詳解

    這篇文章主要給大家介紹了關于Golang如何調(diào)用Python代碼的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-10-10
  • golang程序使用alpine編譯出最小arm鏡像實現(xiàn)

    golang程序使用alpine編譯出最小arm鏡像實現(xiàn)

    這篇文章主要為大家介紹了golang程序使用alpine編譯出最小arm鏡像,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 一文帶你了解Go語言中接口的使用

    一文帶你了解Go語言中接口的使用

    這篇文章主要和大家分享一下Go語言中的接口的使用,文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的小伙伴可以參考一下
    2022-12-12
  • GoFrame框架數(shù)據(jù)校驗之校驗對象校驗結構體

    GoFrame框架數(shù)據(jù)校驗之校驗對象校驗結構體

    這篇文章主要為大家介紹了GoFrame框架數(shù)據(jù)校驗之校驗對象校驗結構體示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Go語言實現(xiàn)文件上傳

    Go語言實現(xiàn)文件上傳

    這篇文章主要為大家詳細介紹了Go語言實現(xiàn)文件上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • go 微服務框架kratos使用中間件的方法

    go 微服務框架kratos使用中間件的方法

    在go語言中,中間件是一種用于處理http請求的開發(fā)模式,允許開發(fā)人員在請求到達處理程序之前或之后執(zhí)行特定的操作,如日志記錄、身份驗證、錯誤處理等,這篇文章主要介紹了go 微服務框架kratos使用中間件的方法,需要的朋友可以參考下
    2024-05-05
  • 使用Go語言實現(xiàn)的WebDAV內(nèi)存文件系統(tǒng)

    使用Go語言實現(xiàn)的WebDAV內(nèi)存文件系統(tǒng)

    這篇文章主要為大家詳細介紹了如何使用Go語言實現(xiàn)的WebDAV內(nèi)存文件系統(tǒng),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-11-11

最新評論

东平县| 伊金霍洛旗| 柘荣县| 威海市| 盐城市| 哈尔滨市| 通渭县| 灵川县| 新平| 保靖县| 武汉市| 盐城市| 综艺| 南宁市| 岳阳县| 金堂县| 东丽区| 龙胜| 信丰县| 东源县| 武川县| 桦川县| 永修县| 汝阳县| 定南县| 天气| 志丹县| 云南省| 靖边县| 甘德县| 庆阳市| 阿勒泰市| 洛川县| 龙山县| 石嘴山市| 镇赉县| 普兰县| 高密市| 区。| 海林市| 昂仁县|