英文:
Can I write a Go method that operates on a struct with arbitrary number of fields?
问题
我有一个Go结构体,看起来像这样:
type myStruct struct {
A bool
B bool
C bool
}
我想编写一个方法,将布尔值从true
翻转为false
,反之亦然。但我不想为字段A
、B
和C
重复相同的代码3次。我想要写一个循环。
我考虑的代码如下:
func (m *myStruct) flipBools() {
r := reflect.ValueOf(*m)
for i := 0; i < r.NumField(); i++ {
// 在这里写什么?
}
}
但我不知道在循环内部应该写什么。这可行吗?我意识到对于像Go这样的强类型语言来说,这是一个很高的要求。
英文:
I have a Go struct that looks like this:
type myStruct struct {
A bool
B bool
C bool
}
I want to write a method that flips the bool values from true
to false
and vice-versa. But I don't want to repeat the same code 3 times for fields A
, B
& C
. I want to write a loop.
I'm thinking something like this:
func (m *myStruct) flipBools() {
r := reflect.ValueOf(*m)
for i := 0; i < r.NumField(); i++ {
// WHAT GOES HERE?
}
}
But I don't know what to put inside the loop. Can it be done? I realize this is a tall order for a strongly typed language like Go.
答案1
得分: 3
不需要反射。
func (m *myStruct) flipBools() {
ps := []*bool{&m.A, &m.B, &m.C}
for _, p := range ps {
*p = !*p
}
}
你甚至可以将逻辑提取到一个可变参数的函数中,并且可以重复使用,如果你想的话:
func flipBools(ps ...*bool) {
for _, p := range ps {
*p = !*p
}
}
func (m *myStruct) flipBools() {
flipBools(&m.A, &m.B, &m.C)
}
英文:
No need for reflection.
func (m *myStruct) flipBools() {
ps := []*bool{&m.A, &m.B, &m.C}
for _, p := range ps {
*p = !*p
}
}
https://play.golang.org/p/RrCo4Kph-hl
You can even extract the logic into a variadic func and have it be re-used, if you want to:
func flipBools(ps ...*bool) {
for _, p := range ps {
*p = !*p
}
}
func (m *myStruct) flipBools() {
flipBools(&m.A, &m.B, &m.C)
}
答案2
得分: 3
为了实际回答这个问题:是的,这是可能的(即使不是特别明智)。以下是实现的代码:
func (m *myStruct) flipBools() {
r := reflect.ValueOf(m).Elem()
for i := 0; i < r.NumField(); i++ {
fld := r.Field(i)
if fld.Kind() == reflect.Bool {
fld.SetBool(!fld.Bool())
} // 可选:否则,做其他操作?
}
}
内部循环实际上很简单;唯一需要修复的是使用 reflect.ValueOf(*m)
会得到一个不可寻址的值,无法设置其字段;而 reflect.ValueOf(m).Elem()
通过指针访问结构体,这样就可以正常工作了。
英文:
In the spirit of actually answering the question: yes, it's possible (even if it's not particularly wise). This works:
func (m *myStruct) flipBools() {
r := reflect.ValueOf(m).Elem()
for i := 0; i < r.NumField(); i++ {
fld := r.Field(i)
if fld.Kind() == reflect.Bool {
fld.SetBool(!fld.Bool())
} // optional: else, do something else?
}
}
The inner loop is actually pretty easy; the only thing that needed fixing was that using reflect.ValueOf(*m)
leaves you with an un-addressable value that can't have its fields set; reflect.ValueOf(m).Elem()
accesses the struct through the pointer, which works fine.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论