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

PHP轉(zhuǎn)Go之?dāng)?shù)組的正確使用詳解

 更新時間:2023年09月17日 11:38:06   作者:全Neng攻城獅  
這篇文章主要為大家對比一下PHP中的Array和Golang中的 Array&Slice&Map,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

本文概要

思維速轉(zhuǎn),PHP Array -> Go Array or Slice or Map

底層實現(xiàn)的異同

使用中的注意事項及坑坑

  • 如何選擇 Array 和 Slice
  • 值傳遞和引用傳遞的坑
  • Map 的無序
  • 并發(fā)安全性

一、思維速轉(zhuǎn)

PHP 中 Array 實在是太好用了,即可以聲明為索引數(shù)組,又可以聲明為關(guān)聯(lián)數(shù)組;但是在 Golang 中,被拆解成了多個數(shù)據(jù)類型,其中索引數(shù)組與 Array/Slice 更貼近,而關(guān)聯(lián)數(shù)組更貼近于 Map

// 索引數(shù)組
$colors = array("red", "green", "blue");  
// Go Array: [3]string{"red", "green", "blue"} // 固定長度
// Go Slice: []string{"red", "green", "blue"}
// 關(guān)聯(lián)數(shù)組
$person = array(
    "first_name" => "John",
    "last_name" => "Doe",
    "age" => 30
);
// 對比 Golang Map
person := map[string]string{
    "first_name": "John",
    "last_name": "Doe",
    "age": "30",   // 特別注意強類型下 map 中值部分無法存放不同類型的數(shù)據(jù)
}

二、底層實現(xiàn)的異同

PHP 的語法上屏蔽了索引數(shù)組和關(guān)聯(lián)數(shù)組,底層實現(xiàn)均基于 HashTable 完成,但是對于 Golang 來說,不同的類型實現(xiàn)是略有差異的;

Array 底層實現(xiàn)

Go 的 Array 一定是預(yù)先確定長度的,故底層分配的是固定連續(xù)內(nèi)存,變量在聲明后,直接指向數(shù)組存儲的內(nèi)存地址,所以讀取會非常高效

arr := [3]int32{1,2,3}
fmt.Println(&arr[0],&arr[1],&arr[2])
// Output: 可以看到每個元素偏移剛好是 4 個字節(jié)
0xc0000a6030 0xc0000a6034 0xc0000a6038

特別注意,對于[3]string 字符串?dāng)?shù)組來說,string 實際上是存放在獨立的內(nèi)存中的,所以數(shù)組中保存的是字符串地址,所以打印出來的地址偏移是 16 個字節(jié)(string 底層數(shù)據(jù)結(jié)構(gòu)包括一個指向字符串真實地址的指針,以及一個字符串長度的值)

注意,所有這些字節(jié)偏移均是 64 位機器上

Slice 底層實現(xiàn)

Slice 實際上底層也是引用了數(shù)組的實現(xiàn),但是它在數(shù)組的上面又封裝了一層數(shù)據(jù)結(jié)構(gòu),當(dāng)我們打印 Slice 中每個元素的內(nèi)存地址時你會發(fā)現(xiàn)其每個元素的偏移規(guī)則與數(shù)組是一致的。差別在于當(dāng)我們打印整個數(shù)組的指針地址時會發(fā)現(xiàn)其與數(shù)組第一個元素的地址是一致的,而 Slice 的不同。

type slice struct {
    array unsafe.Pointer  // 指向底層數(shù)組
    len   int
    cap   int
}
arr := [3]int64{1,2,3}
fmt.Printf("arr : %p \n", &arr)
fmt.Println(&arr,&arr[0],&arr[1],&arr[2])
slice := []int64{1,2,3}
fmt.Printf("slice : %p \n", &slice)
fmt.Println(&slice,&slice[0],&slice[1],&slice[2])
// Output:
arr : 0xc000018120 // 與第一個元素一致
&[1 2 3] 0xc000018120 0xc000018128 0xc000018130
slice : 0xc000010078 // 指向 Slice 結(jié)構(gòu)體指針,故與第一個元素內(nèi)存不一致
&[1 2 3] 0xc000018150 0xc000018158 0xc000018160

