简体   繁体   中英

Golang populate function parameters with struct values

I'm wondering is there is a way to populate a variadic function parameter in golang with all the values of a struct (which will typically be of varying types).

The specific example I'm thinking of is the following snippet to generate a row for a mocked postgres database query using https://github.com/DATA-DOG/go-sqlmock :

rows := sqlmock.NewRows([]string{
        "id",
        "updated_at",
        "created_at",
        "meta",
        "account_id",
        "currency",
        "nickname",
        "scheme_name",
        "identification",
        "name",
        "identification_secondary",
        "servicer_scheme_name",
        "servicer_identification",
        "institution_id",
        "client_id",
    }).AddRow(
        mock.Values.AccountID,
        time.Now(),
        time.Now(),
        "{}",
        "12345678",
        "GBP",
        "Test",
        "Schema",
        "12345676534263",
        "New account",
        "12345",
        "schema",
        "test id",
        mock.Values.InstitutionID,
        mock.Values.ClientID,
    )

Given the parameters always represent a struct (fields and values), I was attempting to use a struct to populate both the fields and values rather than complete each manually. Fields is fairly simple with reflection, however the values are of multiple types with the AddRow function defined as:

AddRow func(values ...driver.Value) *Rows

Is there a way to loop over struct fields and provide typed values to achieve something like?...

account := Account{
        ID:             "ABCD12436364",
        UpdatedAt:      time.Now(),
        CreatedAt:      time.Now(),
        Meta:           "{}",
        AccountID:      "12345678",
        Currency:       "GBP",
        Nickname:       "Test",
        SchemeName:     "Scheme",
        Identification: "12345676534263",
        Name:           "New account",
        IdentificationSecondary: "12345",
        ServicerSchemeName:      "scheme",
        ServicerIdentification:  "test id",
        InstitutionID:           "ABCD123456",
        ClientID:                "ZXCVB12436",
    }

rows := sqlmock.NewRows(account.GetFieldsJSON()).AddRow(account.GetValues())

This can be done with the reflect package which allows you to loop over a struct's fields and then construct a slice of driver.Value s. You would then pass the resulting slice to AddRow with the trailing ... to "unpack" the contents.

var result []driver.Value

rv := reflect.ValueOf(account)
for i := 0; i < rv.NumField(); i++ {
    fv := rv.Field(i)
    dv := driver.Value(fv.Interface())
    result = append(result, dv)
}

AddRow(result...)

Note that in this case the conversion driver.Value(fv.Interface()) works because driver.Value is an empty interface and so is the type returned by fv.Interface() .

https://play.golang.org/p/7Oy8_YrmkMa

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM