This is a creation in Article, where the information may have evolved or changed.
Go provides a list package, like a python list, that can store any type of data and provide the appropriate APIs, as follows:
Type Element func (e *element) Next () *element func (e *element) Prev () *elementtype List func New () * List func (L *list) back () *element func (L *list) Front () *element func (L *list) Init () *list func (L *list) InsertAfter (v interface{}, Mark *element) *element func (L *list) insertbefore (v interface{}, Mark *element) *element Func (L *list) Len () int func (l *list) MoveAfter (E, Mark *element) func (L *list) MoveBefore (E, Mark *element) Func (L *list) movetoback (e *element) func (L *list) Movetofront (e *element) func (L *list) pushback (v interface{} ) *element func (L *list) pushbacklist (Other *list) func (L *list) Pushfront (v interface{}) *element func (L *lis T) pushfrontlist (other *list) func (L *list) Remove (e *element) interface{}
It is really handy to use the api,list provided with the list package, but in the process of using it, if you are not careful you will encounter some pits that are difficult to spot, resulting in a program that is not as expected. The pit here is the problem of traversing the list through a for loop and removing all elements. For example, the following example program creates a list, stores 0-3 sequentially, and then iterates through the list with a for loop to delete all the elements:
package mainimport ( "container/list" "fmt")func main() { l := list.New() l.PushBack(0) l.PushBack(1) l.PushBack(2) l.PushBack(3) fmt.Println("original list:") prtList(l) fmt.Println("deleted list:") for e := l.Front(); e != nil; e = e.Next() { l.Remove(e) } prtList(l)}func prtList(l *list.List) { for e := l.Front(); e != nil; e = e.Next() { fmt.Printf("%v ", e.Value) } fmt.Printf("\n")}
Run the program output as follows:
original list:0 1 2 3 deleted list:1 2 3
From the output you can know that the elements in the list are not completely deleted, only the first element 0 is deleted, and the original idea is not the same, according to the use of Go habits, walk a list and delete all the elements should be written as follows:
for e := l.Front(); e != nil; e = e.Next() { l.Remove(e)}
But according to the output of the example code above, it is not valid to delete all the elements of list, so what is the problem? The mechanism of the For loop knows that since the first element has been deleted, the second element has not been deleted, and the condition of the second loop must be invalid to cause the loop to exit, after executing the following statement:
l.Remove(e)
E should be nil, so the loop exits. The L in the for loop. Remove (e) statement before adding a print statement validation, such as adding the following statement:
fmt.Println("delete a element from list")
Run the program output as follows:
original list:0 1 2 3 deleted list:delete a element from list1 2 3
As you can see, it's really just a loop, and the loop ends. That is, when you finish executing the statement L. After Remove (e), E is equal to E. Next (), because E. Next () is nil, causing E to nil and the loop to exit. Why E. Next () will be nil? By looking at the Go List source, as shown below:
// remove removes e from its list, decrements l.len, and returns e.func (l *List) remove(e *Element) *Element { e.prev.next = e.next e.next.prev = e.prev e.next = nil // avoid memory leaks e.prev = nil // avoid memory leaks e.list = nil l.len-- return e}// Remove removes e from l if e is an element of list l.// It returns the element value e.Value.func (l *List) Remove(e *Element) interface{} { if e.list == l { // if e.list == l, l must have been initialized when e was inserted // in l or l == nil (e is a zero Element) and l.remove will crash l.remove(e) } return e.Value}
By the source can be seen when executing L. Remove (e), the L.remove (e) method is called internally to delete element E, in order to avoid a memory leak, the E.next and E.prev are assigned to nil, which is the source of the problem.
The correct procedure is as follows:
package mainimport ( "container/list" "fmt")func main() { l := list.New() l.PushBack(0) l.PushBack(1) l.PushBack(2) l.PushBack(3) fmt.Println("original list:") prtList(l) fmt.Println("deleted list:") var next *list.Element for e := l.Front(); e != nil; e = next { next = e.Next() l.Remove(e) } prtList(l)}func prtList(l *list.List) { for e := l.Front(); e != nil; e = e.Next() { fmt.Printf("%v ", e.Value) } fmt.Printf("\n")}
Run the program output as follows:
original list:0 1 2 3 deleted list:
As you can see, all the elements in the list have been deleted correctly.
This recommendation: simple logic
Simple logic.