Loops 循环和映射引用

Loops 循环和映射引用,loops,pointers,go,Loops,Pointers,Go,我的代码在Task数组上循环,并使用字符串键和Task值创建一个映射: package main import ( "fmt" ) type Task struct { Name string Project string } func main() { taskMap := map[string]*Task{} taskList := []Task{ { Name: "name1",

我的代码在
Task
数组上循环,并使用字符串键和
Task
值创建一个映射:

package main

import (
    "fmt"
)

type Task struct {
    Name    string
    Project string
}

func main() {
    taskMap := map[string]*Task{}
    taskList := []Task{
        {
            Name:    "name1",
            Project: "project1",
        },
        {
            Name:    "name2",
            Project: "project2",
        },
        {
            Name:    "name3",
            Project: "project3",
        },
    }
    for _, task := range taskList {
        taskMap[task.Name] = &task
    }

    // Print results
    for k, v := range taskMap {
        fmt.Println(k, v)
    }
}
此代码的输出如下所示:

name1 &{name3 project3}
name2 &{name3 project3}
name3 &{name3 project3}
这不是我所期望的,因为它每次都打印相同的内容。我对这里发生的事情略知一二,因为如果我用以下内容替换循环,它将按预期工作:

for _, task := range taskList {
        taskMap[task.Name] = &Task{
            Name:        task.Name,
            Project: task.Project,
        }
}
因此,最后访问的任务的引用显然存储在
taskMap
的每个键中


有没有一种方法可以做到这一点而不必手动复制每个字段?

所有键的值都相同,因为您在
for
循环中引用了相同的
任务
变量。使用以下代码段获取对切片中项目的引用

for idx, task := range taskList {
    taskMap[task.Name] = &taskList[idx]
}
顺便说一句,要复制一个变量,您可以将其分配给一个新变量,如

for _, task := range taskList {
    x := task
    taskMap[task.Name] = &x
}

每次迭代都将创建一个新的
x
变量,并在映射内使用指向该变量的指针。

所有键的值都相同,因为您在
循环中引用了相同的
任务
变量。使用以下代码段获取对切片中项目的引用

for idx, task := range taskList {
    taskMap[task.Name] = &taskList[idx]
}
顺便说一句,要复制一个变量,您可以将其分配给一个新变量,如

for _, task := range taskList {
    x := task
    taskMap[task.Name] = &x
}

每次迭代将创建一个新的
x
变量,并在映射中使用指向该变量的指针。

您存储的是
任务的地址,而不是值


您可以将
taskList
切换到一段指针:
taskList:=[]*Task{
并使用
taskMap[Task.Name]=Task
存储的是
Task
的地址,而不是值


您可以将
taskList
切换到一段指针:
taskList:=[]*Task{
并使用
taskMap[Task.Name]=任务

事实上我比我更喜欢Arman的答案,它向你展示了如何在不改变现有数据结构的情况下完成它。在这种情况下,我的答案是可以接受的,但你不能总是控制输入的内容。事实上,我比我更喜欢Arman的答案,它向你展示了如何在不改变现有数据结构的情况下完成它。我的答案是在这种情况下是可接受的,但您并不总是控制输入的内容。变量
task
存储在每次迭代中更改的本地副本,但
task
的地址(存储在映射中)保持不变。因此,当您打印地图内容时,所有地图值都指向最后一个列表项的副本。变量
task
存储在每次迭代中更改的本地副本,但
task
的地址(存储在地图中)保持不变。因此,当您打印映射内容时,所有映射值都指向最后一个列表项的副本。对于I:=range taskList{taskMap[taskName]=&taskList[I]},正确的解决方案应该是
。我的意思是,如果想在每次迭代中获得一个指向切片元素的指针,那么获取元素本身就没有意义了——它的索引就足够了,并且可以轻松地使用它来获取指向其对应元素的指针。除了在您的示例中,
taskName
不存在之外;您需要元素来获取名称。在我看来,发布的解决方案似乎是正确的。“让它存在”并不难不,真的。ooo或者你可以只使用
范围
运算符的两个参数形式,而不必使用中间变量或额外的切片标识符。说真的,为什么要让这比需要的更难呢。两个参数形式在这里非常合适。我想说,对于I:=范围任务列表,正确的解决方案应该是
{taskMap[taskName]=&taskList[i]}
。我的意思是,如果想在每次迭代中获得一个指向切片元素的指针,那么获取元素本身就没有意义了——它的索引就足够了,并且可以轻松地使用它来获取指向其对应元素的指针。除了在您的示例中,
taskName
不存在之外;您需要元素来获取名称。在我看来,发布的解决方案似乎是正确的。“让它存在”并不难。不,真的。ooo或者您可以只使用
range
运算符的双参数形式,而不必使用中间变量或附加的切片标识符。说真的,为什么要让这比需要的更难呢。双参数形式在这里非常合适。