1. ホーム
  2. arrays

[解決済み] 反復しながら値を変更する

2022-04-20 05:54:33

質問

このような型があるとします。

type Attribute struct {
    Key, Val string
}
type Node struct {
    Attr []Attribute
}

で、自分のノードの属性を繰り返し変更したいとします。

できるようになるといいなと思いました。

for _, attr := range n.Attr {
    if attr.Key == "href" {
        attr.Val = "something"
    }
}

としていますが attr はポインターではないので、これはうまくいかないので、そうしなければならない。

for i, attr := range n.Attr {
    if attr.Key == "href" {
        n.Attr[i].Val = "something"
    }
}

もっと簡単な方法、もっと速い方法はないでしょうか?からのポインタを直接取得することは可能でしょうか? range ?

もちろん、反復のためだけに構造を変えたくはありませんし、より冗長な解決策は解決策ではありません。

どのように解決するのですか?

いいえ、ご希望の省略形はできません。

その理由は、以下の通りです。 range は、反復処理中のスライスから値をコピーします。 そのため 範囲についての指定 と書かれています。

Range expression                          1st value             2nd value (if 2nd variable is present)
array or slice  a   [n]E, *[n]E, or []E   index    i  int       a[i]       E

そこで、レンジは a[i] を配列/スライスの2つ目の値として使用することを意味します。 の値がコピーされ、元の値には手を付けられなくなります。

この挙動を示すのが 次のコード :

x := make([]int, 3)

x[0], x[1], x[2] = 1, 2, 3

for i, val := range x {
    println(&x[i], "vs.", &val)
}

このコードでは、範囲指定された値と実際の値で、まったく異なるメモリ位置が表示されます。 の値をスライスします。

0xf84000f010 vs. 0x7f095ed0bf68
0xf84000f014 vs. 0x7f095ed0bf68
0xf84000f018 vs. 0x7f095ed0bf68

ということは、すでにjnmlさんやpeterSOさんが提案されているように、ポインターを使うかインデックスを使うかしかないわけです。