IT

반복하는 동안 값 변경

itgroup 2023. 6. 2. 20:23
반응형

반복하는 동안 값 변경

다음과 같은 유형이 있다고 가정합니다.

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]두 번째 값으로 배열/배열을 지정할 수 있습니다. 즉, 값이 복사되어 원래 값을 만질 수 없게 됩니다.

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

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과 peter가 이미 제안한 것처럼 포인터나 인덱스를 사용하는 것입니다.그렇게.

당신은 이것과 동등한 것을 요구하는 것처럼 보입니다.

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값, 조각 경계 검사의 희생.예제에서 다음을 입력합니다.Attribute상대적으로 작음, 2string슬라이스 참조: 64비트 아키텍처 컴퓨터에서 2 * 3 * 8 = 48바이트.

간단히 다음과 같이 쓸 수도 있습니다.

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

하지만, 그에 상응하는 결과를 얻는 방법은range복사본을 생성하지만 슬라이스 경계 검사를 최소화하는 절은 다음과 같습니다.

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

당신의 마지막 제안을 수정하여 인덱스 전용 버전의 범위를 사용하겠습니다.

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

제가 참조하기에 더 간단한 것 같습니다.n.Attr[i]테스트하는 두 행 모두에서 명시적으로Key그리고 지는 선이Val사용하는 것보다attr처음부터 끝까지n.Attr[i]다른 하나는

예:

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

놀이터.


산출량

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

대안적 접근 방식:

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

놀이터.


출력:

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

반응형