Каков тип данных итерационных значений, возвращаемых `range`? - PullRequest
0 голосов
/ 14 марта 2020
type Student struct {
    Name string
    Age  int
}

func main() {
    data := make([]*Student, 0)

    src := []Student{
        Student{Name: "allen", Age: 30},
        Student{Name: "tom", Age: 33},
    }

    for _, m := range src {
        data = append(data, &m) // notice point!!!
    }

    for _, s := range data {
        fmt.Println(*s)
    }
}

Почему этот фрагмент кода работает в Go? Вывод немного отличается от ожидаемого, который ниже.

{tom 33}
{tom 33}

вместо

{allen 30}
{tom 33}

Я нашел объяснение, что m является фиксированным указателем, таким образом каждый раз append(data,&m) просто добавляет адрес m, который остается неизменным во время итераций.

Однако, согласно этому объяснению, m, похоже, имеет *Student, поэтому &m имеет **Student, но как можно добавить значение (&m) **Student в массив []*Student?

Ответы [ 3 ]

1 голос
/ 14 марта 2020

При ранжировании по срезу для каждой итерации возвращаются два значения. Первый - это индекс, а второй - копия элемента с этим индексом.

Итак, у него есть значение массива / фрагмента, который вы перебираете.

В вашем случае значение равно Student struct

0 голосов
/ 14 марта 2020

На самом деле это связано с тем, что в Go все передается по значению.

m := range src

m всегда одна и та же ссылка, и ее значение обновляется. Простой способ увидеть это - напечатать адрес

for _, m := range src {
    // ---
    p := &m
    fmt.Printf("%p\n", p)
    // ---
    data = append(data, &m) // notice point!!!
}

Отличный пост, объясняющий ваш точный вопрос, можно найти здесь Итерация по ломтикам в go

0 голосов
/ 14 марта 2020

Во-первых, вы можете использовать самоанализ, чтобы узнать, что такое m. Кроме того, вы можете объявить это (var m ...) перед l oop как эксперимент.

Теперь вы пишете: «Я нашел объяснение, что m - фиксированный указатель». Во-первых, я не уверен, что вы имеете в виду под «фиксированным указателем», и не думаю, что вы это делаете. Фиксированным (или постоянным) является адрес m. Вывод таков: «каждый раз, когда append(data,&m) просто добавляет адрес m», именно это и происходит. Тем не менее, ваше предположение о том, что «m, по-видимому, имеет значение *Student», ошибочно, вместо этого m имеет тип Student, просто так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...