Это потому что, когда вы передаете аргументы функции и т. Д., Они всегда передаются по значению.
Другими словами, даже если вы принимаете указатель в параметре функции, адрес структуры будет скопирован.
Затем, когда вы назначаете s
, чтобы попытаться изменить адрес, он изменяет только локальную копию, а не ту, которая находится вне функции.
Для изменения адреса из функции вам нужно будет передать указатель указателя, а затем присвоить разыменованный s
, например:
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(&pod)
fmt.Println(pod.Power)
}
func Change(s **Pod) {
*s = &Pod{2}
}
В этом случае копия адреса по-прежнему передается в функцию, но поскольку это указатель на указатель, это означает, что когда вы разыскиваете s
как *s
, вы получите адрес структуры вне функции. Это означает, что если вы назначаете *s
, вы можете изменить адрес указателя вне функции.
Конечно, как говорит Энди Швайг, вы, вероятно, не хотели бы этого делать, и, вероятно, просто изменили бы отдельные поля по мере необходимости с обычной версией функции указателя.
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
s.Power = 2
}
Это работает, потому что, когда вы набираете s.Power = 2
Go будет на самом деле сделать что-то вроде (*s).Power = 2
для вас. Таким образом, это автоматически разыгрывает s
для вас, что дает вам фактическую структуру Pod
.
Вы не можете сделать *s = &Pod{2}
в этом обычном примере указателя, потому что в этом случае *s
будет фактически равен тип Pod
, не *Pod
.
Из-за этого, если вы хотите использовать синтаксис &Pod{2}
для назначения адреса, вам нужно передать указатель на указатель. В случае s **Pod
разыменование *s
будет указывать на адрес Pod
вместо фактического Pod
, поэтому *s
будет иметь тип *Pod
, который позволяет назначить &Pod{2}
.
Сказав все этого, **Pod
только требуется, если вы хотите назначить адрес с синтаксисом &Pod{2}
.
Если вам не нужен синтаксис &Pod{2}
, вы можете просто разыменовать s
и назначить нормальный Pod{2}
.
package main
import (
"fmt"
)
type Pod struct {
Power int
}
func main() {
pod := &Pod{1}
fmt.Println(pod.Power)
Change(pod)
fmt.Println(pod.Power)
}
func Change(s *Pod) {
*s = Pod{2}
}
Это также работает, потому что теперь s
является копией адреса, и когда вы разыменования вы получите значения вне функции, типа Pod
, а не *Pod
.
Это означает, что вы можете просто назначить ему, удалив &
.
В принципе, если вы используете &
, это значит, что вы хотите присвоить адрес, а не действительное значение.
Я надеюсь, что это объяснение не слишком смущает. Я объяснил, используя **Pod
, потому что я думал, что вы хотите использовать синтаксис &Pod{2}
, а не Pod{2}
, но если это не так, мои примеры s.Power = 2
или *s = Pod{2}
могут иметь больше смысла.
Спасибо и хорошо объяснил. – Nair
@Nair Я видел ваш предыдущий комментарий, который ушел сейчас, но из-за этого я только что отредактировал ответ, чтобы предоставить дополнительную информацию. Надеюсь, это вам поможет :) –
Да. Это было связано с указателем, который я забыл на мгновение, и теперь вспоминал то, что я узнал в колледже. Мы уже давно не указали указатель на все языки нового поколения. Игнорируй меня. – Nair