V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Vibra
V2EX  ›  程序员

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

  •  
  •   Vibra · 2020-11-02 22:54:05 +08:00 · 2321 次点击
    这是一个创建于 1487 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 我想在里面添加一些东西, 但是一直报错, 怎样才能顺利添加进去呢?

    21 条回复    2020-11-03 22:24:27 +08:00
    2kCS5c0b0ITXE5k2
        1
    2kCS5c0b0ITXE5k2  
       2020-11-02 22:58:43 +08:00
    报啥错啊
    Vibra
        2
    Vibra  
    OP
       2020-11-02 23:09:20 +08:00
    @emeab 错误写在了代码中了 `panic: reflect: call of reflect.Value.Elem on slice Value`
    impl
        3
    impl  
       2020-11-02 23:29:10 +08:00
    Go 圣经没看过?少用 reflect 和 unsafe 这两个包
    treblex
        4
    treblex  
       2020-11-02 23:34:46 +08:00 via iPhone
    使用 .([]int) 推算类型,修改切片试试吧
    Vibra
        5
    Vibra  
    OP
       2020-11-02 23:41:47 +08:00
    @impl 主要是自己对 golang 不是很熟悉,一熟悉一下语法, 二是有点代码洁癖吧 reflect 节省了大量的重复代码
    Vibra
        6
    Vibra  
    OP
       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
        7
    mason961125  
       2020-11-02 23:46:56 +08:00   ❤️ 1
    merin96
        8
    merin96  
       2020-11-03 06:10:06 +08:00 via iPhone
    这玩意慢得很,小心使用
    BBCCBB
        9
    BBCCBB  
       2020-11-03 08:27:53 +08:00
    这报错应该是 aValue := arrValue.Elem() 这一行的数据,

    arrValue := reflect.ValueOf(&tt).Elem().FieldByName("Arr") 你在这里已经调用过 Elem()了, 获取到的就是 slice 了, slice 没法再 elem()了.
    CEBBCAT
        10
    CEBBCAT  
       2020-11-03 09:12:26 +08:00 via Android
    @impl 少用又不是不能用,现在就是要解决用得不好的问题。就像人家在尝试使用 goto 解决跳出循环的问题时,旁人插一嘴 goto 是毒药,不能用,这不是搞笑呢吗?
    useben
        11
    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
        12
    GopherDaily  
       2020-11-03 09:47:21 +08:00
    @Vibra
    impl
        13
    impl  
       2020-11-03 10:31:03 +08:00
    @CEBBCAT 我说不能用了吗?要不回去学校找体育老师教你语文?
    dimlau
        14
    dimlau  
       2020-11-03 12:11:40 +08:00
    @impl

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

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

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

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

    少用又不是不能用,现在就是要解决用得不好的问题。就像人家在尝试使用 goto 解决跳出循环的问题时,旁人插一嘴 goto 是毒药,少用,这不是搞笑呢吗?
    no1xsyzy
        17
    no1xsyzy  
       2020-11-03 15:16:48 +08:00
    @no1xsyzy 自句 -> 字句
    impl
        18
    impl  
       2020-11-03 15:59:33 +08:00
    @no1xsyzy 那你的建议就是一个 go 初学者浪费一个下午时间琢磨怎么用 reflect 这个包咯?
    lxz6597863
        19
    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
        20
    Glauben  
       2020-11-03 20:02:30 +08:00
    楼上正解
    no1xsyzy
        21
    no1xsyzy  
       2020-11-03 22:24:27 +08:00
    @impl 我感觉你纯粹是不会说话,或者心态崩了
    “我建议先考虑不用 reflect 解决问题。另外,楼主可以把原本的问题问出来,以避免这是个潜在的 X-Y 问题”
    这是否正确表达了你的意图?同时,这样一段话又能显得说话人温和谦虚且博学。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1031 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 21:31 · PVG 05:31 · LAX 13:31 · JFK 16:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.