duanshangying5102 2018-11-12 00:48
浏览 32
已采纳

填充作为指针传递给函数的结构数组

I'm want to do data pagination with Google Cloud Platform Datastore and I've found an example on GCP's page (https://cloud.google.com/datastore/docs/concepts/queries) for doing it with Cursors and it works absolutely fine.

The example provided by Google has hardcoded the variables var tasks []Task and var task Task and I would like to create a reusable function where I can pass the pointer to a struct array via a parameter typed interface{} and get this struct populated by this function. For example:

    type MyStruct1 struct {
        F1 string
    }

    type MyStruct2 struct {
        F1 int
    }

    func list(ctx context.Context, cursorStr string, data interface{}) {
    ...
    }

    func main() {
        mystruct1 := make([]MyStruct1, 0)
        list(ctx, "", &mystruct1)

        mystruct2 := make([]MyStruct2, 0)
        list(ctx, "", &mystruct2)
    }

My problem starts when I need to create in this function, a variable to store the record and then append it to the struct array passed as a pointer.

Example from Google

func SnippetIterator_Cursor() {
    ctx := context.Background()
    client, _ := datastore.NewClient(ctx, "my-proj")
    cursorStr := ""
    // [START datastore_cursor_paging]
    const pageSize = 5
    query := datastore.NewQuery("Tasks").Limit(pageSize)
    if cursorStr != "" {
        cursor, err := datastore.DecodeCursor(cursorStr)
        if err != nil {
            log.Fatalf("Bad cursor %q: %v", cursorStr, err)
        }
        query = query.Start(cursor)
    }

    // Read the tasks.
    var tasks []Task << THIS IS WHAT I WANT TO BE GENERIC 
    var task Task. << THIS IS WHAT I WANT TO BE GENERIC 
    it := client.Run(ctx, query)
    _, err := it.Next(&task)
    for err == nil {
        tasks = append(tasks, task)
        _, err = it.Next(&task)
    }
    if err != iterator.Done {
        log.Fatalf("Failed fetching results: %v", err)
    }

    // Get the cursor for the next page of results.
    nextCursor, err := it.Cursor()
    // [END datastore_cursor_paging]
    _ = err        // Check the error.
    _ = nextCursor // Use nextCursor.String as the next page's token.
}

My Generic function based on the code above

func list(ctx context.Context, kind string, data interface{}, pageSize int, cursorStr string) string {
    query := datastore.NewQuery(kind).Limit(pageSize)
    if cursorStr != "" {
        cursor, err := datastore.DecodeCursor(cursorStr)
        if err != nil {
            log.Fatalf("Bad cursor %q: %v", cursorStr, err)
        }
        query = query.Start(cursor)
    }
    it := query.Run(ctx)

    // HERE IS WHERE THE PROBLEM STARTS
    var vet []interface{}
    var rec interface{}

    k, err := it.Next(rec)
    if err != nil {
        log.Println(err.Error())
    }
    for err == nil {
        log.Println(k, rec) // PROBLEM: The key comes ok but rec comes nil
        vet = append(vet, rec)
        k, err = it.Next(rec)
    }
    log.Println(vet) // PROBLEM: vet has only nils

    nextCursor, err := it.Cursor()
    if err != nil {
        log.Println(err.Error())
    }

    data = vet
    return nextCursor.String()
}

func TestListFunc() {
    data := make([]Tasks, 0)
    cursor := list(ctx, "Tasks", &data, 10, "")
    x, _ := json.MarshalIndent(data, " ", "   ")
    log.Println(string(x))
}

PROBLEM: The Datastore iterator .Next() doesn't seem to store the record in a variable typed interface{}

  • 写回答

1条回答 默认 最新

  • donglu9445 2018-11-12 01:10
    关注

    Use the reflect package:

    func list(ctx context.Context, kind string, dst interface{}, pageSize int, cursorStr string) string {
        client, _ := datastore.NewClient(ctx, "my-proj")
        query := datastore.NewQuery(kind).Limit(pageSize)
        if cursorStr != "" {
            cursor, err := datastore.DecodeCursor(cursorStr)
            if err != nil {
                log.Fatalf("Bad cursor %q: %v", cursorStr, err)
            }
            query = query.Start(cursor)
        }
    
        // Get reflect value for the result slice.
        results := reflect.ValueOf(dst).Elem()
    
        // Allocate new value of the slice element type. 
        // resultp is pointer to that value.
        resultp := reflect.New(results.Type().Elem())
    
        it := client.Run(ctx, query)
        _, err := it.Next(resultp.Interface())
        for err == nil {
            // Append last value to results
            results.Set(reflect.Append(results, resultp.Elem())
    
            _, err = it.Next(resultp.Interface())
        }
        if err != iterator.Done {
            log.Fatalf("Failed fetching results: %v", err)
        }
    
        // Get the cursor for the next page of results.
        nextCursor, err := it.Cursor()
        // [END datastore_cursor_paging]
        _ = err        // Check the error.
        _ = nextCursor // Use nextCursor.String as the next page's token.
    }
    

    Call the function with a pointer to the destination slice:

    var data []Tasks
    cursor := list(ctx, "Tasks", &data, 10, "")
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号