欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang標(biāo)準(zhǔn)庫unsafe源碼解讀

 更新時(shí)間:2022年08月11日 14:35:56   作者:大摩羯先生  
這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫unsafe源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

當(dāng)你閱讀Golang源碼時(shí)一定遇到過unsafe.Pointer、uintptr、unsafe.Sizeof等,是否很疑惑它們到底在做什么?如果不了解這些底層代碼在發(fā)揮什么作用,一定也無法了解上層應(yīng)用構(gòu)建的來由了,本篇我們來剖析下Golang標(biāo)準(zhǔn)庫的底層包unsafe!

unsafe包

我們基于Go1.16版本進(jìn)行剖析,按照包的簡(jiǎn)介內(nèi)容描述是:unsafe包含的是圍繞Go程序安全相關(guān)的操作,導(dǎo)入unsafe包后構(gòu)建的功能可能不被Go相關(guān)兼容性支持。

這里和Java中的unsafe包功能類似,unsafe包中功能主要面向Go語言標(biāo)準(zhǔn)庫內(nèi)部使用,一般業(yè)務(wù)開發(fā)中很少用到,除非是要做基礎(chǔ)能力的鋪建,對(duì)該包的使用應(yīng)當(dāng)是非常熟悉它的特性,對(duì)使用不當(dāng)帶來的負(fù)面影響也要非常清晰。

unsafe構(gòu)成

type ArbitraryType int
type Pointer *ArbitraryType
func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr

可以看到,包的構(gòu)成比較簡(jiǎn)單,下面我們主要結(jié)合源碼中注釋內(nèi)容來展開剖析和學(xué)習(xí)。

type ArbitraryType int

Arbitrary翻譯: 隨心所欲,任意的

type ArbitraryType int

ArbitraryType沒有什么實(shí)質(zhì)作用,它表示任意一種類型,實(shí)際上不是unsafe包的一部分。它表示任意Go表達(dá)式的類型。

type Pointer *ArbitraryType

type Pointer *ArbitraryType

Pointerunsafe包的核心。

靈活轉(zhuǎn)換

它表示指向任意類型的指針,有四種特殊操作可用于類型指針,而其他類型不可用,大概的轉(zhuǎn)換關(guān)系如下:

  • 任何類型的指針值都可以轉(zhuǎn)換為Pointer
  • Pointer可以轉(zhuǎn)換為任何類型的指針值
  • 任意uintptr可以轉(zhuǎn)換為Pointer
  • Pointer也可以轉(zhuǎn)換為任意uintptr

潛在的危險(xiǎn)性

正是因?yàn)樗心芰透鞣N數(shù)據(jù)類型之間建立聯(lián)系完成轉(zhuǎn)換,Pointer通常被認(rèn)為是較為危險(xiǎn)的,它能允許程序侵入系統(tǒng)并讀取和寫入任意內(nèi)存,使用時(shí)應(yīng)格外小心?。?!

源碼注釋中列舉了提到了一些正確錯(cuò)誤使用的例子。它還提到更為重要的一點(diǎn)是:不使用這些模式的代碼可能現(xiàn)在或者將來變成無效。即使下面的有效模式也有重要的警告。試圖來理解下這句話的核心就是,它不能對(duì)你提供什么保證!

對(duì)于編碼的正確性還可以通過運(yùn)行Golang提供的工具“go vet”可以幫助找到不符合這些模式的指針用法,但“go vet”并不能保證代碼一定一定是有效的。

go vetgolang中自帶的靜態(tài)分析工具,可以幫助檢測(cè)編寫代碼中一些隱含的錯(cuò)誤并給出提示。比如下面故意編寫一個(gè)帶有錯(cuò)誤的代碼,fmt.Printf%d需要填寫數(shù)值類型,為了驗(yàn)證go vet效果,故意填寫字符串類型看看靜態(tài)分析效果。

代碼樣例:
func TestErr(t *testing.T) {
  fmt.Printf("%d","hello world")
}
運(yùn)行:
`go vet unsafe/unsafe_test.go`
控制臺(tái)輸出提示: 
unsafe/unsafe_test.go:9:2: Printf format %d has arg "hello world" of wrong type string

? 正確的使用姿勢(shì)

以下涉及Pointer的模式是有效的,這里給出幾個(gè)例子:

  • (1) 指針 *T1 轉(zhuǎn)化為 指針 *T2. T1、T2兩個(gè)變量共享等值的內(nèi)存空間布局,在不超過數(shù)據(jù)范圍的前提下,可以允許將一種類型的數(shù)據(jù)重新轉(zhuǎn)換、解釋為其他類型的數(shù)據(jù)。

下面我們操作一個(gè)樣例:聲明并開辟一個(gè)內(nèi)存空間,然后基于該內(nèi)存空間進(jìn)行不同類型數(shù)據(jù)的轉(zhuǎn)換。

代碼如下:

// 步驟:
// (1) 聲明為一個(gè)int64類型
// (2) int64 -> float32
//(3) float32 -> int32
func TestPointerTypeConvert(t *testing.T) {
   //  (1) 聲明為一個(gè)int64類型
   int64Value := int64(20)
   // int64數(shù)據(jù)打印
   fmt.Println("int64類型的值:", int64Value)
   //打?。篿nt64類型的值: 20
   fmt.Println("int64類型的指針地址:", &int64Value)
   //打印:int64類型的指針地址: 0xc000128218
   // (2) int64 -> float32
   float32Ptr := (*float32)(unsafe.Pointer(&int64Value))
   fmt.Println("float32類型的值:", *(*float32)(unsafe.Pointer(&int64Value)))
   //打?。篺loat32類型的值: 2.8e-44
   fmt.Println("float32類型的指針地址:", (*float32)(unsafe.Pointer(&int64Value)))
   //打?。篺loat32類型的指針地址: 0xc000128218
   // (3) float32 -> int32
   fmt.Println("int32類型的指針:", (*int32)(unsafe.Pointer(float32Ptr)))
   //打?。篿nt32類型的指針: 0xc000128218
   fmt.Println("int32類型的值:", *(*int32)(unsafe.Pointer(float32Ptr)))
   //打?。篿nt32類型的值: 20
}

小結(jié) Pointer利用能夠和不同數(shù)據(jù)類型之間進(jìn)行轉(zhuǎn)換的靈活特性,可以有效進(jìn)行完成數(shù)據(jù)轉(zhuǎn)換、指針復(fù)制的功能

(2) Pointer 轉(zhuǎn)換為 uintptr(不包括返回的轉(zhuǎn)換)

  • 將指針轉(zhuǎn)換為uintptr將生成指向的值的內(nèi)存地址,該地址為整數(shù)。
  • 這種uintptr通常用于打印。將uintptr轉(zhuǎn)換回指針通常無效,uintptr是整數(shù),而不是引用。
  • 將指針轉(zhuǎn)換為uintptr將創(chuàng)建一個(gè)沒有指針語義的整數(shù)值。即使uintptr包含某個(gè)對(duì)象的地址,如果對(duì)象移動(dòng),垃圾收集器不會(huì)更新uintptr的值,uintptr也不會(huì)阻止對(duì)象被回收。
  • 其余模式枚舉從uintptr到指針的唯一有效轉(zhuǎn)換。

(3) Pointer 轉(zhuǎn)換為 uintptr(包含返回的轉(zhuǎn)換,使用算術(shù)) 如果變量p指向一個(gè)分配的對(duì)象,它可以通過該對(duì)象轉(zhuǎn)換為uintptr,添加偏移量,并轉(zhuǎn)換回指針。

// (1) 聲明一個(gè)數(shù)組,持有兩個(gè)元素
// (2) 輸出第1個(gè)元素指針信息
// (3) 輸出第2個(gè)元素指針信息
// (4) 通過第一個(gè)元素指針地址加上偏移量可以得到第二個(gè)元素地址
// (5) 還原第二個(gè)元素的值
func TestUintptrWithOffset(t *testing.T) {
  // (1) 聲明一個(gè)數(shù)組,持有兩個(gè)元素
  p := []int{1,2}
  // (2) 輸出第1個(gè)元素指針信息
  fmt.Println("p[0]的指針地址:",&p[0])
  // p[0]的指針地址 0xc0000a0160
  ptr0 := uintptr(unsafe.Pointer(&p[0]))
  fmt.Println(ptr0)
  // 824634376544
  // (3) 輸出第2個(gè)元素指針信息
  fmt.Println("p[1]的指針地址:",&p[1])
  // p[1]的指針地址 0xc0000a0168
  ptr1 := uintptr(unsafe.Pointer(&p[1]))
  fmt.Println(ptr1)
  // 824634376552
  // (4) 通過第一個(gè)元素指針地址加上偏移量可以得到第二個(gè)元素指針地址
  offset := uintptr(unsafe.Pointer(&p[0])) + 8 //int類型占8字節(jié)
  ptr1ByOffset := unsafe.Pointer(offset)
  fmt.Println("p[0]的指針地址 + offset偏移量可以得到p[1]的指針地址:",ptr1ByOffset)
  // p[0]的指針地址 + offset偏移量可以得到p[1]的指針地址 0xc0000a0168
  // (5) 還原第二個(gè)元素的值
  fmt.Println("通過偏移量得到的指針地址還原值:",*(*int)(ptr1ByOffset))
  // 通過偏移量得到的指針地址還原值:2
}

