当我输入断言接口时,为什么我的代码会出现恐慌?

时间:2016-10-18 20:01:25

标签: json go server slice type-assertion

我有一些服务器代码向端点发送请求并接收存储在类型为空接口的对象中的JSON响应。我必须解析信息并将其存储在"资源"对象,资源是一个接口。在我的案例中,JSON数据代表了一个"位置" object,它满足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 doesn& #39; t允许这个)而是通过迭代手动完成。所以我按照代码进行了操作,并将我的问题分离出来:

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模型数据的空接口,我也应该能够将assert输入到Resource中,因为Position类型无论如何都满足了Resource接口。我理解这个是正确的吗?或者我有什么遗失的东西?

1 个答案:

答案 0 :(得分:0)

Ok Kaedys建议我改变     r:= s.Index(i) 成:     r:= s.Index(i).Addr()

这就是诀窍,显然当你使用一个应该满足接口的对象时会出现问题,但是该对象上的所有方法都有指针接收器。我只需要在接口中添加一个指向该类型的指针。