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

關(guān)于golang?struct?中的?slice?無法原子賦值的問題

 更新時間:2024年01月20日 09:13:17   作者:ahfuzhang  
這篇文章主要介紹了為什么?golang?struct?中的?slice?無法原子賦值的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

golang struct 中的 slice 無法原子賦值

有這樣一個結(jié)構(gòu)體:

type MySt struct{
    Field []byte
}

我在數(shù)組排序中想要交換值:

func Swap(arr []MySt, i,j int){
    arr[i], arr[j] = arr[j], arr[i]
}

我猜測,就算其成員 Field 是引用類型,但是引用的指針也會交換,應(yīng)該是沒問題的。
實際測試這里復(fù)制錯誤了。

于是我換個寫法:

func Swap(arr []MySt, i,j int){
    arr[i].Field, arr[j].Field = arr[j].Field, arr[i].Field
}

上面的代碼仍然是不行。
猜測是編譯期產(chǎn)生的代碼不是類似 memcpy() 這種,而是逐個成員去交換,交換到指針這里時,無法做到原子的交換,從而出了問題。

改成下面的方法,終于對了:

func Swap(arr []MySt, i,j int){
    arr[i].Field, arr[j].Field = swapSlice(arr[j].Field, arr[i].Field)
}
func swapSlice(a, b []byte) ([]byte, []byte) {
	return b, a
}

仍然無法理解我為社么錯了,求指教。

golang struct注意事項

 struct注意事項:

1.字段聲明語法同變量,示例: 字段名  字段類型

2.字段的類型可以為:基本類型、數(shù)組或引用類型

3.在創(chuàng)建一個結(jié)構(gòu)體變量后,如果沒有給字段賦值,都對應(yīng)一個零值(默認(rèn)值),布爾類型是false,數(shù)值是0,字符串是""。                                                                                                                 

數(shù)組類型的默認(rèn)值和它的元素類型相關(guān),比如score[3]int 則為[0,0,0]                                     

指針,slice,和map的零值都為nil,即還沒有分配空間

type Person struct {
	Name  string
	Age   int
	Score [5]float64
	ptr   *int
	slice []int
	map1  map[string]string
}
func main() {
	var p1 Person
	fmt.Println(p1)
    fmt.Println()
	if p1.ptr == nil {
		fmt.Println("ok1")
	}
	if p1.slice == nil {
		fmt.Println("ok2")
	}
	if p1.map1 == nil {
		fmt.Println("ok3")
	}
	//使用 slice 一定要先make
	p1.slice = make([]int, 10)
	p1.slice[0] = 100
	p1.map1 = make(map[string]string)
	p1.map1["key1"] = "tom"
	fmt.Println(p1)
}

 結(jié)果為:

4.不同結(jié)構(gòu)體變量的字段是獨(dú)立,互不影響,一個結(jié)構(gòu)體變量字段的改變,不影響另外一個。因為結(jié)構(gòu)體是值類型,不是引用類型。

type Monster struct {
	Name string
	Age  int
}
func main() {
	var monster1 Monster
	monster1.Name = "牛博文"
	monster1.Age = 500
	monster2 := monster1
	monster2.Name = "蕪湖"
	fmt.Println("monster1 = ", monster1)
	fmt.Println("monster2 = ", monster2)
}

 結(jié)果:

monster2的改變并沒有影響monster1。但如果想要monster2的改變影響monster1,那么應(yīng)該把monster2變?yōu)橹羔槪?/p>

monster2 := &monster1
	monster2.Name = "蕪湖"
	fmt.Println("monster1 = ", monster1)
	fmt.Println("monster2 = ", *monster2)

 此時結(jié)果為:

5. 不能這樣寫:*p2.Name  會報錯,因為.的運(yùn)算符優(yōu)先級比*高,應(yīng)該:(*p2).Name

6. 結(jié)構(gòu)體中所有字段在內(nèi)存中是連續(xù)的 

