请教一个 golang 中 reflect 的问题, 琢磨了一下午了

2020-11-02 22:54:05 +08:00
 Vibra
package main

import (
    "fmt"
    "reflect"
)

type arrT struct {
    Arr []int
}


func main() {
	tt := arrT{
		Arr: []int{1, 2},
	}

	arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr")
	fmt.Printf("%v, %T\n", arrValue, arrValue)

	aValue := arrValue.Elem()
	aValue.Set(reflect.Append(aValue, reflect.ValueOf(80)))
	// panic: reflect: call of reflect.Value.Elem on slice Value

    fmt.Println("Slice after appending data:", tt)
}

如代码所示

一个结构体中有一个 split 我想在里面添加一些东西, 但是一直报错, 怎样才能顺利添加进去呢?

2159 次点击
所在节点    程序员
21 条回复
emeab
2020-11-02 22:58:43 +08:00
报啥错啊
Vibra
2020-11-02 23:09:20 +08:00
@emeab 错误写在了代码中了 `panic: reflect: call of reflect.Value.Elem on slice Value`
impl
2020-11-02 23:29:10 +08:00
Go 圣经没看过?少用 reflect 和 unsafe 这两个包
treblex
2020-11-02 23:34:46 +08:00
使用 .([]int) 推算类型,修改切片试试吧
Vibra
2020-11-02 23:41:47 +08:00
@impl 主要是自己对 golang 不是很熟悉,一熟悉一下语法, 二是有点代码洁癖吧 reflect 节省了大量的重复代码
Vibra
2020-11-02 23:44:22 +08:00
@suke971219 这个修改不到原本的切片呀, 我现在已经修改好了, 谢谢. 代码附上供大家参考
```golang

func main() {
tt := arrT{
Arr: []int{1, 2},
}

arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr")
fmt.Printf("%v, %T\n", arrValue, arrValue)

arrValue.Set(reflect.Append(arrValue, reflect.ValueOf(80)))

fmt.Println("Slice after appending data:", tt.Arr)
}
```
mason961125
2020-11-02 23:46:56 +08:00
merin96
2020-11-03 06:10:06 +08:00
这玩意慢得很,小心使用
BBCCBB
2020-11-03 08:27:53 +08:00
这报错应该是 aValue := arrValue.Elem() 这一行的数据,

arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr") 你在这里已经调用过 Elem()了, 获取到的就是 slice 了, slice 没法再 elem()了.
CEBBCAT
2020-11-03 09:12:26 +08:00
@impl 少用又不是不能用,现在就是要解决用得不好的问题。就像人家在尝试使用 goto 解决跳出循环的问题时,旁人插一嘴 goto 是毒药,不能用,这不是搞笑呢吗?
useben
2020-11-03 09:36:44 +08:00
一堆人都不知道说什么...

reflect.ValueOf(&tt).Elem() 这里已经对对象指针相当于解引用了, 已经拿到对象值信息, aValue := arrValue.Elem() 这里没必要再用 Elem() , 修改为一下即可

```go
package main

import (
"fmt"
"reflect"
)

type arrT struct {
Arr []int
}


func main() {
tt := arrT{
Arr: []int{1, 2},
}

arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr")
fmt.Printf("%v, %T\n", arrValue, arrValue)

aValue := arrValue
aValue.Set(reflect.Append(aValue, reflect.ValueOf(80)))

fmt.Println("Slice after appending data:", tt)
}
```
GopherDaily
2020-11-03 09:47:21 +08:00
@Vibra
impl
2020-11-03 10:31:03 +08:00
@CEBBCAT 我说不能用了吗?要不回去学校找体育老师教你语文?
dimlau
2020-11-03 12:11:40 +08:00
@impl

1 、顶楼作者没说要多用 reflect 和 unsafe 这两个包,只是在使用时遇到了具体问题希望探讨。
---> 而妳回复说 Go 圣经主张少用;

2 、 @CEBBCAT 反驳妳说「少用又不是不能用」,意思是会尽量少用但是在用的时候遇到问题还是要解决啊。
---> 而妳回复说「我说不能用了吗?」。

似乎这两次互动都是妳(不知是否故意地)理解错了别人的意思,为什么还要让别人回学校学语文呢?
impl
2020-11-03 12:38:25 +08:00
@dimlau 看看他举的 goto 例子
no1xsyzy
2020-11-03 15:16:20 +08:00
@impl 那我问你:你在 #3 说少用的目的是什么?对楼主的问题有何建树?
猜想的可能:
1. 你认为这个问题可以更优雅地实现,不需要 reflect,那你 #13 的回复就显得非常诡异。
2. 你说的话与主题根本无关

你要纠结自句,那 #10 把 “不能用” 改成 “少用” 不是一样的吗?
那咱重新再来一遍?

少用又不是不能用,现在就是要解决用得不好的问题。就像人家在尝试使用 goto 解决跳出循环的问题时,旁人插一嘴 goto 是毒药,少用,这不是搞笑呢吗?
no1xsyzy
2020-11-03 15:16:48 +08:00
@no1xsyzy 自句 -> 字句
impl
2020-11-03 15:59:33 +08:00
@no1xsyzy 那你的建议就是一个 go 初学者浪费一个下午时间琢磨怎么用 reflect 这个包咯?
lxz6597863
2020-11-03 18:18:08 +08:00
```go
package main

import (
"fmt"
"reflect"
)

type arrT struct {
Arr []int
}

func main() {
tt := arrT{
Arr: []int{1, 2},
}

arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr")
fmt.Printf("%v, %T\n", arrValue, arrValue)

arrValue.Set(reflect.Append(arrValue, reflect.ValueOf(80)))
// panic: reflect: call of reflect.Value.Elem on slice Value

fmt.Println("Slice after appending data:", tt)
}
```
Glauben
2020-11-03 20:02:30 +08:00
楼上正解

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/721175

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX