golang 在 for 循环中追加问题

golang append issue inside a for loop

问题:

append inside Users() for loop below 将 users 中的最后一项添加到 userRxs []*UserResolver

3x

期望:

append 应将 users 中的每个项目添加到 userRxs []*UserResolver

// Users return all users from Db
func (r *RootResolver) Users() ([]*UserResolver, error) {
    var userRxs []*UserResolver
    users := r.Db.Users()
    for _, u := range users {
        log.Printf("userID: %s, username: %s, email: %s, password: %s", u.UserID, u.Username, u.Email, u.Password)
        userRxs = append(userRxs, &UserResolver{&u})
    }
    log.Printf("%v", userRxs)
    return userRxs, nil
}

在 for 循环中,log.Printf 打印此

userID: 0374402a-3dc4-48da-86c4-949905ccc26c, username: sunnysan, email: sunnysan@gmail.com, password: 12345678
userID: 53f21c4f-2cd8-4e67-b3e9-5ef344806230, username: sunnysan2, email: sunnysan2@gmail.com, password: 12345678
userID: 0a47d3af-03dc-4050-a028-7a41599af497, username: sunnysan3, email: sunnysan3@gmail.com, password: 12345678 

for 循环后,log.Printf("%v", userRxs) 打印此

[
  User { 
    userID: 0a47d3af-03dc-4050-a028-7a41599af497, 
    username: sunnysan3, 
    email: sunnysan3@gmail.com, 
    password: 12345678 
  }
  User { 
    userID: 0a47d3af-03dc-4050-a028-7a41599af497, 
    username: sunnysan3, 
    email: sunnysan3@gmail.com, 
    password: 12345678 
  }
  User { 
    userID: 0a47d3af-03dc-4050-a028-7a41599af497, 
    username: sunnysan3, 
    email: sunnysan3@gmail.com, 
    password: 12345678 
  }
]

这里是完整的文件以获取更多上下文

package main

import (
    "fmt"
    "log"

    graphql "github.com/graph-gophers/graphql-go"
)

/*
 *  User GQL type

        type User {
        userID: ID!
        username: String!
        email: String!
        password: String!
    }
*/

// User type should match the exact shape of the schema commented above
type User struct {
    UserID   graphql.ID
    Username string
    Email    string
    Password string
}

// RootResolver ingests Db to run queries (getters) against it
type RootResolver struct {
    *Db
}

// String prints pretty structs ie. fmt.Printf can't do it on its own
func (r *UserResolver) String() string {
    return fmt.Sprintf("User{userID: %s, username: %s, email: %s, password: %+v}",
        r.u.UserID, r.u.Username, r.u.Email, r.u.Password,
    )
}

// Users return all users from Db
func (r *RootResolver) Users() ([]*UserResolver, error) {
    var userRxs []*UserResolver
    users := r.Db.Users()
    for _, u := range users {
        log.Printf("userID: %s, username: %s, email: %s, password: %s", u.UserID, u.Username, u.Email, u.Password)
        userRxs = append(userRxs, &UserResolver{&u})
    }
    log.Printf("%v+", userRxs)
    return userRxs, nil
}

// User returns a single user from Db
func (r *RootResolver) User(args struct{ UserID graphql.ID }) (*UserResolver, error) {
    // Find user:
    u, err := r.Db.User(args.UserID)
    if err != nil {
        // Didn’t find user:
        return nil, nil
    }
    return &UserResolver{&u}, nil
}

// UserResolver ingests properties from User
type UserResolver struct{ u *User }

// UserID returns the userId of the user
func (r *UserResolver) UserID() graphql.ID {
    return r.u.UserID
}

// Username returns the username of the user
func (r *UserResolver) Username() string {
    return r.u.Username
}

// Email returns the email of the user
func (r *UserResolver) Email() string {
    return r.u.Email
}

// Password returns the password of the user
func (r *UserResolver) Password() string {
    return r.u.Password
}

r.Db.Users()方法

// Users correspond to Users query from graphql
func (d *Db) Users() []User {
    rows, err := d.Query("SELECT * FROM users")
    Check(err, "stmt.Query")

    // Create User struct for holding each row's data
    var r User
    // Create slice of Users for our response
    users := []User{}
    // Copy the columns from row into the values pointed at by r (User)
    // order matters here from db table
    defer rows.Close()
    for rows.Next() {
        err = rows.Scan(
            &r.UserID,
            &r.Username,
            &r.Email,
            &r.Password,
        )
        Check(err, "rows.Next")
        users = append(users, r)
    }

    return users
}

每次迭代都会覆盖范围变量,&u也是一样。因此,您最终会多次附加包含相同地址的 UserResolver 。您需要使用该变量的本地副本。试试这个:

for _, u := range users {
        u:=u  // Make a copy of the variable and redeclare it
        userRxs = append(userRxs, &UserResolver{&u})
    }