HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMinor

Remove element slice of struct pointers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
structremovepointerselementslice

Problem

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)
        }   
    }
}

Solution

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 


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.

Code Snippets

copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]
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])
        }
    }
}
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>

Context

StackExchange Code Review Q#78465, answer score: 5

Revisions (0)

No revisions yet.