代码之家  ›  专栏  ›  技术社区  ›  learningtech

当参数不是go中的指针时,使用reflect通过引用更新值

  •  0
  • learningtech  · 技术社区  · 7 年前

    我在学习围棋中的反射、指针和接口的基础知识时遇到了困难,所以这里还有一个入门级的问题我似乎想不通。

    这段代码实现了我希望它做的事情-我使用reflect向作为接口类型的切片添加另一条记录。

    package main
    
    import (
      "reflect"
      "log"
    )
    type Person struct {
      Name string
    }
    func Add(slice interface{}) {
      s := reflect.ValueOf(slice).Elem()
      // in my actual code, p is declared via the use of reflect.New([Type])
      p := Person{Name:"Sam"}
    
      s.Set(reflect.Append(s,reflect.ValueOf(p)))
    }
    
    func main() {
      p := []Person{}
      Add(&p)
      log.Println(p)
    }
    

    func Add(slice interface{}) {
      s := reflect.ValueOf(&slice).Elem()
      p := Person{Name:"Sam"}
    
      s.Set(reflect.Append(reflect.ValueOf(slice),reflect.ValueOf(p)))
      log.Println(s)
    }
    
    func main() {
      p := []Person{}
      Add(p)
      log.Println(p)
    }
    

    log.Println(p) 在结尾没有显示与记录的片段 Sam 就像我希望的那样。 Add() 接收一个不是指针的片,我仍然可以在其中编写一些代码 添加()

    我最近提出的很多问题都围绕着这类主题,所以我仍然需要花一段时间来弄清楚如何有效地使用reflect包。

    1 回复  |  直到 7 年前
        1
  •  2
  •   svsd    7 年前

    不,如果不传入指向片的指针,就不可能附加到函数中的片。这与反射无关,而是与变量如何传入函数有关。下面是相同的代码,修改为不使用反射:

    package main
    
    import (
            "log"
    )
    
    type Person struct {
            Name string
    }
    
    func AddWithPtr(slicep interface{}) {
            sp := slicep.(*[]Person)
    
            // This modifies p1 itself, since *sp IS p1
            *sp = append(*sp, Person{"Sam"})
    }
    
    func Add(slice interface{}) {
            // s is now a copy of p2
            s := slice.([]Person)
    
            sp := &s
    
            // This modifies a copy of p2 (i.e. s), not p2 itself
            *sp = append(*sp, Person{"Sam"})
    }
    
    func main() {
            p1 := []Person{}
            // This passes a reference to p1
            AddWithPtr(&p1)
            log.Println("Add with pointer:   ", p1)
    
            p2 := []Person{}
            // This passes a copy of p2
            Add(p2)
            log.Println("Add without pointer:", p2)
    }
    

    (上面,当它表示切片的“copy”时,并不意味着底层数据的拷贝-只是切片)

    当您传入一个切片时,函数将有效地获取一个新切片,该切片引用与原始切片相同的数据。在函数中附加到切片会增加新切片的长度,但不会更改传入的原始切片的长度。这就是原始切片保持不变的原因。