5
\$\begingroup\$

I have an application with a recent addition that requires the removal of a struct pointer from a slice that is itself an element of another struct. A summary of the usage.

I am wondering if this is idiomatic and okay usage of the go languages. Things appear to work and this appears to be inline with the golang recommendations for slice element deletion.

package main

import (
    "fmt"
    "strconv"
)


const ARBITRARY= 5


type myData struct {
    det detailSlicePtr 
}

type detail struct {
    id   int
    name string
}

// Slice of pointers to details
type detailSlicePtr []*detail


// Returns true if item removed succesfully,
// false all other cases
func(s *myData ) remove(d *detail) bool {
    for i:= range s.det {
        if s.det[i].name == d.name && s.det[i].id == d.id {
            s.det[i] = new(detail)
            s.det = append(s.det[:i],s.det[i+1:]...)
            return true
        }
    }

    return false
}

// Find and remove a struct element from a slice of struct pointers within a     struct
func main() {

    var d myData
    details := make(detailSlicePtr , ARBITRARY)

    for j := 0; j < ARBITRARY; j++ {
        details [j] = &detail{
            id:   j,
            name: strconv.Itoa(j),
        }
    }

    d.det = details 

    // Print out what we have so far
    for index := range d.det {
        fmt.Printf("Item %d is %s\n", index, d.det[index].name)
    }

    findMe := ARBITRARY / 2
    middle := &detail{id: findMe ,name:strconv.Itoa(findMe)}

    if ok := d.remove(middle); !ok {

        fmt.Printf("Unable to find element: %v\n", middle)

    } else {

        fmt.Printf("Found and removed element: %v\n", middle)

        // Print what is left
         for index := range d.det {
            fmt.Printf("Item %d is %s\n", index, d.det[index].name)
        }   
    }
}
\$\endgroup\$
5
\$\begingroup\$

It is not idiomatic and it is not okay usage. It should be:

SliceTricks

Delete (pointers)

copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]

For example,

package main

import (
    "fmt"
    "strconv"
)

const ARBITRARY = 5

type myData struct {
    det detailSlicePtr
}

type detail struct {
    id   int
    name string
}

// Slice of pointers to details
type detailSlicePtr []*detail

// Returns true if item removed succesfully,
// false all other cases
func (s *myData) remove(d *detail) bool {
    for i := range s.det {
        if s.det[i].name == d.name && s.det[i].id == d.id {
            copy(s.det[i:], s.det[i+1:])
            s.det[len(s.det)-1] = nil
            s.det = s.det[:len(s.det)-1]
            return true
        }
    }
    return false
}

// Find and remove a struct element from a slice of struct pointers within a     struct
func main() {

    var d myData
    details := make(detailSlicePtr, ARBITRARY)

    for j := 0; j < ARBITRARY; j++ {
        details[j] = &detail{
            id:   j,
            name: strconv.Itoa(j),
        }
    }

    d.det = details

    // Print out what we have so far
    for index := range d.det {
        fmt.Printf("Item %d is %s\n", index, d.det[index].name)
    }
    // Print what is hidden
    for i := range d.det[len(d.det):cap(d.det)] {
        j := len(d.det) + i
        det := d.det[:cap(d.det)]
        fmt.Printf("Hidden item %d is %v\n", j, det[j])
    }

    findMe := ARBITRARY / 2
    middle := &detail{id: findMe, name: strconv.Itoa(findMe)}

    if ok := d.remove(middle); !ok {

        fmt.Printf("Unable to find element: %v\n", middle)

    } else {

        fmt.Printf("Found and removed element: %v\n", middle)

        // Print what is left
        for index := range d.det {
            fmt.Printf("Item %d is %s\n", index, d.det[index].name)
        }
        // Print what is hidden
        for i := range d.det[len(d.det):cap(d.det)] {
            j := len(d.det) + i
            det := d.det[:cap(d.det)]
            fmt.Printf("Hidden item %d is %v\n", j, det[j])
        }
    }
}

Output:

Item 0 is 0
Item 1 is 1
Item 2 is 2
Item 3 is 3
Item 4 is 4
Found and removed element: &{2 2}
Item 0 is 0
Item 1 is 1
Item 2 is 3
Item 3 is 4
Hidden item 4 is <nil>

NOTE: There is a bug in the Slice Tricks that you linked to. It will be corrected soon. Until then use the link in my answer.

\$\endgroup\$
  • \$\begingroup\$ Awesome, thank you. So just to check my understanding: In the remove method, use copy to basically push our element to the end, nil that index, assign our struct field to the new slice that is now 1 element shorter. So this frees the memory consumed by the target element, and shrinks our slice by 1, correct? I'm not sure how the show hidden loop is not causing a panic here. \$\endgroup\$ – cory.todd Jan 24 '15 at 20:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.