Referencias de rango en lugar de valores

90

Vi que el rango devuelve la clave y la "copia" del valor. ¿Hay alguna forma de que ese rango devuelva la dirección del artículo? Ejemplo

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

Aquí "campo" no se modifica porque el rango envía la copia del campo. ¿Tengo que usar el índice o hay alguna otra forma de modificar el valor?

Gracias por leer.

Epitouille
fuente
4
posible duplicado de los valores
James Henstridge
1
¿Puedes usar una matriz de puntero de MyType?
nvcnvn
Sí, si usa una matriz de punteros, puede modificar los resultados directamente en la matriz sin tener que usar el índice, hay un ejemplo aquí play.golang.org/p/_Vx7ONLDJs
notzippy
rangefunciona bien y devuelve lo que ha puesto dentro del segmento. Aquí los valores de tipo MyStruct(que es un tipo de valor) residen dentro del segmento. En su lugar, podríamos poner punteros de tipo *MyStructdentro del segmento. Si es absolutamente necesario que funcione como está, puede usar índices en lugar de valores devueltos por range.
Kaveh Shahbazian

Respuestas:

123

La respuesta corta y directa: no, use el índice de la matriz en lugar del valor

Entonces el código anterior se convierte en:

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("--")
    }
}
MushinNoShin
fuente
30
Y, por supuesto, si tiene acceso a varias veces array[idx]en su lugar podría optar por tener e := &array[idx]en la parte superior del bucle y luego usar e.field1, e.field2, etc, que se asemeja más a la OP hubiera querido (solo con dos líneas en lugar de uno).
Dave C
16
Puede abandonar por , _completofor idx := range array
Sam Toliman
0

Ya se ha dicho en los comentarios, pero para aquellos que buscan respuestas de inmediato, así es como pueden lograr el resultado esperado usando una porción de punteros y haciendo los mínimos cambios en el código original.

package main

import "fmt"

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] = &MyType{}
    }

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

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

}

Aquí está en el patio de recreo

Jairo Lozano
fuente
2
El hecho es que ese puntero es útil solo para este uso de rango. Preferiría agregar e := &array[idx]dentro de cada rango que tenga ese puntero a un puntero ...
Cirelli94
-1
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("--")
    }
}
jukay
fuente
Esto no parece agregar nada a la respuesta aceptada existente (publicada hace 6 años).
Británicos