范围引用而不是数值引用

huangapple go评论90阅读模式
英文:

Range references instead values

问题

我看到range返回键和值的“副本”。有没有办法让range返回项目的地址呢?例如:

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]*MyType

    for _, e := range array {
        e = &MyType{field: "foo"}
    }

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

在这个例子中,"field"没有被修改,因为range发送的是field的副本。我是否必须使用索引,还是有其他方法可以修改值?

英文:

I saw that range returns the key and the "copy" of the value. Is there a way for that range to return the address of the item? Example

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

http://play.golang.org/p/AFOGG9NGpx

Here "field" is not modified because range sends the copy of field.
Do I have to use index or is there any other way to modify the value?

答案1

得分: 192

简短而直接的答案是:不要使用值,而是使用数组索引

所以上述代码变为:

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

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

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}
英文:

The short & direct answer: no, use the array index instead of the value

So the above code becomes:

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

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

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

答案2

得分: 11

@Dave C@Sam Toliman的评论合并起来

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

    for idx := range array {
        e := &array[idx]
        e.field = "foo"
    }

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

https://play.golang.org/p/knKfziB1nce

英文:

To combine @Dave C and @Sam Toliman's comments

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

    for idx := range array {
        e := &array[idx]
        e.field = "foo"
    }

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

https://play.golang.org/p/knKfziB1nce

答案3

得分: 9

Go的range只支持按值赋值。没有&range,因为它解决的问题太简单了。

可以通过以下方式实现所需的效果:

for i := range array {
    e := &array[i]
    e.field = "foo"
}
英文:

Go's range only supports assignment by value. There is no &range because the problem it solves is too trivial.

The desired effect can be achieved as follows:

for i := range array {
    e := &array[i]
    e.field = "foo"
}

答案4

得分: 2

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

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

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}
package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

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

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

这是一个Go语言的代码示例,它定义了一个名为MyType的结构体,其中包含一个名为field的字符串字段。在main函数中,创建了一个长度为10的array数组,然后使用循环为每个元素的field字段赋值为"foo"。最后,使用循环打印出每个元素的field字段的值,并在每个值之后打印"--"。

英文:
package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    var array [10]MyType

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

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

答案5

得分: 1

如果您想访问v的引用值(例如for i, v := range arr)以更新数组中对象的值,有三种有希望(相对简单)的解决方法:

  1. 如第一个答案所建议的,从数组内部更新arr[i]而不是v(例如arr[i] = "Hello")。

  2. 仅当您的数组包含一组需要更新但不替换的结构体时,在数组内将v设置为arr[i],然后通过v更新属性(例如v := arr[i]; v.thingSheSays = "Hello")。

  3. 或者,我最喜欢的方法是定义一个包含对象地址的数组。然后在for循环内使用指针访问对象。可以这样做:

输入:

a, b, c := "A", "B", "C"
arr := []*string{&a, &b, &c}
fmt.Println("- Arr Value Updates:")
for i, v := range arr {
    *v = "Hello"
    fmt.Println("v's value:      " + *v)
    fmt.Println("arr[i]'s value: " + *arr[i])
}

输出:

- Arr Value Updates:
v's value:      Hello
arr[i]'s value: Hello
v's value:      Hello
arr[i]'s value: Hello
v's value:      Hello
arr[i]'s value: Hello

希望这能帮助到某些人,因为作为Go语言的新手,这最初让我感到困惑。欢迎分享您自己避免此问题的方法!

英文:

If you would like to access v's reference value (as in for i, v := range arr) to update the value of the object in the array, there are three promising (relatively simple) workarounds:

  1. Like the first answer suggested, update arr[i] instead of v from within the array (e.g., arr[i] = "Hello")

  2. ONLY IF your array contains a set of structs you need to update but not replace in the array's assignment, set v to arr[i] within your array and then update properties through v (e.g., v := arr[i]; v.thingSheSays = "Hello";)

  3. Or, my favorite—define an array containing the object addresses. Then access the objects using a pointer from within the for-loop. Do this like so:

Input:

a, b, c := "A", "B", "C"
arr := []*string{&a, &b, &c}
fmt.Println("- Arr Value Updates:")
for i, v := range arr {
	*v = "Hello"
	fmt.Println("v's value:      " + *v)
	fmt.Println("arr[i]'s value: " + *arr[i])
}

