Голан не может располагаться по указателю на срез
Я продолжаю получать эту ошибку при попытке переместиться по указателю на фрагмент.
app/domain/repositories/class_repository.go:24: cannot range over classes (type *[]entities.Class)
Что я делаю неправильно?
Вот структура:
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)
}
}
Вот структура класса:
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
}
Ответы
Ответ 1
Вы предполагаете, что указатель на срез будет автоматически разыменован для итерации.
Это не так, и нет причин для этого, потому что срез уже является своего рода указателем, что делает указатель на фрагмент абсолютно бесполезным.
Из Эффективный путь:
Если функция принимает аргумент среза, изменяется его значение на элементы фрагмента будет видна вызывающей стороне, аналогичной указатель на базовый массив.
Внутренне, срез сделан из
- указатель на первый элемент среза в базовом массиве
- длина среза
- емкость среза (срез обычно может быть расширен до конца массива)
Эта структура очень мала, делая указатель бесполезным.
Ответ 2
От Эффективный переход:
Если вы перебираете массив, срез, строку или карту или читаете из канала, предложение диапазона может управлять циклом.
Вы пытаетесь выполнить итерацию по указателю на срез, который является единственным значением, а не коллекция, поэтому не представляется возможным.
Измените аргумент на populateClassRelationships
как срез, а не на указатель на фрагмент. Или вы можете разыменовать указатель:
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)
}
}
Ответ 3
если вам нужно вытащить отдельный элемент из среза *, вы должны сначала разыменовать его следующим образом: (*slice)[0]
. Я стукнул головой на *slice[0]
около 6 часов, прежде чем понял это. Это связано с порядком операций, и это не очень ИМО, очень элегантный результат.
В конце концов я написал несколько методов-приемников указателей, чтобы сделать модификации на месте, такие как append и pop в более, на мой взгляд, разумным способом - пример можно найти здесь: https://play.golang.org/p/qZEYMcPHl4
Ответ 4
Вы можете разыменовать указатель:
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)
}
}
Я также изменил предложение диапазона, поскольку я не думаю, что вы изменяете classes
.