小結(jié)

最常見的用途是訪問結(jié)構(gòu)或數(shù)組元素中的字段:

  • 從指針添加、減去偏移量都是可操作的
  • 使用&^對(duì)指針進(jìn)行舍入也是有效的,通常用于對(duì)齊
  • 要保證內(nèi)存偏移量指向正確,指向有效的原始分配的對(duì)象的偏移量上

? 錯(cuò)誤的使用姿勢(shì)

與C中不同的是,將指針指向到其原始分配結(jié)束之后是無效的:

//? 無效:分配空間外的端點(diǎn)
func TestOverOffset(t *testing.T) {
   // 聲明字符串變量str
   str := "abc"
   // 在str的內(nèi)存偏移量基礎(chǔ)上增加了額外的一個(gè)偏移量得到一個(gè)新的內(nèi)存偏移量,該內(nèi)存地址是不存在的
   newStr := unsafe.Pointer(uintptr(unsafe.Pointer(&str)) + unsafe.Sizeof(str))
   // 這里由于不存在該內(nèi)存偏移量的對(duì)象,肯定求不到值,這里的表現(xiàn)是一直阻塞等待
   fmt.Println(*(*string)(newStr))
}

注意,兩個(gè)轉(zhuǎn)換必須出現(xiàn)在同一個(gè)表達(dá)式中,它們之間只有中間的算術(shù)運(yùn)算。

//? 無效:在轉(zhuǎn)換回指針之前,uintptr不能存儲(chǔ)在變量中
u := uintptr(p)
p = unsafe.Pointer(u + offset)
//推薦如下這種方式,不要依靠中間變量來傳遞uintptr
p = unsafe.Pointer(uintptr(p) + offset)

請(qǐng)注意,指針必須指向已分配的對(duì)象,因此它不能是零。

//? 無效:零指針的轉(zhuǎn)換
u := unsafe.Pointer(nil)
p := unsafe.Pointer(uintptr(u) + offset)
  • (4) 調(diào)用syscall.Syscall時(shí)將指針轉(zhuǎn)換為uintptr syscall包中的Syscall函數(shù)將其uintptr參數(shù)直接傳遞給操作系統(tǒng),然后操作系統(tǒng)可能會(huì)根據(jù)調(diào)用的詳細(xì)信息,將其中一些重新解釋為指針。也就是說,系統(tǒng)調(diào)用實(shí)現(xiàn)隱式地將某些參數(shù)從uintptr轉(zhuǎn)換回指針。

如果必須將指針參數(shù)轉(zhuǎn)換為uintptr以用作參數(shù),則該轉(zhuǎn)換必須出現(xiàn)在調(diào)用表達(dá)式本身之中:

syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n))

編譯器處理在程序集中實(shí)現(xiàn)的函數(shù)調(diào)用的參數(shù)列表中轉(zhuǎn)換為uintptr的指針,方法是安排保留引用的已分配對(duì)象(如果有),并在調(diào)用完成之前不移動(dòng),即使僅從類型來看,調(diào)用期間似乎不再需要該對(duì)象。

要使編譯器識(shí)別此模式,轉(zhuǎn)換必須出現(xiàn)在參數(shù)列表中:

//? 無效:在系統(tǒng)調(diào)用期間隱式轉(zhuǎn)換回指針之前,uintptr不能存儲(chǔ)在變量中,和上面提到的問題類似
u := uintptr(unsafe.Pointer(p))
syscall.Syscall(SYS_READ, uintptr(fd), u, uintptr(n))

(5) 從uintptrPointer,包含反射(Reflect)、反射值指針(Reflect.Value.Pointer)、反射值地址(Reflect.Value.UnsafeAddr)的轉(zhuǎn)換結(jié)果

reflect的值方法名為PointerUnsafeAddr,返回類型為uintptr,而不是unsafe。防止調(diào)用者在不首先導(dǎo)入“unsafe”的情況下將結(jié)果更改為任意類型的指針。然而,這意味著結(jié)果是脆弱的,必須在調(diào)用后立即在同一表達(dá)式中轉(zhuǎn)換為Pointer

