为什么我的代码在我输入 assert 接口时出现 panic?

Why does my code panic when I type assert an interface?

我有一些服务器代码可以向端点发送请求并接收 JSON 响应,该响应存储在空接口类型的对象中。我必须解析出信息并将其存储在一片 "Resource" 对象中,其中 Resource 是一个接口。 JSON 数据在我的例子中表示一个 "Position" 对象,它满足 Resource 接口。所以基本上这些代码看起来像这样:

// Resource interface type
type Resource interface {
    // Identifier returns the id for the object
    Identifier() bson.ObjectId
    // Description give a short description of the object
    Description() string
    // Initialize should configure a resource with defaults
    Initialize()
    // Collection name for resource
    Collection() string
    // Indexes for the resources
    Indexes() []mgo.Index
    // UserACL returns the user access control list
    UserACL() *UserACL
    // IsEqual should compare and return if resources are equal
    IsEqual(other Resource) bool
    // Refresh should update a resource from the database
    Refresh()
}

职位模型为:

// Position model
type Position struct {
    ID        bson.ObjectId `json:"id" bson:"_id,omitempty" fake:"bson_id"`
    Title     string        `json:"title" bson:"title" fake:"job_title"`
    Summary   string        `json:"summary" bson:"summary,omitempty" fake:"paragraph"`
    IsCurrent bool          `json:"isCurrent" bson:"is_current,omitempty" fake:"bool"`
    CompanyID bson.ObjectId `json:"company" bson:"company_id,omitempty" fake:"bson_id"`
    UACL      *UserACL      `bson:"user_acl,omitempty" fake:"user_acl"`
}

// Identifier returns the id for the object
func (p *Position) Identifier() bson.ObjectId {
    return p.ID
}

// Description give a short description of the object
func (p *Position) Description() string {
    return fmt.Sprintf("[%v:%v]", p.Collection(), p.ID)
}
....(the other methods follow)

我的端点旨在检索我的数据库中的位置列表,因此这显然意味着包含 JSON 数据的空接口包含一片资源,并且不能被类型断言为切片(Go 不允许这样做),而是通过迭代手动完成。所以我遵循了代码并将我的问题隔离到这个:

func InterfaceSlice(slice interface{}) []Resource {
    s := reflect.ValueOf(slice).Elem()
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    ret := make([]Resource, s.Len())

    for i := 0; i < s.Len(); i++ {
        r := s.Index(i)
        rInterface := r.Interface()
        ret[i] = rInterface.(Resource)
    }

    return ret
}

之前,上面代码中的一切都工作正常
ret[i] = rInterface.(Resource)

然后我的服务器崩溃并出现恐慌。我查看了 Go 文档,据我所知,即使 rInterface 是带有 Position 模型数据的空接口,我也应该能够将断言键入 Resource,因为 Position 类型无论如何都满足 Resource 接口。我的理解是否正确?还是我遗漏了什么?

好的,Kaedys 建议我更改 r := s.Index(i) 进入: r := s.Index(i).Addr()

这确实成功了,显然当您使用一个应该实现接口的对象时会出现问题,但该对象上的所有方法都有指针接收器。我只需要将指向该类型的指针放入接口中。