dqkelut8423 2018-07-24 05:03
浏览 32
已采纳

如果对象在切片中,则方法不会更改对象的值

Here is my program:

package main

import (
    "fmt"
)

type Number struct {
    val int
}

func (num * Number) Increment () {
    num.val += 1
}

func (num Number) Value() int {
    return num.val
}

func main() {
    numbers := []Number {
        {val: 12}, 
        {val: 7},
        {val: 0},
    }

    for _, each := range numbers {
        each.Increment()
        fmt.Println(each.Value())
    }

    for _, each := range numbers {
        fmt.Println(each.Value())
    }
}

Here is the output:

13
8
1
12
7
0

First question: why does the Increment()method not update the value in the first for loop? I used pointer as the receiver so that val can be updated for sure, but why would the second for loop print out the original values of those Numbers?

Second question: what can be done so that when I iterate over a slice of Numbers and invoke the Increment() method, all Numbers are correctly incremented?

[Edit] I noticed that if I use index-based for loop and invoke the Increment() method, values will be correctly updated. Why?

for i := 0; i < len(numbers); i++ {
    numbers[i].Increment()
}
  • 写回答

3条回答 默认 最新

  • douyinjiao9351 2018-07-24 07:46
    关注

    This for range loop:

    for _, each := range numbers {
    

    iterates over the elements of the numbers slice, and in each iteration it assigns (copies) an element to the each loop variable.

    Since your numbers slices is of type []Number, it will copy the Number struct into the each variable (whose type will be Number).

    Then you call the Number.Increment() method on this variable. Since Increment() has pointer receiver, this is a shorthand for (&each).Increment(). So the address of this loop variable is taken and used as the receiver for the Increment() method. The Increment() method will properly change this loop variable, but this is independent, distinct, detached from the slice, so you are not modifying the element in the slice.

    When you do:

    for i := 0; i < len(numbers); i++ {
        numbers[i].Increment()
    }
    

    Elements of numbers are not copied here. This:

    numbers[i].Increment()
    

    Indexes the numbers slice, and since Increment() has a pointer receiver, the address of numbers[i] is taken and used, which is the address of the element in the slice. So here, you will modify the Number struct value of the slice.

    Note that you can also use for range here:

    for i := range numbers {
        numbers[i].Increment()
    }
    

    The first iteration variable when ranging over a slice is the index.

    Also, if you would store pointers in your numbers slice (which would then have type of []*Number), the same thing would happen, but in that case the for range would copy pointers, not structs, and the pointer in the loop variable would point to the same Number struct value as the pointer in the slice would, so that would also work with your first for range variant.

    All these are detailed in Spec: For statements, in the For statements with range clause subsection.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)