p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer()))

與上述情況一樣,在轉(zhuǎn)換之前存儲(chǔ)結(jié)果是無效的

//? 無效:在轉(zhuǎn)換回指針之前,uintptr不能存儲(chǔ)在變量中,和上面提到的問題類似
u := reflect.ValueOf(new(int)).Pointer()
p := (*int)(unsafe.Pointer(u))

(6)reflect.SliceHeaderreflect.StringHeader的數(shù)據(jù)字段與Pointer的轉(zhuǎn)換 與前一種情況一樣,reflect.SliceHeaderreflect.StringHeader將字段數(shù)據(jù)聲明為uintptr,以防止調(diào)用方在不首先導(dǎo)入“unsafe”的情況下將結(jié)果更改為任意類型。

然而,這意味著SliceHeaderStringHeader僅在解釋實(shí)際切片(slice)或字符串值(string)的內(nèi)容時(shí)有效。

var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) // case 1
hdr.Data = uintptr(unsafe.Pointer(p))              // case 6 (this case)
hdr.Len = n

在此用法中,hdr.Data實(shí)際上是引用字符串頭中底層指針的另一種方式,而不是uintptr變量本身。

一般來說,reflect.SliceHeaderreflect.StringHeader應(yīng)該僅用作那些指向?qū)嶋H為切片(slice)、字符串(string)的*reflect.SliceHeader*reflect.StringHeader,而不是普通的結(jié)構(gòu)體。程序不應(yīng)聲明或分配這些結(jié)構(gòu)類型的變量。

// ? 無效: 直接聲明的Header不會(huì)將數(shù)據(jù)作為引用。
var hdr reflect.StringHeader
hdr.Data = uintptr(unsafe.Pointer(p))
hdr.Len = n
s := *(*string)(unsafe.Pointer(&hdr)) // p可能已經(jīng)被回收

func Sizeof(x ArbitraryType) uintptr

Sizeof返回類型v本身數(shù)據(jù)所占用的字節(jié)數(shù)。返回值是“頂層”的數(shù)據(jù)占有的字節(jié)數(shù)。例如,若v是一個(gè)切片,它會(huì)返回該切片描述符的大小,而非該切片底層引用的內(nèi)存的大小。

Go語言中非聚合類型通常有一個(gè)固定的大小
引用類型或包含引用類型的大小在32位平臺(tái)上是4字節(jié),在64位平臺(tái)上是8字節(jié)。

類型分類大小
bool非聚合1個(gè)字節(jié)
intN, uintN, floatN, complexN非聚合N/8個(gè)字節(jié)(例如float64是8個(gè)字節(jié))
int, uint, uintptr非聚合1個(gè)機(jī)器字 (32位系統(tǒng):1機(jī)器字=4字節(jié); 64位系統(tǒng):1機(jī)器字=8字節(jié))
*T聚合1個(gè)機(jī)器字
string聚合2個(gè)機(jī)器字(data,len)
[]T聚合3個(gè)機(jī)器字(data,len,cap)
map聚合1個(gè)機(jī)器字
func聚合1個(gè)機(jī)器字
chan聚合1個(gè)機(jī)器字
interface聚合2個(gè)機(jī)器字(type,value)
type Model struct {
   //Field...
}
func TestSizeOf(t *testing.T) {
   boolSize := false
   intSize := 1
   int8Size := int8(1)
   int16Size := int16(1)
   int32Size := int32(1)
   int64Size := int64(1)
   arrSize := make([]int, 0)
   mapSize := make(map[string]string, 0)
   structSize := &Model{}
   funcSize := func() {}
   chanSize := make(chan int, 10)
   stringSize := "abcdefg"
   fmt.Println("bool sizeOf:", unsafe.Sizeof(boolSize))
   //bool sizeOf: 1
   fmt.Println("int sizeOf:", unsafe.Sizeof(intSize))
   //int sizeOf: 8
   fmt.Println("int8 sizeOf:", unsafe.Sizeof(int8Size))
   //int8 sizeOf: 1
   fmt.Println("int16 sizeOf:", unsafe.Sizeof(int16Size))
   //int16 sizeOf: 2
   fmt.Println("int32 sizeOf:", unsafe.Sizeof(int32Size))
   //int32 sizeOf: 4
   fmt.Println("int64 sizeOf:", unsafe.Sizeof(int64Size))
   //int64 sizeOf: 8
   fmt.Println("arrSize sizeOf:", unsafe.Sizeof(arrSize))
   //arrSize sizeOf: 24
   fmt.Println("structSize sizeOf:", unsafe.Sizeof(structSize))
   //structSize sizeOf: 8
   fmt.Println("mapSize sizeOf:", unsafe.Sizeof(mapSize))
   //mapSize sizeOf: 8
   fmt.Println("funcSize sizeOf:", unsafe.Sizeof(funcSize))
   //funcSize sizeOf: 8
   fmt.Println("chanSize sizeOf:", unsafe.Sizeof(chanSize))
   //chanSize sizeOf: 8
   fmt.Println("stringSize sizeOf:", unsafe.Sizeof(stringSize))
   //stringSize sizeOf: 16
}

