go-sql-driver Scan()的命名键

When using the go-sql-driver it feels like I'm re-inventing the wheel a little bit. I'm used to languages where you have a data model (like a User class) which is strictly related to the database model. Then you can have additional models for what you want to expose on an API of course, but still, you have a model for the database object. In Go I'm not sure how to do this the best way. Below is a GetUserByEmail function.

func GetUserByEmail(email string) (*myapp.User, error) {
    smt, err := database.Prepare("SELECT * FROM users WHERE email = ?")

    if err != nil {
        return nil, err
    }

    rows, err := smt.Query(email)
    defer rows.Close()

    if err != nil {
        return nil, err
    }

    var users []*myapp.User

    for rows.Next() {
        var id string
        var confirmed bool
        var password string
        var email string
        var updated string
        var created string
        err = rows.Scan(&id, &confirmed, &password, &email, &updated, &created)

        if err != nil {
            return nil, err
        }

        user := myapp.User{id, confirmed, created, password, email, updated}
        users = append(users, &user)
    }

    if users == nil || len(users) == 0 {
        return nil, errors.New("User not found.")
    }

    if len(users) != 1 {
        return nil, errors.New("Nr of users fetched: " + string(len(users)) + ". Expected: 1.")
    }

    return users[0], nil
}

One problem here is that if I change the order of password and email in the database, my application will silently switch those and I will get no error. That's an awful and dangerous behavior. Can Scan() take keys somehow or can I do this in some other way? I could of course look at Columns() and take the index order from there as an int (although Go doesn't seem to have that function built in) and map it to my User variables, but do I really need to do all that for all my database methods? Is it abstracted somewhere or do I need to do that myself?

One problem here is that if I change the order of password and email in the database, my application will silently switch those and I will get no error.

Arguably the best solution to this problem is simply not to use SELECT * -- always name your columns. The problems with * can actually be larger than what you describe--what if new columns are added, which your query doesn't even need? Your code will break, for no useful reason.

But on to your larger question...

Can Scan() take keys somehow or can I do this in some other way?

The standard library sql package does not provide this functionality. However, there are third-party libraries that do. sqlx is probably the most popular one, which is most similar to the standard library. It is my recommendation.

If you prefer pain, suffering, and never-ending bloodshed, something like gorm or gorp are also possibilities.