IT

반복하는 동안 값 변경

lottoking 2020. 6. 27. 10:37
반응형

반복하는 동안 값 변경


이 유형이 있다고 가정 해 봅시다.

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

따라서 range는 a[i]배열 / 슬라이스의 두 번째 값으로 사용 됩니다. 즉, 값이 복사되어 원래 값을 건드리지 못하게됩니다.

이 동작은 다음 코드로 설명됩니다 .

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에서 이미 제안한대로 포인터 또는 색인을 사용하는 것이 유일한 방법입니다.


당신은 이것과 동등한 것을 요구하는 것 같습니다 :

package main

import "fmt"

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

func main() {

    n := Node{
        []Attribute{
            {"key", "value"},
            {"href", "http://www.google.com"},
        },
    }
    fmt.Println(n)

    for i := 0; i < len(n.Attr); i++ {
        attr := &n.Attr[i]
        if attr.Key == "href" {
            attr.Val = "something"
        }
    }

    fmt.Println(n)
}

산출:

{[{key value} {href http://www.google.com}]}
{[{key value} {href something}]}

이렇게하면 Attribute슬라이스 경계 검사를 희생시키면서 유형 값을 복사 할 수 있습니다 . 귀하의 예에서 유형 Attributestring64 비트 아키텍처 시스템에서 비교적 작은 두 개의 슬라이스 참조입니다. 2 * 3 * 8 = 48 바이트.

간단히 쓸 수도 있습니다.

for i := 0; i < len(n.Attr); i++ {
    if n.Attr[i].Key == "href" {
        n.Attr[i].Val = "something"
    }
}

But, the way to get an equivalent result with a range clause, which creates a copy but minimizes slice bounds checks, is:

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

I'd adapt your last suggestion and use the index-only version of range.

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

It seems simpler to me to refer to n.Attr[i] explicitly in both the line that tests Key and the line that sets Val, rather than using attr for one and n.Attr[i] for the other.


For example:

package main

import "fmt"

type Attribute struct {
        Key, Val string
}

type Node struct {
        Attr []*Attribute
}

func main() {
        n := Node{[]*Attribute{
                &Attribute{"foo", ""},
                &Attribute{"href", ""},
                &Attribute{"bar", ""},
        }}

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

        for _, v := range n.Attr {
                fmt.Printf("%#v\n", *v)
        }
}

Playground


Output

main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}

Alternative approach:

package main

import "fmt"

type Attribute struct {
        Key, Val string
}

type Node struct {
        Attr []Attribute
}

func main() {
        n := Node{[]Attribute{
            {"foo", ""},
            {"href", ""},
            {"bar", ""},
        }}

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

        for _, v := range n.Attr {
                fmt.Printf("%#v\n", v)
        }
}

Playground


Output:

main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}

참고URL : https://stackoverflow.com/questions/15945030/change-values-while-iterating

반응형