r1 := Rect{Point{1, 2}, Point{3, 4}}
	fmt.Println(r1)
	//r1有四個int,在內(nèi)存中是連續(xù)分布的
	//打印地址
	fmt.Printf("r1.leftUp.x的地址是 %p\n", &r1.leftUp.x)
	fmt.Printf("r1.leftUp.y的地址是 %p\n", &r1.leftUp.y)
	fmt.Printf("r1.righttUp.x的地址是 %p\n", &r1.rightUp.x)
	fmt.Printf("r1.rightUp.y的地址是 %p\n", &r1.rightUp.y)
	fmt.Println()
	//r2有兩個 *Point類型,這兩個*Point類型的本身地址是連續(xù)的,但是他們指向的地址不一定是連續(xù)的
	r2 := Rect2{&Point{10, 20}, &Point{30, 40}}
	//打印地址
	fmt.Printf("r2.leftUp 本身的地址是%p\n", &r2.leftUp)
	fmt.Printf("r2.rightUp 本身的地址是%p\n", &r2.rightUp)
	fmt.Printf("r2.leftUp 指向的地址是%p\n", r2.leftUp) 
	fmt.Printf("r2.rightUp 指向的地址是%p\n", r2.rightUp)
	fmt.Printf("r2.leftUp.x的地址是 %p\n", &r2.leftUp.x)
	fmt.Printf("r2.leftUp.y的地址是 %p\n", &r2.leftUp.y)
	fmt.Printf("r2.righttUp.x的地址是 %p\n", &r2.rightUp.x)
	fmt.Printf("r2.rightUp.y的地址是 %p\n", &r2.rightUp.y)

7. 結(jié)構(gòu)體是用戶單獨(dú)定義的類型,和其他類型進(jìn)行轉(zhuǎn)換時需要有完全相同的字段(名字,個數(shù),類) 

type A struct {
	num int
	str string
}
type B struct {
	num int
	str string
}
func main() {
	var a A
	var b B
	a = A(b)
	fmt.Println(a, b)
}     //輸出結(jié)果為 {0 } {0 }

 8. 結(jié)構(gòu)體進(jìn)行type重新定義(相當(dāng)于取別名), Golang認(rèn)為是新的數(shù)據(jù)類型,但是相互之間可以強(qiáng)轉(zhuǎn)

type Student struct {
	Name string
	Age  int
}
type Stu Student
func main() {
	var stu1 Student
	var stu2 Stu
	// stu2 = stu1    這樣會報錯,因為golang認(rèn)為Stu是重新定義的結(jié)構(gòu)體
	stu1 = Student(stu2)
	fmt.Println(stu1, stu2)
}    //輸出結(jié)果為:{ 0} { 0}

9. struct的每個字段上,可以寫上一個tag,該tag可以通過反射機(jī)制獲取,常見的使用場景就是序列化和反序列化 

type Monsters struct {
	Name  string `json:"name"`   //`json:"name"`就是struct tag
	Age   int    `json:"age"`
	Skill string `json:"skill"`
}
func main() {
	//1. 創(chuàng)建一個monster變量
	monster := Monsters{"牛魔王", 500, "芭蕉扇"}
	//2. 將monster變量序列化為 json格式字串
    //  json.Marshal函數(shù)中使用了反射
	jsonMonster, err := json.Marshal(monster)
	if err != nil {
		fmt.Println("json 處理錯誤", err)
	}
	//如果age, name, skill首字母是小寫,name返回空序列,所以必須要大寫
	//但如果某些程序員或用戶不習(xí)慣大寫,非要小些,那么可以在struct定義的時候加上 `json:"name"`
	//注意:式鍵盤左上角的``,不是引號''
	fmt.Println("jsonMonster", jsonMonster)
	fmt.Println("jsonMonster", string(jsonMonster))
}

 創(chuàng)建struct實例的四種方式

 方式一:

type Person struct {
	Name string
	Age  int
}
func main() {
	p1 := Person{}
	p1.Name = "tom"
	p1.Age = 18
	fmt.Println(p1)     //{tom 18}
}

 方式二:

p2 := Person{"marry", 18}
	fmt.Println(p2)    //{marry 18}

 方式3:

// var person *person = new (Person)
	var p3 *Person = new(Person)
	//因為p3是一個指針,因此標(biāo)準(zhǔn)的給字段賦值
	(*p3).Name = "smith"
	//(*p3).Name = "smith" 也可以這樣寫 p3.Name = "smith"
	//原因:go的設(shè)計者為了程序員使用方便,底層會對p3.Name = "smith"進(jìn)行處理
	//會給 p3 加上取值運(yùn)算(*p3).Name = "smith"
	p3.Name = "amy"
	(*p3).Age = 30
	fmt.Println(*p3)   //{amy 30}

方式4:

