获取指向结构体字段值的指针

huangapple go评论82阅读模式
英文:

Get pointer to a struct field value

问题

我正在尝试创建一个函数,将结构体转换为mysql rows.Scan函数所需的方式,这样我就不需要手动传递很多参数。

注意:我知道sqlx的存在以及手动在单独的行中编写每个指针的替代方法,但我想以这种方式解决它,因为我正在学习Go,并且想要理解其中的原理。

我使用这种解决方案时遇到的错误是:

对我来说,valueField.Addr().Pointer() 应该是值的指针。以下是我代码的简化版本。

type User struct {
    Name string
    Age  int
}

func StrutForScan(u interface{}) []interface{} {
    val := reflect.ValueOf(u).Elem()
    v := make([]interface{}, val.NumField())
    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        v[i] = valueField.Addr().Pointer()
    }
    return v
}

func ListUsers {
    rows, err := db.Query("SELECT * FROM users")
    PanicIf(err)
    var user User
    for rows.Next() {
        err := rows.Scan(StrutForScan(&user)...)
        PanicIf(err)
        fmt.Printf("\nName: %s, Age: %s", user.Name, string(user.Age))
    }
}
英文:

I'm trying to make a function that converts a struct in the way mysql rows.Scan function needs it, so I don't need to pass manually lots of parameters.

Note: I know the existence of sqlx and the alternative of writing manually in separate lines every pointer, but I'd like to solve it in this way as I'm learning go and want to understand what's going on.

The error I get with this solution is:

to me looks like valueField.Addr().Pointer() should be a Pointer to the value. The following is a simplification of my code.

type User struct {
	Name string
	Age  int
}

func StrutForScan(u interface{}) []interface{} {
	val := reflect.ValueOf(u).Elem()
	v := make([]interface{}, val.NumField())
	for i := 0; i &lt; val.NumField(); i++ {
		valueField := val.Field(i)
		v[i] = valueField.Addr().Pointer()
	}
	return v
}

func ListUsers {
    rows, err := db.Query(&quot;SELECT * FROM users&quot;)
    PanicIf(err)
    var user User
    for rows.Next() {
	    err := rows.Scan(StrutForScan(&amp;user)...)
	    PanicIf(err)
		fmt.Printf(&quot;\nName: %s, Age: %s&quot;, user.Name, string(user.Age))

    }
}

答案1

得分: 24

你需要使用.Interface()而不是.Pointer()

func StrutForScan(u interface{}) []interface{} {
    val := reflect.ValueOf(u).Elem()
    v := make([]interface{}, val.NumField())
    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        v[i] = valueField.Addr().Interface()
    }
    return v
}

之所以这样做是因为.Pointer()返回的是实际的数据指针,如果不使用unsafe包,你无法对其进行太多操作。

英文:

You need to use .Interface() not .Pointer()

func StrutForScan(u interface{}) []interface{} {
	val := reflect.ValueOf(u).Elem()
	v := make([]interface{}, val.NumField())
	for i := 0; i &lt; val.NumField(); i++ {
		valueField := val.Field(i)
		v[i] = valueField.Addr().Interface()
	}
	return v
}

The reason behind that is that .Pointer() returns an actual "pointer" to the data, you can't do much with it without using the unsafe package.

huangapple
  • 本文由 发表于 2015年3月22日 00:14:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/29184933.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定