尝试在切片指针上移动时,我一直收到此错误。
1 | app/domain/repositories/class_repository.go:24: cannot range over classes (type *[]entities.Class) |
我究竟做错了什么?
这是结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | package repositories import ( "mobifit/app/domain/entities" ) type ClassRepository struct { *Repository } func (c *ClassRepository) ClassesForLastNDays(days int) *[]entities.Class { classes := new([]entities.Class) query := Select("*"). From("Class"). Where("VisibleAt > CURRENT_TIMESTAMP() - INTERVAL ? DAY"). OrderBy("ClassTypeId"). Sql() c.Repository.Select(classes, query, days) c.populateClassRelationships(classes) return classes } func (c *ClassRepository) populateClassRelationships(classes *[]entities.Class) { for i := range classes { <<<<<<<<<<< Here is the problem class := classes[i] // ClassType c.Repository.GetById(class.ClassType, class.ClassTypeId) //Instructor c.Repository.GetById(class.Instructor, class.ClassType.InstructorId) // Equipment query := Select("E.*"). From("Equipment E"). Join("ClassEquipment CE on E.Id = CE.EquipmentId"). Where("CE.ClassId = ?"). Sql() c.Repository.Select(class.Equipment, query, class.Id) } } |
这是Class结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package entities import ( "time" ) type Class struct { Id int ClassTypeId int VideoPath string VideoSize int Duration float64 CreatedAt time.Time VisibleAt time.Time NoLongerVisibleAt time.Time // Relationships ClassType ClassType Instructor User Equipment []Equipment } |
- 切片已经是一种指针,没有理由指向它。
-
我希望有一块指针,所以可以用
PoulateClassRelationships 函数填充它们 -
@dystroy我认为您现在实际上是最好的答案,因为您实际上已经找到了问题的根源。 根据golang.org/doc/effective_go.html#slices,
If a function takes a slice argument, changes it makes to the elements of the slice will be visible to the caller, analogous to passing a pointer to the underlying array - 我曾经踩过同样的耙子。 玩。
您假设指向切片的指针将在迭代时自动取消引用。
事实并非如此,这没有理由,因为切片已经是一种指针,使指向切片的指针完全无用。
从有效出发:
If a function takes a slice argument, changes it makes to the elements
of the slice will be visible to the caller, analogous to passing a
pointer to the underlying array.
在内部,切片是由
- 指向基础数组中切片的第一个元素的指针
- 切片的长度
- 切片的容量(通常可以将切片扩展到数组的末尾)
这种结构非常小,使指针无用。
- 澄清:指向切片的指针有一种用途:如果程序的多个部分需要共享同一切片,则对切片本身的修改会反映在程序的其他部分中(例如,如果从切片中删除元素,通过执行a = append(a [:i],a [i + 1:] ...)应该反映在其他数据结构持有的切片中)。但是,这很少是您想要的,并且没有锁定也不是线程安全的。
- 我花了几个小时进行调试,因为我一直试图变得太聪明了。我有个函数正在返回[] *结构,因为我不想复制内存。当构建返回结果时,这对我的代码造成了严重的破坏,因为我的片中的每个指针都指向每个循环迭代器的内存地址,这意味着我最终返回的片中有10个指针全部指向相同的结构。当我从方程式中取出指针并在每次循环后返回一个正常切片时,一切工作都很好。
从有效执行:
If you're looping over an array, slice, string, or map, or reading
from a channel, a range clause can manage the loop.
您尝试遍历指向单个值的切片的指针,因此无法进行收集。
将参数更改为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | func (c *ClassRepository) populateClassRelationships(classes *[]entities.Class) { for i := range *classes { // dereferencing the pointer to get the actual slice class := classes[i] // ClassType c.Repository.GetById(class.ClassType, class.ClassTypeId) //Instructor c.Repository.GetById(class.Instructor, class.ClassType.InstructorId) // Equipment query := Select("E.*"). From("Equipment E"). Join("ClassEquipment CE on E.Id = CE.EquipmentId"). Where("CE.ClassId = ?"). Sql() c.Repository.Select(class.Equipment, query, class.Id) } } |
- 不,它不必是一个指针,我只是想使其工作。
- 您能告诉我如何在没有指针的情况下进行操作吗?我将关键部分复制到play.golang.org/p/KonrOk3bp-
- 第19行出现问题。
-
我以为,如果您在调用
populateClassRelationships 时没有将指针传递给数组,那么您只是填充一个副本,而在ClassesForLastNDays 中返回时,原始副本将为空白 - 现在获取不能使用&classes(类型** [] entities.Class)作为函数参数中的[] entities.Class类型
如果需要从* slice中提取单个元素,则必须先取消引用它,例如:
我最终写了一些指针接收器方法来进行就地修改,例如追加和弹出,在我看来,这是一种合理的方式-可以在以下示例中找到示例:
-
@HassaanSalik-感谢您的支持,让我过去了,我不再这样做了。切片已经是指针类型,因此通常不应有任何理由需要
*slice -自从重构了此代码以来,Id建议您寻找机会做同样的事情。
您可以取消引用指针:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | func (c *ClassRepository) populateClassRelationships(classes *[]entities.Class) { for _, class := range *classes { // NOTE the * dereference // ClassType c.Repository.GetById(class.ClassType, class.ClassTypeId) //Instructor c.Repository.GetById(class.Instructor, class.ClassType.InstructorId) // Equipment query := Select("E.*"). From("Equipment E"). Join("ClassEquipment CE on E.Id = CE.EquipmentId"). Where("CE.ClassId = ?"). Sql() c.Repository.Select(class.Equipment, query, class.Id) } } |
我还更改了range子句,因为我不认为您正在修改