Путаница с указателями в Go - PullRequest
0 голосов
/ 01 апреля 2020

Мне трудно понять приведенный ниже код, он работает, но все еще не понимаю. Было бы очень полезно, если бы кто-то мог его демистифицировать

В приведенном ниже коде имя флага не обновляется до «Изменено»

package main

import "fmt"

type Command struct {
   Name  string
   Flags []Flag
}

type Flag struct {
   Name      string
   Shorthand string
}

func getCommand() *Command {
   return &Command{Name: "Hello", Flags: []Flag{{"version", "v"}}}
}

func change(cmd *Command) {
   for _, flg := range cmd.Flags {
       flg.Name = "Changed"
   }

}

func main() {
   cmd := getCommand()
   change(cmd)
   fmt.Println(cmd.Flags[0])

}

Правильный код. Имя флага изменено на «Изменено»

package main

import "fmt"

type Command struct {
    Name  string
    Flags []*Flag
}

type Flag struct {
    Name      string
    Shorthand string
}

func getCommand() *Command {
    return &Command{Name: "Hello", Flags: []*Flag{{"version", "v"}}}
}

func change(cmd *Command) {
    for _, flg := range cmd.Flags {
        flg.Name = "Changed"
    }

}

func main() {
    cmd := getCommand()
    change(cmd)
    fmt.Println(cmd.Flags[0])

}

Я уверен, что моя путаница может быть тривиальной, но она потратила мои пару часов

Ответы [ 2 ]

1 голос
/ 01 апреля 2020
for _, flg := range cmd.Flags {
        flg.Name = "Changed"
    }

Эта часть является точным виновником. Первое значение, возвращаемое диапазоном, является индексом (который здесь игнорируется), второе значение является копией фактических данных. Когда вы используете его внутри l oop (flg.Name = ...), вы присваиваете значение имени, указанному в копии. Вы можете сделать это:

for index, _ := range cmd.Flags {
        cmd.Flags[index].Name = "Changed"
    }

Во втором случае вы присваиваете полю Имя копии ссылки (или адреса памяти) для флага, поэтому значение при этом адрес памяти изменился.

1 голос
/ 01 апреля 2020

В вашей первой версии, когда вы делаете это:

for _, flg := range cmd.Flags {
    flg.Name = "Changed"
}

flg является локальной переменной типа Flag. На каждой итерации for l oop, range устанавливает flg для копии следующего элемента в cmd.Flags. Поэтому, когда вы изменяете это, ничего не меняется вне этого l oop.

Во второй версии, когда вы делаете это, l oop, flg является локальной переменной типа *Flag, поэтому, когда range устанавливает для него копию следующего элемента в cmd.Flags, flg указывает на данные, которые вы пытаетесь изменить, и изменение их на самом деле изменяет эти данные.

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