關(guān)于golang?struct?中的?slice?無法原子賦值的問題
golang struct 中的 slice 無法原子賦值
有這樣一個(gè)結(jié)構(gòu)體:
type MySt struct{
Field []byte
}我在數(shù)組排序中想要交換值:
func Swap(arr []MySt, i,j int){
arr[i], arr[j] = arr[j], arr[i]
}我猜測(cè),就算其成員 Field 是引用類型,但是引用的指針也會(huì)交換,應(yīng)該是沒問題的。
實(shí)際測(cè)試這里復(fù)制錯(cuò)誤了。
于是我換個(gè)寫法:
func Swap(arr []MySt, i,j int){
arr[i].Field, arr[j].Field = arr[j].Field, arr[i].Field
}上面的代碼仍然是不行。
猜測(cè)是編譯期產(chǎn)生的代碼不是類似 memcpy() 這種,而是逐個(gè)成員去交換,交換到指針這里時(shí),無法做到原子的交換,從而出了問題。
改成下面的方法,終于對(duì)了:
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
}仍然無法理解我為社么錯(cuò)了,求指教。
golang struct注意事項(xiàng)
struct注意事項(xiàng):
1.字段聲明語法同變量,示例: 字段名 字段類型
2.字段的類型可以為:基本類型、數(shù)組或引用類型
3.在創(chuàng)建一個(gè)結(jié)構(gòu)體變量后,如果沒有給字段賦值,都對(duì)應(yīng)一個(gè)零值(默認(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ú)立,互不影響,一個(gè)結(jié)構(gòu)體變量字段的改變,不影響另外一個(gè)。因?yàn)榻Y(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)此時(shí)結(jié)果為:

5. 不能這樣寫:*p2.Name 會(huì)報(bào)錯(cuò),因?yàn)?的運(yùn)算符優(yōu)先級(jí)比*高,應(yīng)該:(*p2).Name
6. 結(jié)構(gòu)體中所有字段在內(nèi)存中是連續(xù)的
r1 := Rect{Point{1, 2}, Point{3, 4}}
fmt.Println(r1)
//r1有四個(gè)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有兩個(gè) *Point類型,這兩個(gè)*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í)需要有完全相同的字段(名字,個(gè)數(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 這樣會(huì)報(bào)錯(cuò),因?yàn)間olang認(rèn)為Stu是重新定義的結(jié)構(gòu)體
stu1 = Student(stu2)
fmt.Println(stu1, stu2)
} //輸出結(jié)果為:{ 0} { 0}9. struct的每個(gè)字段上,可以寫上一個(gè)tag,該tag可以通過反射機(jī)制獲取,常見的使用場(chǎng)景就是序列化和反序列化
type Monsters struct {
Name string `json:"name"` //`json:"name"`就是struct tag
Age int `json:"age"`
Skill string `json:"skill"`
}
func main() {
//1. 創(chuàng)建一個(gè)monster變量
monster := Monsters{"牛魔王", 500, "芭蕉扇"}
//2. 將monster變量序列化為 json格式字串
// json.Marshal函數(shù)中使用了反射
jsonMonster, err := json.Marshal(monster)
if err != nil {
fmt.Println("json 處理錯(cuò)誤", err)
}
//如果age, name, skill首字母是小寫,name返回空序列,所以必須要大寫
//但如果某些程序員或用戶不習(xí)慣大寫,非要小些,那么可以在struct定義的時(shí)候加上 `json:"name"`
//注意:式鍵盤左上角的``,不是引號(hào)''
fmt.Println("jsonMonster", jsonMonster)
fmt.Println("jsonMonster", string(jsonMonster))
}創(chuàng)建struct實(shí)例的四種方式
方式一:
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)
//因?yàn)閜3是一個(gè)指針,因此標(biāo)準(zhǔn)的給字段賦值
(*p3).Name = "smith"
//(*p3).Name = "smith" 也可以這樣寫 p3.Name = "smith"
//原因:go的設(shè)計(jì)者為了程序員使用方便,底層會(huì)對(duì)p3.Name = "smith"進(jìn)行處理
//會(huì)給 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{}
//因?yàn)閜erson是一個(gè)指針,因此標(biāo)準(zhǔn)的訪問字段的方法
//(*person).Name = "scott"
//go的設(shè)計(jì)者為了程序員使用方便,也可以person.Name = "scott"
//原因和上面一樣,底層會(huì)對(duì) person.Name = "scott"進(jìn)行處理,會(huì)加上(*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做了一個(gè)簡(jiǎn)化,也支持結(jié)構(gòu)體指針.字段名,比如:preson.Name = "tom "。更符合程序員使用的習(xí)慣,go編譯器底層對(duì)person.Name做了轉(zhuǎn)化(*person).Name
到此這篇關(guān)于為什么 golang struct 中的 slice 無法原子賦值的文章就介紹到這了,更多相關(guān)golang struct slice 無法原子賦值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang定時(shí)器的2種實(shí)現(xiàn)方法與區(qū)別
這篇文章主要給大家介紹了關(guān)于Golang定時(shí)器的2種實(shí)現(xiàn)方法與區(qū)別的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Golang實(shí)現(xiàn)根據(jù)某個(gè)特定字段對(duì)結(jié)構(gòu)體的順序進(jìn)行排序
這篇文章主要為大家詳細(xì)介紹了Golang如何實(shí)現(xiàn)根據(jù)某個(gè)特定字段對(duì)結(jié)構(gòu)體的順序進(jìn)行排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
Go語言中的goroutine和channel如何協(xié)同工作
在Go語言中,goroutine和channel是并發(fā)編程的兩個(gè)核心概念,它們協(xié)同工作以實(shí)現(xiàn)高效、安全的并發(fā)執(zhí)行,本文將詳細(xì)探討goroutine和channel如何協(xié)同工作,以及它們?cè)诓l(fā)編程中的作用和優(yōu)勢(shì),需要的朋友可以參考下2024-04-04
go打包aar及flutter調(diào)用aar流程詳解
這篇文章主要為大家介紹了go打包aar及flutter調(diào)用aar流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