func Offsetof(x ArbitraryType) uintptr

Offsetof返回類型v所代表的結(jié)構(gòu)體字段f在結(jié)構(gòu)體中的偏移量,它必須為結(jié)構(gòu)體類型的字段的形式。換句話說,它返回該結(jié)構(gòu)起始處與該字段起始處之間的字節(jié)數(shù)。

內(nèi)存對(duì)齊 計(jì)算機(jī)在加載和保存數(shù)據(jù)時(shí),如果內(nèi)存地址合理地對(duì)齊的將會(huì)更有效率。由于地址對(duì)齊這個(gè)因素,一個(gè)聚合類型的大小至少是所有字段或元素大小的總和,或者更大因?yàn)榭赡艽嬖趦?nèi)存空洞。\

內(nèi)存空洞 編譯器自動(dòng)添加的沒有被使用的內(nèi)存空間,用于保證后面每個(gè)字段或元素的地址相對(duì)于結(jié)構(gòu)或數(shù)組的開始地址能夠合理地對(duì)齊

下面通過排列bool、string、int16類型字段的不同順序來演示下內(nèi)存對(duì)齊時(shí)填充的內(nèi)存空洞。

type BoolIntString struct {
   A bool
   B int16
   C string
}
type StringIntBool struct {
   A string
   B int16
   C bool
}
type IntStringBool struct {
   A int16
   B string
   C bool
}
type StringBoolInt struct {
   A string
   B bool
   C int16
}
func TestOffsetOf(t *testing.T) {
   bis := &BoolIntString{}
   isb := &IntStringBool{}
   sbi := &StringBoolInt{}
   sib := &StringIntBool{}
   fmt.Println(unsafe.Offsetof(bis.A)) // 0
   fmt.Println(unsafe.Offsetof(bis.B)) // 2
   fmt.Println(unsafe.Offsetof(bis.C)) // 8
   fmt.Println("")
   fmt.Println(unsafe.Offsetof(isb.A)) // 0
   fmt.Println(unsafe.Offsetof(isb.B)) // 8
   fmt.Println(unsafe.Offsetof(isb.C)) // 24
   fmt.Println("")
   fmt.Println(unsafe.Offsetof(sbi.A)) // 0
   fmt.Println(unsafe.Offsetof(sbi.B)) // 16
   fmt.Println(unsafe.Offsetof(sbi.C)) // 18
   fmt.Println("")
   fmt.Println(unsafe.Offsetof(sib.A)) // 0
   fmt.Println(unsafe.Offsetof(sib.B)) // 16
   fmt.Println(unsafe.Offsetof(sib.C)) // 18
}

以上是針對(duì)單個(gè)結(jié)構(gòu)體內(nèi)的內(nèi)存對(duì)齊的測(cè)試演示,當(dāng)多個(gè)結(jié)構(gòu)體組合在一起時(shí)還會(huì)產(chǎn)生內(nèi)存對(duì)齊,感興趣可以自行實(shí)踐并打印內(nèi)存偏移量來觀察組合后產(chǎn)生的內(nèi)存空洞。

func Alignof(x ArbitraryType) uintptr

Alignof返回類型v的對(duì)齊方式(即類型v在內(nèi)存中占用的字節(jié)數(shù));若是結(jié)構(gòu)體類型的字段的形式,它會(huì)返回字段f在該結(jié)構(gòu)體中的對(duì)齊方式。

