创建数组/切片以在Golang

时间:2016-05-28 16:54:04

标签: postgresql go

我刚刚开始使用golang,我正在尝试从Postgres users表中读取多行,并将结果存储为模型行的User结构数组。

type User struct {
    Id  int
    Title string
}

func Find_users(db *sql.DB) {
    // Query the DB
    rows, err := db.Query(`SELECT u.id, u.title FROM users u;`)
    if err != nil { log.Fatal(err) }

    // Initialize array slice of all users. What size do I use here? 
    // I don't know the number of results beforehand
    var users = make([]User, ????)

    // Loop through each result record, creating a User struct for each row
    defer rows.Close()
    for i := 0; rows.Next(); i++ {
        err := rows.Scan(&id, &title)
        if err != nil { log.Fatal(err) }

        log.Println(id, title)
        users[i] = User{Id: id, Title: title}
    }

    // .... do stuff
}

正如您所看到的,我的问题是我想事先初始化一个数组或切片以存储所有数据库记录,但我不知道会提前记录多少条记录。

我正在权衡几种不同的方法,并希望找出以下哪种方式最常用于golang社区 -

  1. 事先创建一个非常大的数组(例如10,000个元素)。似乎很浪费

  2. 事先明确计算行数。这可能有效,但我需要运行2个查询 - 一个用于计数,一个用于获取结果。如果我的查询很复杂(这里没有显示),那就是在2个地方复制那个逻辑。或者,我可以运行相同的查询两次,但首先循环它并计算行。这一切都会奏效,但看起来似乎不洁净。

  3. 我见过扩展切片的例子。我不太了解切片,看看它如何适应这里。此外,如果我不断扩大10倍的切片,它肯定是浪费。

  4. 谢谢!

2 个答案:

答案 0 :(得分:8)

Go具有内置的append功能,正是出于此目的。它需要一个切片和一个或多个元素,并将这些元素附加到切片,返回新切片。此外,切片的零值(nil)是一个长度为零的切片,因此如果您附加到零切片,它将起作用。因此,您可以这样做:

type User struct {
    Id    int
    Title string
}

func Find_users(db *sql.DB) {
    // Query the DB
    rows, err := db.Query(`SELECT u.id, u.title FROM users u;`)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    var users []User
    for rows.Next() {
        err := rows.Scan(&id, &title)
        if err != nil {
            log.Fatal(err)
        }

        log.Println(id, title)
        users = append(users, User{Id: id, Title: title})
    }
    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }

    // ...
}

答案 1 :(得分:3)

用户附加到切片:

type DeviceInfo struct {
     DeviceName     string
     DeviceID       string
     DeviceUsername string
     Token          string
}

func QueryMultiple(db *sql.DB){
    var device DeviceInfo
    sqlStatement := `SELECT "deviceName", "deviceID", "deviceUsername", 
                 token FROM devices LIMIT 10`
    rows, err := db.Query(sqlStatement)
    if err != nil {
       panic(err)
    }
    defer rows.Close()
    var deviceSlice []DeviceInfo
    for rows.Next(){
        rows.Scan(&device.DeviceID, &device.DeviceUsername, &device.Token, 
                  &device.DeviceName)
         deviceSlice = append(deviceSlice, device)
    }
    fmt.Println(deviceSlice)
}