为什么我的代码在我输入 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()
这确实成功了,显然当您使用一个应该实现接口的对象时会出现问题,但该对象上的所有方法都有指针接收器。我只需要将指向该类型的指针放入接口中。
我有一些服务器代码可以向端点发送请求并接收 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()
这确实成功了,显然当您使用一个应该实现接口的对象时会出现问题,但该对象上的所有方法都有指针接收器。我只需要将指向该类型的指针放入接口中。