国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

淺析Go語言中的Range關(guān)鍵字

2020-04-01 19:08:27
字體:
供稿:網(wǎng)友

前言

相信用過Range的朋友們都知道,Go語言中的range關(guān)鍵字使用起來非常的方便,它允許你遍歷某個(gè)slice或者map,并通過兩個(gè)參數(shù)(indexvalue),分別獲取到slice或者map中某個(gè)元素所在的index以及其值。

比如像這樣的用法:

for index, value := range mySlice { fmt.Println("index: " + index) fmt.Println("value: " + value)}

上面的例子足夠清晰的描述了range的用法,實(shí)際上在使用range關(guān)鍵字的時(shí)候,還有一些需要特別注意的地方,有一些新手很容易入的”坑”。

為了說明這些”坑”,我們可以從下面這個(gè)稍復(fù)雜的例子說起:

type Foo struct { bar string}func main() { list := []Foo{ {"A"}, {"B"}, {"C"}, } list2 := make([]*Foo, len(list)) for i, value := range list { list2[i] = &value } fmt.Println(list[0], list[1], list[2]) fmt.Println(list2[0], list2[1], list2[2])}

在這個(gè)例子中,我們干了下面的一些事情:

     1、定義了一個(gè)叫做Foo的結(jié)構(gòu),里面有一個(gè)叫bar的field。隨后,我們創(chuàng)建了一個(gè)基于Foo結(jié)構(gòu)體的slice,名字叫l(wèi)ist

     2、我們還創(chuàng)建了一個(gè)基于Foo結(jié)構(gòu)體指針類型的slice,叫做list2

     3、在一個(gè)for循環(huán)中,我們試圖遍歷list中的每一個(gè)元素,獲取其指針地址,并賦值到list2中index與之對應(yīng)的位置。

     4、最后,分別輸出list與list2中的每個(gè)元素

從代碼來看,理所當(dāng)然,我們期望得到的結(jié)果應(yīng)該是這樣:

{A} {B} {C}&{A} &{B} &{C}

但是結(jié)果卻出乎意料,程序的輸出是這樣的:

{A} {B} {C}&{C} &{C} &{C}

從結(jié)果來看,仿佛list2中的三個(gè)元素,都指向了list中的最后一個(gè)元素。這是為什么呢?問題就出在上面那一段for…range循環(huán)中。

在Go的for…range循環(huán)中,Go始終使用值拷貝的方式代替被遍歷的元素本身,簡單來說,就是for…range中那個(gè)value,是一個(gè)值拷貝,而不是元素本身。這樣一來,當(dāng)我們期望用&獲取元素的指針地址時(shí),實(shí)際上只是取到了value這個(gè)臨時(shí)變量的指針地址,而非list中真正被遍歷到的某個(gè)元素的指針地址。而在整個(gè)for…range循環(huán)中,value這個(gè)臨時(shí)變量會被重復(fù)使用,所以,在上面的例子中,list2被填充了三個(gè)相同的指針地址,并且這三個(gè)地址都指向value,而在最后一次循環(huán)中,value被賦與了{c}的指針地址。因此,list2輸出的時(shí)候顯示出了三個(gè)&{c}

同樣的,下面的寫法,跟for…range的例子如出一轍:

var value Foofor var i := 0; i < len(list); i++ { value = list[i] list2[i] = &value}

如果我們輸出list2的三個(gè)元素,結(jié)果同樣是: &{C} &{C} &{C}

那么,怎樣才是正確的寫法呢?我們應(yīng)該用index來訪問for…range中真實(shí)的元素,并獲取其指針地址:

for i, _ := range list { list2[i] = &list[i]}

這樣,輸出list2中的元素,就能得到我們想要的結(jié)果(&{A} &{B} &{C})了。

實(shí)驗(yàn)代碼如下:

package mainimport "fmt"type Foo struct { bar string}func main() { list := []Foo{ {"A"}, {"B"}, {"C"}, } list2 := make([]*Foo, len(list)) //錯(cuò)誤的例子 for i, value := range list { list2[i] = &value } //正確的例子 //for i, _ := range list { // list2[i] = &list[i] //} fmt.Println(list[0], list[1], list[2]) fmt.Println(list2[0], list2[1], list2[2])}

了解了range的正確使用姿勢,那么我們下面這個(gè)例子也能迎刃而解了:

package mainimport "fmt"type MyType struct { field string}func main() { var array [10]MyType for _, e := range array { e.field = "foo" } for _, e := range array { fmt.Println(e.field) fmt.Println("--") }}

平常寫代碼最常見的場景,就是我們需要在一個(gè)循環(huán)中修改被遍歷元素的值。比如上面這個(gè)例子,我們希望能使用for…range循環(huán),一次性將array中每個(gè)元素的field設(shè)置為”foo”。同樣,因?yàn)閞ange值拷貝的緣故,上面的程序什么都不會輸出……

而正確的做法是:

for i, _ := range array { array[i].field = "foo"}

通過index訪問每個(gè)元素,并修改其field,這樣,就能輸出一堆”foo”了……

實(shí)驗(yàn)代碼如下:

package mainimport "fmt"type MyType struct { field string}func main() { var array [10]MyType for i, _ := range array { array[i].field = "foo" } for _, e := range array { fmt.Println(e.field) }}

總結(jié)

以上就是關(guān)于Go語言中Range關(guān)鍵字的全部內(nèi)容,這篇文章介紹的還是很詳細(xì)的,相信本文會對大家學(xué)習(xí)Go語言具有一定的參考價(jià)值,如果有疑問大家可以留言交流,小編會盡快給大家回復(fù)的,也請大家繼續(xù)支持VEVB武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 拉萨市| 双江| 永嘉县| 陇南市| 突泉县| 达拉特旗| 明水县| 山东| 左贡县| 凭祥市| 奇台县| 兴业县| 玉田县| 南充市| 宾川县| 卢龙县| 新乐市| 定安县| 民乐县| 晋中市| 达州市| 乌拉特前旗| 华宁县| 铜山县| 松江区| 平武县| 景宁| 治多县| 上蔡县| 扶绥县| 古浪县| 彭州市| 兰考县| 锡林郭勒盟| 木里| 唐海县| 聂荣县| 襄垣县| 新竹市| 云梦县| 广南县|