// var person *Person = &person{}
	var person *Person = &Person{}
	//因為person是一個指針,因此標(biāo)準(zhǔn)的訪問字段的方法
	//(*person).Name = "scott"
	//go的設(shè)計者為了程序員使用方便,也可以person.Name = "scott"
	//原因和上面一樣,底層會對 person.Name = "scott"進(jìn)行處理,會加上(*person)
	(*person).Name = "scott"
	person.Name = "scott~~"
	(*person).Age = 88
	person.Age = 10
	fmt.Println(*person)

第3種和第4種方式返回的是 結(jié)構(gòu)體指針

結(jié)構(gòu)體指針訪問字段的標(biāo)準(zhǔn)方式應(yīng)該是:(*結(jié)構(gòu)體指針)字段名,比如:(*person).Name = "tom"

但go做了一個簡化,也支持結(jié)構(gòu)體指針.字段名,比如:preson.Name = "tom "。更符合程序員使用的習(xí)慣,go編譯器底層對person.Name做了轉(zhuǎn)化(*person).Name

到此這篇關(guān)于為什么 golang struct 中的 slice 無法原子賦值的文章就介紹到這了,更多相關(guān)golang struct  slice 無法原子賦值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang定時器的2種實現(xiàn)方法與區(qū)別

    Golang定時器的2種實現(xiàn)方法與區(qū)別

    這篇文章主要給大家介紹了關(guān)于Golang定時器的2種實現(xiàn)方法與區(qū)別的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • golang croncli 定時器命令詳解

    golang croncli 定時器命令詳解

    定時器是執(zhí)行任務(wù)時的常用功能,配置系統(tǒng)的定時任務(wù)太麻煩,所以就想用golang簡單實現(xiàn)一個定時器命令,包括定時器命令格式、定時執(zhí)行命令的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • 淺談JWT在GO中的使用方法及原理

    淺談JWT在GO中的使用方法及原理

    JWT是一種基于?JSON?的開放標(biāo)準(zhǔn),用于在網(wǎng)絡(luò)應(yīng)用間傳遞聲明,JWT被設(shè)計為可安全地將用戶身份驗證和授權(quán)數(shù)據(jù)作為?JSON?對象在各個應(yīng)用程序之間傳遞,本文將詳細(xì)給大家介紹JWT原理及在Go中的用法,需要的朋友可以參考下
    2023-05-05
  • Golang實現(xiàn)根據(jù)某個特定字段對結(jié)構(gòu)體的順序進(jìn)行排序

    Golang實現(xiàn)根據(jù)某個特定字段對結(jié)構(gòu)體的順序進(jìn)行排序

    這篇文章主要為大家詳細(xì)介紹了Golang如何實現(xiàn)根據(jù)某個特定字段對結(jié)構(gòu)體的順序進(jìn)行排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • golang 切片截取參數(shù)方法詳解

    golang 切片截取參數(shù)方法詳解

    這篇文章主要介紹了golang 切片截取參數(shù)方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Go語言中的goroutine和channel如何協(xié)同工作

    Go語言中的goroutine和channel如何協(xié)同工作

    在Go語言中,goroutine和channel是并發(fā)編程的兩個核心概念,它們協(xié)同工作以實現(xiàn)高效、安全的并發(fā)執(zhí)行,本文將詳細(xì)探討goroutine和channel如何協(xié)同工作,以及它們在并發(fā)編程中的作用和優(yōu)勢,需要的朋友可以參考下
    2024-04-04
  • go打包aar及flutter調(diào)用aar流程詳解

    go打包aar及flutter調(diào)用aar流程詳解

    這篇文章主要為大家介紹了go打包aar及flutter調(diào)用aar流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • go語言time.After()的作用

    go語言time.After()的作用

    time.After 是 Go 語言中的一個函數(shù),用于返回一個定時器通道,該通道在指定時間后發(fā)送當(dāng)前時間,這個功能常用于超時控制和延遲執(zhí)行,本文就來詳細(xì)的介紹一下,感興趣的可以了解學(xué)習(xí)
    2024-10-10
  • RoaringBitmap原理及在Go中的使用詳解

    RoaringBitmap原理及在Go中的使用詳解

    這篇文章主要為大家介紹了RoaringBitmap原理及在Go中的使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • 一文了解Go語言io.Copy函數(shù)

    一文了解Go語言io.Copy函數(shù)

    這篇文章主要為大家介紹了Go語言io.Copy函數(shù)使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07

最新評論