Referências de intervalo em vez de valores

91

Vi que o intervalo retorna a chave e a "cópia" do valor. Existe uma maneira desse intervalo retornar o endereço do item? Exemplo

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

Aqui, "campo" não é modificado porque intervalo envia a cópia do campo, Devo usar o índice ou existe alguma outra maneira de modificar o valor?

Obrigado pela leitura.

Epitouille
fonte
4
possível duplicata de valores
James Henstridge
1
Você pode usar uma matriz de ponteiro de MyType?
nvcnvn
Sim, se você usar uma matriz de ponteiros, poderá modificar os resultados diretamente na matriz sem precisar usar o índice, há um exemplo aqui play.golang.org/p/_Vx7ONLDJs
notzippy
rangeestá funcionando bem e retorna o que você colocou dentro da fatia. Aqui, os valores do tipo MyStruct(que é um tipo de valor) residem dentro da fatia. Em vez disso, poderíamos colocar ponteiros do tipo *MyStructdentro da fatia. Se você realmente precisa que ele funcione da maneira que está, use índices em vez de valores retornados por range.
Kaveh Shahbazian

Respostas:

126

A resposta curta e direta: não, use o índice da matriz em vez do valor

Portanto, o código acima se torna:

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
fonte
30
E, claro, se você acessar repetidamente, array[idx]poderá optar por ter e := &array[idx]no topo do loop for e, em seguida e.field1, usar e.field2,, etc, que se assemelha mais ao que o OP poderia desejar (apenas com duas linhas em vez de uma).
Dave C,
18
Você pode abandonar , _inteiramente -for idx := range array
Sam Toliman
0

Já foi dito nos comentários, mas para aqueles que procuram respostas imediatas, veja como você pode alcançar o resultado esperado usando uma porção de ponteiros e fazendo o mínimo de alterações no 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("--")
    }

}

Aqui está no playground

Jairo Lozano
fonte
2
O fato é que esse ponteiro é útil apenas para esse uso de intervalo. Eu preferiria adicionar e := &array[idx]dentro de cada intervalo que tem esse ponteiro para um ponteiro ...
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
fonte
1
Isso não parece acrescentar nada à resposta aceita existente (postada há 6 anos).
Britânicos de