type Fields struct {
   Bool    bool
   String  string
   Int     int
   Int8    int8
   Int16   int16
   Int32   int32
   Float32 float32
   Float64 float64
}
func TestAlignof(t *testing.T) {
   fields := &Fields{}
   fmt.Println(unsafe.Alignof(fields.Bool)) // 1
   fmt.Println(unsafe.Alignof(fields.String))// 8
   fmt.Println(unsafe.Alignof(fields.Int)) // 8
   fmt.Println(unsafe.Alignof(fields.Int8)) // 1
   fmt.Println(unsafe.Alignof(fields.Int16)) // 2
   fmt.Println(unsafe.Alignof(fields.Int32))  // 4
   fmt.Println(unsafe.Alignof(fields.Float32))  // 4
   fmt.Println(unsafe.Alignof(fields.Float64))  // 8
}

不同類型有著不同的內(nèi)存對(duì)齊方式,總體上都是以最小可容納單位進(jìn)行對(duì)齊的,這樣可以在兼顧以最小的內(nèi)存空間填充來換取內(nèi)存計(jì)算的高效性。

參考

Golang標(biāo)準(zhǔn)庫文檔

《Go語言圣經(jīng)》底層編程章節(jié)

以上就是Golang標(biāo)準(zhǔn)庫unsafe源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于Golang標(biāo)準(zhǔn)庫unsafe的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 談?wù)凣o語言的反射三定律

    談?wù)凣o語言的反射三定律

    本文中,我們將解釋Go語言中反射的運(yùn)作機(jī)制。每個(gè)編程語言的反射模型不大相同,很多語言索性就不支持反射(C、C++)。由于本文是介紹Go語言的,所以當(dāng)我們談到“反射”時(shí),默認(rèn)為是Go語言中的反射。
    2016-08-08
  • go語言VScode?see?'go?help?modules'?(exit?status?1)問題的解決過程

    go語言VScode?see?'go?help?modules'?(exit?statu

    最近上手學(xué)習(xí)go語言,準(zhǔn)備在VSCode上寫程序的時(shí)候卻發(fā)現(xiàn)出了一點(diǎn)問題,下面這篇文章主要給大家介紹了關(guān)于go語言VScode?see?'go?help?modules'(exit?status?1)問題的解決過程,需要的朋友可以參考下
    2022-07-07
  • Go?語言入門之net/url?包

    Go?語言入門之net/url?包

    這篇文章主要介紹了Go?語言入門之net/url?包,文章基于GO語言的相關(guān)資料展開?net/url?包的詳細(xì)內(nèi)容,具有一定的的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Go語言中常用的基礎(chǔ)方法總結(jié)

    Go語言中常用的基礎(chǔ)方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語言中常用的一些基礎(chǔ)方法,例如:使用正則表達(dá)式驗(yàn)證字符串、格式化字符串、時(shí)間的比較等等,需要的可以參考一下
    2022-09-09
  • Golang之casbin權(quán)限管理的實(shí)現(xiàn)

    Golang之casbin權(quán)限管理的實(shí)現(xiàn)

    這篇文章主要介紹了Golang之casbin權(quán)限管理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Go語言庫系列之flag的具體使用

    Go語言庫系列之flag的具體使用

    這篇文章主要介紹了Go語言庫系列之flag的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • GO語言的map類型實(shí)例詳解

    GO語言的map類型實(shí)例詳解

    這篇文章主要介紹了GO語言的map類型實(shí)例詳解,包括對(duì)map的創(chuàng)建,賦值,排序,刪除,等操作需要的朋友可以參考下
    2022-12-12
  • Golang中深拷貝與淺拷貝詳解

    Golang中深拷貝與淺拷貝詳解

    這篇文章主要為大家詳細(xì)介紹一下Golang深拷貝和淺拷貝,文中有詳細(xì)的代碼示例供大家參考,需要的可以參考一下
    2023-05-05
  • 詳解Go中g(shù)in框架如何實(shí)現(xiàn)帶顏色日志

    詳解Go中g(shù)in框架如何實(shí)現(xiàn)帶顏色日志

    當(dāng)我們?cè)诮K端上(比如Goland)運(yùn)行g(shù)in框架搭建的服務(wù)時(shí),會(huì)發(fā)現(xiàn)輸出的日志是可以帶顏色的,那這是如何實(shí)現(xiàn)的呢?本文就來和大家簡(jiǎn)單講講
    2023-04-04
  • 淺析Golang中的內(nèi)存逃逸

    淺析Golang中的內(nèi)存逃逸

    內(nèi)存逃逸分析是go的編譯器在編譯期間,根據(jù)變量的類型和作用域,確定變量是堆上還是棧上。本文將通過示例淺析一下Golang中的內(nèi)存逃逸,需要的可以了解一下
    2022-10-10

最新評(píng)論