golang append issue inside a for loop [duplicate]

泄露秘密 提交于 2021-02-11 13:46:35

问题


Problem:

append inside Users() for loop below adds the last item in users 3x into userRxs []*UserResolver

Expectation:

append should add each item inside users into 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
}

inside the for loop, log.Printf prints this

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 

after the for loop, log.Printf("%v", userRxs) prints this

[
  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 
  }
]

here's the entire file for more context

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() method

// 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
}

回答1:


The range variable is overwritten at each iteration, and &u is the same. So you end up appending a UserResolver containing the same address multiple times. You need to use a local copy of that variable. Try this:

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


来源:https://stackoverflow.com/questions/61641558/golang-append-issue-inside-a-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!