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.


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

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


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

1
Isso não parece acrescentar nada à resposta aceita existente (postada há 6 anos).
Britânicos de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.