duanao4503 2015-12-07 15:55
浏览 38
已采纳

切片和界面操作

I have recently started programming with Go on Google App Engine and I have run into a road block. I come from Java land so it's been a slight struggle to adapt to Go.

I want to have a method that allows me to pass in a pointer to a slice that I can then pass into the datastore.GetAll call to retrieve the results. I then want to iterate through the results and use an assertion to cast as a specific interface (Queryable) in order to call a method Map().

Initially, I had this functioning properly:

func (s ProjectService) RunQuery(context context.Context, q *datastore.Query, projects *[]Project) error {
    keys, err := q.GetAll(context, projects)
    if err != nil {
        return err
    }

    for i, key := range keys {
        (*projects)[i].Id = key.Encode()
        (*projects)[i].CompanyId = (*projects)[i].Company.Encode()
    }
    return nil
}

I want to have a more generic method that can be applied to any entity that implements a Queryable interface. The idea is to have a hook that allows me to perform some post processing after retrieving the results. I've looked into the ProperyLoadSaver interface however I have no access to the actual key that is associated to the entity. I would like to store the string representation of the datastore.Key in the entity.

This is the Queryable interface:

type Queryable interface {
    Map(*datastore.Key) error
}

Here's an example entity that I am persisting to the GAE store:

type Camera struct {
    Id        string `datastore:"-"`
    ProjectId string `datastore:"-"`
    Name      string
    Project   *datastore.Key `json:"-"`
    Active    bool
    Timestamp Timestamp
}

// Implement Queryable interface. Let me perform any additional mapping
func (c *Camera) Map(key *datastore.Key) error {
    c.Name = "Maybe do other things here"
    c.Id = key.Encode()
    return nil
}

The idea is to have something like the snippet below.

func (c Crud) RunQuery(context context.Context, q *datastore.Query, entities interface{}) error {
    keys, err := q.GetAll(context, entities)    
    v := reflect.ValueOf(entities)
    dv := v.Elem()

    for i, key := range keys {          
// I left this in to show that this worked however this won't let me enforce the interface contract
//dv.Index(i).FieldByName("Id").Set(reflect.ValueOf(key.Encode())) 

        entity := dv.Index(i).Interface().(Queryable)
        entity.Map(key)    
    }

    return err
}

However, when this executes, it panics with the following:

PANIC: interface conversion: entity.Camera is not entity.Queryable: missing method Map goroutine 9 [running]:

Just as a note, I realize the appropriate way to perform an assertion is to do if as, ok := elem.(Type); ok {} but I just wanted to see what the error was

I am guessing I am getting this error because I have defined my parameter with a pointer receiver func (c *Camera) Map(key *datastore.Key) error and not func (c Camera) Map(key *datastore.Key) error However, I want to modify the actual value.

Where am I going wrong with this? Is my Java-ness showing?

Being that I am very new to Go, I may be approaching this completely wrong.

  • 写回答

1条回答 默认 最新

  • dongshi1215 2015-12-07 16:35
    关注

    Because the method is on a pointer receiver (as it should be), use the address of the slice element:

    entity := dv.Index(i).Addr().Interface().(Queryable)
    

    An alternative approach is to use a slice of pointers for the result:

    var result []*Camera
    err := c.RunQuery(ctx, q, &result)
    

    The code can be written to work with both []Camera or []*Camera as follows:

    var queryableType = reflect.TypeOf((*Queryable)(nil)).Elem()
    needAddr := !dv.Type().Implements(queryableType)
    
    ...
    
    var entity Queryable
    if needAddr {
        entity = dv.Index(i).Addr().Interface().(Queryable)
    } else {
        entity = dv.Index(i).Interface().(Queryable)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 keepalive配置业务服务双机单活的方法。业务服务一定是要双机单活的方式
  • ¥50 关于多次提交POST数据后,无法获取到POST数据参数的问题
  • ¥15 win10,这种情况怎么办
  • ¥15 如何在配置使用Prettier的VSCode中通过Better Align插件来对齐等式?(相关搜索:格式化)
  • ¥100 在连接内网VPN时,如何同时保持互联网连接
  • ¥15 MATLAB中使用parfor,矩阵Removal的有效索引在parfor循环中受限制
  • ¥20 Win 10 LTSC 1809版本如何无损提升到20H1版本
  • ¥50 win10 LTSC 虚拟键盘不弹出
  • ¥30 微信小程序请求失败,网页能正常带锁访问
  • ¥15 Matlab求解微分方程,如何用fish2d进行预优?