【问题标题】:Copying pointer content in go causing uneccesary overhead?在 go 中复制指针内容会导致不必要的开销?
【发布时间】:2021-11-25 14:45:39
【问题描述】:

如果我理解正确的话,*s = *(*State)(&state)&state 的内容复制到s 地址(在将*rawState 转换为*State 之后)。但是如果是这样的话,只做s = (*State)(&state)而不是复制和*state被GC收集不是更有效吗?或者它是否会导致副作用改变 s / 的值或这样做的其他原因?谢谢!

来自[0]的完整函数:

func (s *State) UnmarshalJSON(b []byte) error {
type rawState State
var state rawState

dec := json.NewDecoder(bytes.NewReader(b))
if s.useJSONNumber {
    dec.UseNumber()
}
err := dec.Decode(&state)
if err != nil {
    return err
}

*s = *(*State)(&state)

return s.Validate()}

[0]https://github.com/hashicorp/terraform-json/blob/d1018bf93fd9c097133b0159ab8b3c0517a846c9/state.go#L73

【问题讨论】:

  • 请注意,解码为 *rawState 类型的值而不是 *State 是必要的,以避免无限递归调用 UnmarshalJSON。至少在我看来,代码可以像play.golang.org/p/UlKeqi7MZ-q 这样简化一点(通过抛弃令人困惑的部分)。
  • 另外,作者可能只是写了*s = State(state),结果是一样的。 *s = *(*State)(&state) 的使用与上述相比没有任何优势,它所做的只是增加了混乱。

标签: go pointers copy


【解决方案1】:

任务:

*s = *(*State)(&state)

复制指向的值。这是必需的,因为s 是一个局部变量,一旦函数返回,将任何内容分配给s 本身将无效。

目的是在s指向的地方赋值,这就是上面的赋值语句所做的。

使用rawState 的目的是创建一个没有UnmarshalJSON() 方法的新类型,因此将*rawState 传递给json.Unmarshal() 不会导致堆栈溢出。

查看相关:Call json.Unmarshal inside UnmarshalJSON function without causing stack overflow

【讨论】:

    【解决方案2】:

    s 是一个指针,可以说指向内存中的位置x

    &state 是内存位置y 的另一个指针。

    函数UnmarshalJSON被调用,指针指向内存位置x

    如果你这样做:

    *s = *(*State)(&state)

    这意味着: 将指针指向y(&state),将其转换为正确的指针类型(*State),然后转到内存位置y(*在=之后的开头)然后将值(=)复制到另一个内存位置x*s)。

    另一方面,如果你这样做:s = (*State)(&state)

    这意味着: 将 pointer 指向y(&state),将其转换为正确的指针类型(*State),将该指针(=) 复制到接收器(s)。任何调用此函数的对象所指向的内存位置x 保持不变。

    同样,当方法被调用时,UnmarshalJSON 作为s 接收到的指针本身是指针在调用位置处的副本。 UnmarshalJSON 内的 s*State 类型的值,在 UnmarshalJSON 之外不存在。因此,除了UnmarshalJSON,这个分配将毫无意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      相关资源
      最近更新 更多