Значения указателя копирования * a = * b в golang
type T struct {
Id int
Name string
}
func Copy(a *T, b *T) error {
b.Id=5
b.Name="gert"
a = b
return nil
}
a
по-прежнему пуст, я должен сделать это так:
func Copy(a *T, b *T) error {
b.Id = 5
b.Name = "gert"
a.Id = b.Id
a.Name = b.Name
return nil
}
теперь a
совпадает с b
Почему и как я могу скопировать *b
в *a
напрямую?
Ответы
Ответ 1
Ваш первый пример почти прав. Вы передаете указатели на два объекта. Вы помещаете эти указатели в переменные A и B. Но A и B являются локальными переменными, поэтому, когда вы говорите a=b
, вы просто говорите: "Забудьте, что было в (локально)". Остальная часть программы по-прежнему имеет указатели на эти два оригинальных объекта.
Если вы хотите скопировать структуру данных в B в структуру данных в A, сделайте это вместо этого:
*a = *b;
Ответ 2
В go аргументы передаются по значению.
и * T - указатель на T. Подумайте об этом как о int, который сообщает вам, где это T.
Итак, "a" указывает на один экземпляр T и b указывает на другой.
в вашей функции копирования, вы говорите, чтобы указать точку b "T" (если это имело смысл).
Вы хотели сказать, что T должен быть таким же, как b T
Вы делаете это путем разыменования указателей.
поэтому вместо a = b (измените мою локальную переменную "a", чтобы указать на то, что указывает "b" )
вы используете * a = * b (измените значение T равным b T)
Надеюсь, это имело смысл, вот пример вашего приложения, измененный для "правильной работы". Обратите внимание: ваша функция копирования не нужна в этом, она там для иллюстрации. Пример воспроизведения
import "fmt"
type T struct {
Id int
Name string
}
func Copy(a *T, b *T) error {
b.Id = 5
b.Name = "gert"
a = b
return nil
}
func CopyThatActuallyCopies(a *T, b *T) error {
b.Id = 5
b.Name = "gert"
*a = *b
return nil
}
func main() {
var a = &T{1, "one"}
var b = &T{2, "two"}
fmt.Println(a, b)
Copy(a, b)
fmt.Println(a, b)
CopyThatActuallyCopies(a, b)
fmt.Println(a, b)
}
Ответ 3
Общее решение для разработчиков инфраструктуры:
func CloneValue(source interface{}, destin interface{}) {
x := reflect.ValueOf(source)
if x.Kind() == reflect.Ptr {
starX := x.Elem()
y := reflect.New(starX.Type())
starY := y.Elem()
starY.Set(starX)
reflect.ValueOf(destin).Elem().Set(y.Elem())
} else {
destin = x.Interface()
}
}
Итак:
CloneValue(old, new)
см. этот код в play.golang.org
Таким образом, вы можете передавать любой тип во время выполнения, пока вы уверены, что источник и destin являются одинаковыми типами (и destin является указателем на этот тип).
Ответ 4
Это неверно. Это не работает.
func (r *Request) WithContext(ctx context.Context) *Request {
if ctx == nil {
panic("nil context")
}
r2 := new(Request)
*r2 = *r
r2.ctx = ctx
return r2
}