Slice 實際上實現(xiàn)了高效的動態(tài)擴容能力,故對比 Array 來說應(yīng)用場景更廣泛

Map 底層實現(xiàn)

Golang 的 Map 底層實現(xiàn)也同樣是 HashTable ,相同點是,查找插入效率高,支持動態(tài)擴容等,但是 Golang 下的 Map 在遍歷時是無序的,php 下的關(guān)聯(lián)數(shù)組則是有序的;

關(guān)于 Golang 中 Array,Slice,Map 更詳細(xì)的底層實現(xiàn)有大量文章分析,這里不再贅述

使用中的注意事項及坑坑

Array 和 Slice 的選擇

Array 在某些場景下的確是使用起來會更高效,所以原則上在某些特別注意性能,且的確是不需要數(shù)據(jù)長度變動的情況下可以選擇 Array,但是,我要特別說明,這種場景極少極少,在日常業(yè)務(wù)系統(tǒng)開發(fā)中,無腦選擇使用 Slice 通常是正確的選擇

值傳遞和引用傳遞

Array 是值傳遞,Slice 和 Map 是引用傳遞,換句話說,Array 將數(shù)據(jù)傳遞到子函數(shù)后在子函數(shù)做任何修改,不會影響父函數(shù)內(nèi)原始數(shù)據(jù),但是 Slice 和 Map 不一樣,子函數(shù)對數(shù)據(jù)的修改會修改原始數(shù)據(jù),所以在上面無腦選擇 Slice 時要特別注意這一項,是否擔(dān)心子函數(shù)意外修改數(shù)據(jù)

Map 的無序的坑

這個從 PHP 轉(zhuǎn)到 Go 可能無法注意到的一點,每次循環(huán) Map 居然可能會得到完全不一樣的順序的結(jié)果,所以要想保證 Map 順序通常需要配合 slice 完成,或者借助第三方庫,比如:https://github.com/iancoleman/orderedmaphttps://github.com/wangjia184/sortedset 但實際上這種可能也會帶來 json 序列化的坑,所以從接口設(shè)計上就應(yīng)盡可能避免,對有序要求的盡可能使用 Slice

并發(fā)安全性

Go 是一個語言級別就支持并發(fā)的語言,但是 Slice 和 Map 都是并發(fā)不安全的類型,所以在并發(fā)操作 Slice 和 Map 時可能會引起沖突,故要特別注意,修改數(shù)據(jù)時需要引入 sync.Mutex 互斥鎖 or 利用 channel 完成,Map 還提供了一個并發(fā)安全的類型 sync.Map 來解決這個問題。

強類型下 Golang Array靈活性降低

接受它!

當(dāng)你接觸了 Golang 下數(shù)組們的實現(xiàn),會發(fā)現(xiàn)它真的沒有 php 下的數(shù)組靈活好用,這其實是強類型語言的通病,雖然 Golang 也可以通過定義 []interface{} 類型的 Slice,但是強烈不建議這樣用,強類型的優(yōu)點是讓我們盡可能早的發(fā)現(xiàn)問題,比如在編碼時 IDE 就能做到提示,而非在運行

到此這篇關(guān)于PHP轉(zhuǎn)Go之?dāng)?shù)組的正確使用詳解的文章就介紹到這了,更多相關(guān)PHP轉(zhuǎn)Go內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

浦东新区| 兴义市| 陕西省| 荆门市| 南部县| 泾阳县| 那曲县| 布尔津县| 通城县| 广水市| 老河口市| 股票| 建水县| 濮阳县| 临湘市| 壶关县| 靖边县| 岳西县| 鄄城县| 浏阳市| 三门县| 盖州市| 美姑县| 灵川县| 吉林市| 八宿县| 安庆市| 临沧市| 丹江口市| 怀宁县| 农安县| 丰镇市| 深州市| 偏关县| 奉贤区| 昌黎县| 临泉县| 松溪县| 项城市| 百色市| 新巴尔虎右旗|