Golang不能指向切片的指针范围

时间:2014-01-22 08:43:45

标签: go

尝试在切片指针上进行测距时,我一直收到此错误。

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)
    }
}

这是Class结构:

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
    }

4 个答案:

答案 0 :(得分:21)

您假设指向切片的指针将自动解除引用以进行迭代。

情况并非如此,并且没有理由这样做,因为切片已经是一种指针,渲染指向切片的指针完全没用。

来自Effective Go

  

如果函数采用切片参数,则更改它对元素的影响   对于调用者来说,切片是可见的,类似于传递一个   指向底层数组的指针。

在内部,切片由

组成
  • 指向基础数组
  • 中切片的第一个元素的指针
  • 切片的长度
  • 切片的容量(切片通常可以延长到阵列的末尾)

此结构非常小,导致指针无效。

答案 1 :(得分:8)

来自Effective Go

  

如果您循环遍历数组,切片,字符串或地图或阅读   通过一个通道,一个范围子句可以管理循环。

您正在尝试将指针迭代到一个单独的切片,而不是一个集合因此是不可能的。

将参数更改为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)
    }
}

答案 2 :(得分:6)

如果您需要从*切片中提取单个元素,则必须首先取消引用它:(*slice)[0]。在我意识到这一点之前,我对*slice[0]约了6个小时。它与操作的顺序有关,而不是,IMO,这是一个非常优雅的结果。

我最后编写了一些指针接收器方法来进行就地修改,比如追加和弹出更多,在我看来,合理的方式 - 可以在这里找到一个例子:https://play.golang.org/p/qZEYMcPHl4

答案 3 :(得分:5)

您可以取消引用指针:

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