2015-01-25 2 views
2

Я пытаюсь написать эквивалент следующей строки в Pythonподмножество массива в golang

H = [e for e in G if condition(e)]

Вот мой пример кода. В основном я просто пытаюсь использовать функцию getter (G.get), чтобы получить подмножество G. Поэтому я думаю, что я хочу, чтобы arr2 был новым массивом, но содержащим один и тот же объект.

package main 

import "fmt" 

type Object struct { 
    x int 
} 

type Group []Object 

func (G *Group) get() (H []Object) { 
    for _,v := range *G { 
     H = append(H,v) 
    } 
    return 
} 

func main() { 
    arr := make(Group,1) 
    arr[0].x = 1 
    fmt.Println(arr) 
    arr2 := arr.get() 
    arr[0].x = 3 
    fmt.Println(arr) 
    fmt.Println(arr2) 
} 

Что компилируется и работает и дает мне

[{1}] 
[{3}] 
[{1}] 

Мой вопрос: «Почему же arr2 не содержат один и тот же экземпляр объекта как arr?» Кажется, я понимаю, что make только создает экземпляр Group, что означает, что он включает в себя один Object. Но тогда цикл for не должен создавать новый Object, если он?

Спасибо за помощь!

ответ

2

Этот простой фрагмент кода показывает, что происходит:

var a Object 
a.x = 1 
b := a 
fmt.Println(a, b) // prints {1} {1} 
b.x = 2 
fmt.Println(a, b) // prints {1} {2} 

playground example

В заявлении b := a копирует значение Object в переменной a к переменной b. Теперь есть две копии значения. Изменение одного не меняет другого.

Это отличается от Python, где присваивание копирует ссылку на значение.

петля в вопросе также копирует значения:

for _,v := range *G { 
    H = append(H,v) 
} 

Переменная v является копией срез элемент из *G. Копия v добавляется к фрагменту H. Существует три независимых значения Object: значение в slice *G, значение в v и значение в slice H.

Если вы хотите, чтобы ломтики все они относятся к одной и той же Object значения, а затем хранить указатели на Object значений в срезе:

type Group []*Object 

arr := make(Group, 1) 
arr[0] = &Object{x: 1} 
fmt.Println(arr[0].x) // prints 1 
arr2 := arr.get() 
arr[0].x = 3 
fmt.Println(arr[0].x) // prints 3 
fmt.Println(arr2[0].x) // prints 3 

playground example

+0

Великое объяснение! Это полезно знать о ': =' копировании значения. Кроме того, знаете ли вы, есть ли лучший способ сделать '[e для e в G, если условие (e)]'? – Travis