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

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

 更新時間:2016年09月11日 10:30:52   投稿:daisy  
Range是go語言中很獨特的一個關(guān)鍵詞,也相當(dāng)好用。下面就跟著小編來再聊聊這個Range關(guān)鍵字,有需要的朋友們可以參考借鑒。

前言

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

比如像這樣的用法:

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

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

為了說明這些”坑”,我們可以從下面這個稍復(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])
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

實驗代碼如下:

package main

import "fmt"

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
 }

 //正確的例子
 //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的正確使用姿勢,那么我們下面這個例子也能迎刃而解了:

package main
import "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("--")
 }
}

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

而正確的做法是:

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

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

實驗代碼如下:

package main

import "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語言具有一定的參考價值,如果有疑問大家可以留言交流,小編會盡快給大家回復(fù)的,也請大家繼續(xù)支持腳本之家。

相關(guān)文章

  • 一文教你如何快速學(xué)會Go的struct數(shù)據(jù)類型

    一文教你如何快速學(xué)會Go的struct數(shù)據(jù)類型

    結(jié)構(gòu)是表示字段集合的用戶定義類型。它可以用于將數(shù)據(jù)分組為單個單元而不是將每個數(shù)據(jù)作為單獨的值的地方。本文就來和大家聊聊Go中struct數(shù)據(jù)類型的使用,需要的可以參考一下
    2023-03-03
  • Go語言單元測試的實現(xiàn)及用例

    Go語言單元測試的實現(xiàn)及用例

    在日常開發(fā)中,我們通常需要針對現(xiàn)有的功能進(jìn)行單元測試,以驗證開發(fā)的正確性,本文主要介紹了Go語言單元測試的實現(xiàn)及用例,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • golang中結(jié)構(gòu)體嵌套接口的實現(xiàn)

    golang中結(jié)構(gòu)體嵌套接口的實現(xiàn)

    本文主要介紹了golang中結(jié)構(gòu)體嵌套接口的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 最新評論