Golang Pointer Обратный список связанных путаницы - PullRequest
0 голосов
/ 27 апреля 2018

Я новичок в Golang и немного смущен тем, как здесь работают указатели, и я использую вопрос с обратным списком в качестве примера.

func reverseList(head *ListNode) *ListNode {
  var prev *ListNode = nil
  for {
    if head == nil {
      break
    }
    temp := head
    head = head.Next
    temp.Next = prev
    prev = temp
  }
    return prev
}

В этом случае temp и head указывают на одну и ту же ячейку памяти. Но если бы я поставил строку temp.Next = prev перед head = head.Next, head.Next будет указывать на ноль.

Что происходит под капотом, когда мы говорим temp.Next = prev. Мы говорим, что структура, на которую указывает temp, теперь изменилась и, таким образом, если бы я поместил эту строку выше head = head.Next, то head теперь также указывает на эту измененную структуру?

Я думал, что для того, чтобы изменить фактическое значение head.Next, мы должны разыменовать его?

Я немного смущен тем, почему это не сработает вместо

func reverseList(head *ListNode) *ListNode {
  var prev *ListNode = nil
  for {
    if head == nil {
      break
    }
    temp := head   
    temp.Next = prev
    prev = temp
    head = head.Next <--- CHANGED ORDERING HERE
  }
    return prev
}

1 Ответ

0 голосов
/ 27 апреля 2018

Это не сработает, потому что вы аннулируете head на первой итерации. Вот поток:

temp := head   
// Since temp is a pointer, any modifications made to it will also
// impact head. So when you set temp.Next here, you're also setting
// head.Next. Since prev is always nil on the first iteration, you've
// set head.Next = nil.
temp.Next = prev
prev = temp
// This will set head to nil, always.
head = head.Next

В правильной версии обновление head = head.Next до того, как произойдет какая-либо запись, означает, что вы уже перешли к следующему элементу, и поэтому безопасно перезаписать значение.

По сути, вторая версия отсекает все элементы списка, кроме первой. Если вы не делали ссылку на второй элемент до вызова этой функции, то теперь они отключены и будут собирать мусор.

Обновления на основе комментариев:
Когда вы делаете что-то вроде temp := head, вы говорите: «создайте указатель с именем temp и укажите на то же, на что указывает head». Если затем вы измените то, на что указывает temp (как, например, выполнение temp.Next = prev), вы также увидите изменения при чтении данных, на которые указывает head, поскольку они все еще указывают на то же место.

Когда вы затем делаете head = head.Next, вы говорите «обновите head, чтобы он указывал туда, куда указывает head.Next». Это обновляет сам head вместо данных, на которые он указывает, поэтому вы не увидите никаких изменений, связанных с temp.

Вот хороший ресурс, чтобы узнать больше об указателях: https://dave.cheney.net/2017/04/26/understand-go-pointers-in-less-than-800-words-or-your-money-back

...