Output:

- Arr Value Updates:
v's value:      Hello
arr[i]'s value: Hello
v's value:      Hello
arr[i]'s value: Hello
v's value:      Hello
arr[i]'s value: Hello

Hope this was able to help someone, as it initially stumped me as a newbie to golang for-loops. Feel free to share your own methods for avoiding this issue!

答案6

得分: 0

类型 arrType []string
类型 refArrType []*string

func ref(arr arrType) refArrType {
refs := make(refArrType, len(arr))
for i := 0; i < len(arr); i++ {
refs[i] = &arr[i]
}
return refs
}

func main() {
arr := arrType{"hello", "world"}

for _, item := range ref(arr) {
    *item = "some other string"
    fmt.Println(item, arr)
}

}

我不鼓励使用这种方法。但是如果你真的想要通过引用迭代项目,你可以创建一个新的引用切片(空间复杂度不是最佳),然后在该切片上进行循环。

但是在你给item赋新值时,你必须解引用指针并使用它(这就是我认为它不好的地方)。
所以是的,我不会使用这个解决方案。

而且它只适用于字符串数组。你必须为其他类型创建新的ref函数 范围引用而不是数值引用

英文:
type arrType []string
type refArrType []*string

func ref(arr arrType) refArrType {
	refs := make(refArrType, len(arr))
	for i := 0; i &lt; len(arr); i++ {
		refs[i] = &amp;arr[i]
	}
	return refs
}

func main() {
	arr := arrType{&quot;hello&quot;, &quot;world&quot;}

	for _, item := range ref(arr) {
		*item = &quot;some other string&quot;
		fmt.Println(item, arr)
	}
}

I won't encourage to use this. But if you really want to iterate over items by references then you can make a new slice of refs (not best for space complexity) and loop over that.

But with that wherever you are assigning new value to item you'll have to dereference the pointer and use it (that is what makes it bad in my opinion).
So yes I won't use this solution.

And also it works only for array of strings. You have to make new ref function for other types 范围引用而不是数值引用

答案7

得分: -1

已经在评论中提到了,但对于那些希望立即获得答案的人来说,以下是如何通过使用指针切片并对原始代码进行最少更改来实现预期结果的方法。

package main

import "fmt"

type MyType struct {
    field string
}

func main() {
    // 使用指针切片代替类型切片
    var array [10]*MyType

    // 手动初始化数组
    for idx := range array {
        array[idx] = &MyType{}
    }

    for _, e := range array {
        e.field = "foo"
    }

    for _, e := range array {
        fmt.Println(e.field)
        fmt.Println("--")
    }
}

playground中可以查看。

英文:

It's been said in the comments already, but for those looking for answers right away, here's how you can achieve expected result by using a slice of pointers and by making the least changes to the original code.

package main

import &quot;fmt&quot;

type MyType struct {
    field string
}

func main() {
    // Slice of pointers instead of slice of type
    var array [10]*MyType

    // Initialize array manually
    for idx := range array {
	    array[idx] = &amp;MyType{}
    }

    for _, e := range array {
	    e.field = &quot;foo&quot;
    }

    for _, e := range array {
	    fmt.Println(e.field)
	    fmt.Println(&quot;--&quot;)
    }

}

Here it is in playground

答案8

得分: -2

package main

import "fmt"

type MyType struct {
	field string
}

func main() {
	var array [10]MyType

	for index := range array {
		array[index].field = "foo"
	}

	for _, e := range array {
		fmt.Println(e.field)
		fmt.Println("--")
	}
}
package main

import "fmt"

type MyType struct {
	field string
}

func main() {
	var array [10]MyType

	for index := range array {
		array[index].field = "foo"
	}

	for _, e := range array {
		fmt.Println(e.field)
		fmt.Println("--")
	}
}
英文:
package main

import &quot;fmt&quot;

type MyType struct {
	field string
}

func main() {
	var array [10]MyType

	for index := range array {
		array[index].field = &quot;foo&quot;
	}

	for _, e := range array {
		fmt.Println(e.field)
		fmt.Println(&quot;--&quot;)
	}
}

huangapple
  • 本文由 发表于 2013年11月25日 13:39:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/20185511.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定