Golang中如何修改包含结构体对象的切片条目

Golang中如何修改包含结构体对象的切片条目 大家好

我正在尝试设置一个函数,它接收一个包含结构体的切片,该函数应修改保存在此结构体中的变量,然后将其写入CSV文件。但不幸的是,它并未全局调整变量的值,而仅在函数内部生效(希望我的解释是清楚的,我对GoLang和编程还比较陌生^^)。

以下是我提到的结构体:

// Contact 作为类型,由不同的字符串组成
type Contact struct {
	ID        string
	FirstName string
	LastName  string
	Title     string
	EMail     string
}

以及“对象”结构体类型的切片:

var contacts []Contact

以下是修改结构体中特定条目的函数(不确定这样做是否正确^^):

func EditContact(selection string, toEditValue string, EditValue string) {
	//var tempContacts []Contact
	//var contactsFound = false
	fmt.Println("Im in this function")
	switch {

	case selection == "id":
		
		for _, contact := range contacts {

			
			if contact.ID == toEditValue {
				//contactsFound = true
				
				contact.ID = EditValue
				fmt.Println("The ID is now", contact.ID)

			}

		}
		if filePersistence {

			updateDataInFile()
		} else {
		
		}
		break
	case selection == "fn":
		break
	case selection == "ln":
		break
	case selection == "jt":
		break
	case selection == "em":
		break

	}

}

以下是将内容写入CSV文件的函数:

func updateDataInFile() {
	//打开文件并使用 O_Trunc 添加新行,0755 是编辑文件的权限
	file, err := os.OpenFile(FileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
	checkError("Cannot open file", err)
	writer := csv.NewWriter(file)
	//此 for 循环逐行写入新的联系人
	for _, contact := range contacts {
		contactSerialized := []string{contact.ID, contact.FirstName, contact.LastName, contact.Title, contact.EMail}
		err := writer.Write(contactSerialized)
		checkError("Cannot write to file", err)
		fmt.Println("udpatedatainfile here. contact.ID is now", contact.ID)
	}

	writer.Flush()
	file.Close()
}

我猜测可能需要返回它……但删除条目时并不需要这样做:

func DeleteContact(id string) {

	//临时切片用于添加空条目,将索引向前回退一位
	var tempContacts []Contact
	var contactsFound = false
	for _, contact := range contacts {
		if contact.ID == id {
			contactsFound = true
		} else {
			tempContacts = append(tempContacts, contact)
		}
	}

	if contactsFound {
		contacts = tempContacts
	}
	//将新数据写入文件
	if filePersistence {
		updateDataInFile()
	}

}

你能告诉我我做错了什么吗?

感谢你的帮助。

诚挚的问候


更多关于Golang中如何修改包含结构体对象的切片条目的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

是的。你正在使用原始对象,而不是一个副本……

更多关于Golang中如何修改包含结构体对象的切片条目的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


哈哈,不好意思!!打错字了!!!应该是“修改这段代码” 😄

亲爱的 Yamil_Bracho

谢谢,这个方法有效!你能向我解释一下“chane this code”具体是什么意思吗?

此致,

Gabe

另一种方法是使用 []*Contact。这样,原始循环中的 contact 就是一个指向 Contact 的指针,对其字段的赋值会改变原始的 Contact 对象。

哦^^,抱歉,我之前确实没太明白您的意思。

那么,为了确认我理解正确:这不再是本地副本了,因为我们现在是在遍历正确结构体的索引,对吗?

感谢您的帮助。

祝好。

问题在于函数中的“contact”是一个局部副本。这就是为什么你看到了变化,但contacts切片中没有变化。将这段代码:

for _, contact := range contacts {
  if contact.ID == toEditValue {
     contactsFound = true
      contact.ID = EditValue
      fmt.Println("The ID is now", contact.ID)
  }   
}

改为:

  for i := 0; i < len(contacts); i++ {
	    if contacts[i].ID == toEditValue {
		    contactsFound = true
		    contacts[i].ID = EditValue
		    fmt.Println("The ID is now", contacts[i].ID)
            break
	     }
   }

问题在于你使用了值拷贝的 for range 循环。在 Go 中,for _, contact := range contacts 中的 contact 是切片元素的副本,修改它不会影响原始切片中的结构体。

以下是修正后的代码:

func EditContact(selection string, toEditValue string, EditValue string) {
    fmt.Println("Im in this function")
    
    for i := range contacts {
        switch selection {
        case "id":
            if contacts[i].ID == toEditValue {
                contacts[i].ID = EditValue
                fmt.Println("The ID is now", contacts[i].ID)
            }
        case "fn":
            if contacts[i].FirstName == toEditValue {
                contacts[i].FirstName = EditValue
            }
        case "ln":
            if contacts[i].LastName == toEditValue {
                contacts[i].LastName = EditValue
            }
        case "jt":
            if contacts[i].Title == toEditValue {
                contacts[i].Title = EditValue
            }
        case "em":
            if contacts[i].EMail == toEditValue {
                contacts[i].EMail = EditValue
            }
        }
    }
    
    if filePersistence {
        updateDataInFile()
    }
}

或者使用指针切片:

var contacts []*Contact

func EditContact(selection string, toEditValue string, EditValue string) {
    fmt.Println("Im in this function")
    
    for _, contact := range contacts {
        switch selection {
        case "id":
            if contact.ID == toEditValue {
                contact.ID = EditValue
                fmt.Println("The ID is now", contact.ID)
            }
        case "fn":
            if contact.FirstName == toEditValue {
                contact.FirstName = EditValue
            }
        case "ln":
            if contact.LastName == toEditValue {
                contact.LastName = EditValue
            }
        case "jt":
            if contact.Title == toEditValue {
                contact.Title = EditValue
            }
        case "em":
            if contact.EMail == toEditValue {
                contact.EMail = EditValue
            }
        }
    }
    
    if filePersistence {
        updateDataInFile()
    }
}

DeleteContact 函数能正常工作的原因是它直接操作了 contacts 切片变量,通过重新赋值 contacts = tempContacts 来更新原始切片。

回到顶部