Go iteration slices (iterating over Slices in Go)

Source: Internet
Author: User
Tags mathematical functions
Slices are available everywhere in my code. If I am using data from MongoDB, it will be stored in the slice. If I need to track a series of problems after running the operation, it will be stored in a slice. If you don't know how slices work, or if you avoid using slices as I did at the beginning, read these two articles for more information. [Understanding slice in Go] (http://www.goinggo.net/2013/08/understanding-slices-in-go-programming.html) [Set of indefinite lengths in Go] (https://studygolang.com/articles/14132) One of the questions I often ask myself when coding is, "Do I want to use a pointer to this value or do I want to make a copy?" "While Go can be used as a functional programming language, it is essentially a command-type programming language. What's the difference? Functional programming languages do not allow you to change a variable or value after it is created and initialized. This means that the variables and values are immutable and they cannot be changed. If you need to change the state or value of a variable, you must create a copy and initialize the copy to the changed variable and value. The function is always a passing copy, and the return value is always a copy. In an imperative programming language, we can create variable or changeable variables and values. We can pass pointers to functions for any variable or value, and the function can change the state as needed. Functional programming languages expect you to think in terms of mathematical functions that input and produce results. In an imperative programming language, we can build similar functions, but we can also build functions that perform operations on states that can exist anywhere in memory. Being able to use pointers has advantages, but it can also get you into trouble. Using pointers reduces memory constraints and improves performance as much as possible. But it creates synchronization problems, such as shared access to values and resources. Find the solution that works best for each use case. For your Go program, I recommend using pointers when it's safe and practical. Go is a command-based programming language, so take advantage of it. In Go, everything is passed by value, and it's important to remember that. We can pass the address of the object by value, or pass a copy of the object by value. When we use pointers in Go, it is sometimes confusing because go handles all of our references. Don't get me wrong, go to do this is great, but sometimes you can forget the actual value of the variable. At some point in each program, I need to iterate over a slice to do some work. In Go, we use the For loop structure to iterate over the slices. At the beginning, I made some very serious mistakes in iterating over the slices because I misunderstood how the range keyword works. I'm going to show you an annoying mistake that ICreated an iterative slicing feature that confused me. Now it's obvious to me why the code was wrong, but I didn't know why. Let's create some simple values and put them in a slice. Then we'll iterate over the slices to see what happens. ' Gopackage mainimport ("FMT") type Dog struct {Name string Age Int}func main () {jackie: = dog{Name: "Jackie", age:19 ,} FMT. Printf ("Jackie Addr:%p\n", &jackie) Sammy: = dog{Name: "Sammy", Age:10,} fmt. Printf ("Sammy Addr:%p\n", &sammy) Dogs: = []dog{jackie, Sammy} fmt. Println ("") for _, Dog: = Range Dogs {fmt. Printf ("Name:%s Age:%d\n", dog.) Name, dog. Age) Fmt. Printf ("Addr:%p\n", &dog) fmt. Println ("")}} "This program creates two types of dog-only objects and puts them into the dog-type slice dogs. We show the address of each dog. We then iterate over the slices showing each dog's name, age and address. This is the output of the program: "' Jackie addr:0x2101bc000sammy addr:0x2101bc040name:jackie age:19addr:0x2101bc060name:sammy age:10addr:0 x2101bc060 "So why is the value of a dog different in the loop, and why does the same address appear two times? All of this is related to the fact that the value of Go is passed. In this code example, we actually created 2 additional copies of each Dog in memory. [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/iterating-over-slices-in-go/ Iterating-over-slices-in-go.png) The initial existence of each DOG is created using a composite field: "Gojackie: = dog{Name:" Jackie ", Age:19,} ' will create the first copy of the value when the value is placed in the slice: ' ' godogs: = []dog{jackie, Sammy} ' when we traverse the slice, we create a second copy of the value: ' ' Godog: = Range dogs ' ' Now we can see why the address of the variable dog in the loop is always the same. We are showing the address of the variable dog, which happens to be a local variable of type A, which contains a copy of the dog for each index of the slice. For each iteration of the slice, the address of the variable dog is the same. The value of the variable dog is changing. The nasty mistake I talked about with I think that the variable dog's address can be used as a pointer to each dog value in the slice. Something like this: "' goalldogs: = []*dog{}for _, Dog: = Range Dogs {alldogs = append (Alldogs, &dog)}for _, Dog: = Range Alldogs {FMT. Printf ("Name:%s Age:%d\n", dog.) Name, dog. Age)} "I created a new slice that holds a pointer to the DOG value. Then I traverse dogs, storing the address of each DOG value into the new slice alldogs. At least I think I've stored the address of each Dog value. If I add this code to the program and run it, this is the output: ' ' name:sammy age:10name:sammy age:10 ' I finally get a slice where each element has the same address. This address points to a copy of the last value of our iteration. Oh! If making all of these copies is not what you want, you can use pointers. The following is a sample program that uses pointers: "' Gopackage mainimport (" FMT ") type Dog struct {name string Age Int}func main () {jackie: = &dog{Name: "Jackie", Age:19,} fmt. Printf ("Jackie Addr:%p\n", Jackie) Sammy: = &dog{Name: "Sammy", Age:10,} fmt. Printf ("Sammy Addr:%p\n\n", Sammy) Dogs: = []*dog{jackie, Sammy} for _, Dog: = Range Dogs {FMt. Printf ("Name:%s Age:%d\n", dog.) Name, dog. Age) Fmt. Printf ("Addr:%p\n\n", dog)} "" This is the output: ' ' Jackie addr:0x2101bb000sammy addr:0x2101bb040name:jackie age:19addr:0x2101b B000name:sammy age:10addr:0x2101bb040 ' ' This time we create a pointer to the DOG value. When we traverse this slice, the value of the variable dog is the address of each dog value that we store in the slice. Instead of creating two additional copies for each dog value, we use the same initial dog value created with compound text. The range loop is the same when the slice is a collection of dog values or a pointer collection of dog values. "' Gofor _, Dog: = Range Dogs {fmt. Printf ("Name:%s Age:%d\n", dog.) Name, dog. Age)} "regardless of whether we use pointers, go will handle access to the Dog value. It's great, but sometimes it leads to some confusion. At least that's the way it started for me. I can't tell you when you should use a pointer or when you should use a copy. But keep in mind that Go will deliver everything by value. This includes function parameters, return values, and iterations on a slice, map, or channel. Yes, you can also traverse a channel. Look at the sample code I adapted in the blog post written by Ewen Cheslack-postava: [http://ewencp.org/blog/golang-iterators/] (http://ewencp.org/blog/ golang-iterators/) "Gopackage mainimport (" FMT ") type Dog struct {Name string age int}type dogcollection struct {Data [ ]*dog}func (This *dogcollection) Init () {cloey: = &dog{"Cloey", 1} Ralph: = &dog{"Ralph", 5} Jackie: = &dog{" Jackie ", ten} Bella: = &dog{" Bella ", 2} Jamie: = &dog{"Jamie", 6} this. Data = []*dog{cloey, Ralph, Jackie, Bella, Jamie}}func (this *dogcollection) Collectionchannel () Chan *dog {datachannel: = Make (Chan *dog, Len (this). Data)) For _, Dog: = Range this. Data {Datachannel <-dog} close (Datachannel) return Datachannel}func main () {DC: = dogcollection{} DC. Init () for dog: = Range DC. Collectionchannel () {fmt. Printf ("Channel Name:%s\n", dog.) Name)}} ' If you run the program, you will get the following output: ' ' Channel name:cloeychannel name:ralphchannel name:jackiechannel Name:bellachannel Name:jamie ' I really like this sample code because it shows the beauty of the closed channel. The key to making the program effective is that the closed channel is always in a signaled state. This means that any read on the channel will return immediately. If the channel is empty, the default value is returned. This allows range to iterate through all the data passed to the channel and complete when the channel is empty. Once the channel is empty, the next read on the channel returns nil. This causes the loop to terminate. The slices are very good, light weight and powerful. You should use them and get the benefits they provide. Keep in mind that when you iterate over a slice, you get a copy of each element of the slice. If this happens to be an object, you will get a copy of the object. Do not use the address of the local variable in the loop. This is a local variable that contains a copy of the slice element, and only the content. Don't make the same mistake as I do.

Via:https://www.ardanlabs.com/blog/2013/09/iterating-over-slices-in-go.html

Author: William Kennedy Translator: lfasmike proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

127 reads
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.