Goblog--Arrays,slices(and strings):The mechanics of 'append'
2017-05-10 09:41
387 查看
Arrays
Arrays are not often seen in Go programs because the size of an array is part of its type, which limits its expressive power.The declaration
var buffer [256]byte
declares the variable buffer,which holds 256 bytes.
We can access its elements with the familiar indexing syntax,buffer[0], buffer[1] and so on through buffer[256].
There is a built-in function called len that returns the number of elements of an array or slice and also of a few other data types.
Arrays are a good representation of a transformation matrix for instace, but their most common purpose in Go is to hold storage for a slice.
The slice header
A slice is a data structure describing a contiguous section of an array stored separately from the slice variable itself. A slice describes a piece of an array.Given our buffer array variable from the previous sevtion, we could create a slice that describes emements 100 through 150 by slicing the array:
var slice []byte = buffer[100:150] var slice = buffer[100:150] slice := buffer[100:150]
What exactly is the slice variable?It’s not quite the full strory,but bow think of the slice being built like this behind the scenes:
type sliceHeader struct { Length int ZerothElement *byte }
slice := sliceHeader { Length: 50, ZerothElement: &buffer[100] }
Despite what this snippet says that sliceHeader struct is not visible to the programmer, and t
4000
he type of the element pointer depends on the type of the elements, but this gives the general idea of the mechanics.
Passing slices to functions
It’s important to understand that even though a slice contains a pointer,it is itself a value.Under the covers,it is a struct value holding a pointer and a length.It’s not a pointer to a struct.When we called IndexRune in the previous example,it was passed a copy of the slice header.
func AddOneToEachElement(slice []byte) { for 1:= range slice { slice[i]++ } } func main() { slice := buffer[10:20] for i := 0; i < len(slice); i++ { slice[i] = byte(i) } fmt.Println("before", slice) AddOneToEachElement(slice) fmt.Println("after",slice) }
the result:
before [0 1 2 3 4 5 6 7 8 9] after [1 2 3 4 5 6 7 8 9 10]
Even though the slice header is passed by value,the header includes a pointer to elements of an array, so both the original slice header and the copy of the header passed to the function describe the same array.Therefore, when function returns, the modified elements can be seen through the original slice variable.
The argument to the function really is a copy, as this example shows:
func SubtractOneFromLength(slice []byte) []byte { slice = slice[0 : len(slice)-1] return slice } func main() { fmt.Println("Before: len(slice) =", len(slice)) newSlice := SubtractOneFromLength(slice) fmt.Println("After: len(slice) = ", len(slice)) fmt.Println("After:len(newSlice) =", len(newSlice)) }
the result:
Before: len(slice) = 10 After: len(slice) = 10 After:len(newSlice) = 11
Here we see that the contents of a slice argument can be modified by a function, but its header cannot. The length stored in the slice variable is not modified by the call to the function, since the function is passed a copy of thr slice header, not the original. Thus if we want to write a function that modifies the header, we must return it as a result parameter, just as we have done here. The slice variable is unchanged but the returned value has the new length, which is then stored in newSlice.
Pointers to slices:Method recievers
Anthor way to have a function modify the slice header is to pass a pointer to it. Here’s a variant of our previous example that does this:type path []byte func (p path) ToUpper() { for i, b := range p { if 'a' <= b && b <= 'z' { p[i] = b + 'A' - 'a' } } } func main() { pathName := path("/usr/bin/tso") pathName.ToUpper() fmt.Printf("%s\n", pathName) }
Capacity
Besides the array pointer and length, the slice header also stores its capacity:type sliceHeader struct { Length int Capacity int ZerothElement *byte }
The Capacity field records how much space the underlying array actually has; it is the maximum value the Length can reach.
Make
We can’t grow the slice beyond its capacity,but we can achieve an equivalent result by allocating a new array, copying the data over, and modifying the slice to describe the new array.We could use the new built-in function to allocate a bigger array and then slice the result, but it is simpler to use the make built-in function instead.
slice := make([]int, 10, 15) newSlice := make([]int, len(slice), 2*cap(slice)) for i := range slice { newSlice[i] = slice[i] } slice = newSlice
Copy
Go has a built-in function, copy, which copies the data from the right-hand argument to the left-hand argument.The number of elements it copies is the minimum of the lengths of the two slices. Copy returns an integer value, the number of elements it copied.newSlice := make([]int, len(slice), 2*cap(slice)) copy(newSlice,slice)
Append: The built-in function
//Append appends the elements to the slice //Efficient version func append(slice []int, elements ...int) []int { n := len(slice) total := len(slice) + len(elements) if total > cap(slice) { newSize := total*3/2 + 1 newSlice := make([]int, total, newSize) copy(newSlice, slice) slice := newSlice } slice = slice[:total] copy(slice[n:], elements) return slice }
Go provides a built-in generic append function. It works the same as out int slice version, but for any slice type.
slice := []int{1,2,3} slice2 := []int{55,56,57} slice = append(slice, 4) slice2 = append(slice, slice2...) slice3 := append([]int(nil), slice...) slice = append(slice, slice)
Nil
A nil slice is the zero value of the slice header:sliceHeader{ Length: 0, Capacity: 0, ZerothElement: nil, }
or just
sliceHeader{}.
The slice created by
array[0:0].
- ####Strings
Strings are just read-only slices of bytes with a bit of extra syntactic support from the language.Because they are read-only, there is no need for a capacity (you can’t grow them), but otherwise for most purposes you can treat them just like read-only slices of bytes.
We can also take a normal slice of bytes and create a string from it with the simple conversion:
str := string(slice)
and go in reverse direction as well:
slice := []byte(str)
相关文章推荐
- Go语言学习之Arrays和Slices (The way to go)
- The day of blog
- The beginning of my blog.
- The Meaning of Open (from google's offical blog)
- javascript---the advantage of accessing the properties of object as array(objects as associative arrays)
- Customizing the Rendering of a Custom SPField (copy from todd's blog)
- Blog of the Day:几个中文技术类Blogger Groups
- [摘要]Pushing the Limits of Windows: Paged and Nonpaged Pool - From Mark Russinovich's blog
- [摘要]Pushing the Limits of Windows: Virtual Memory -- From Mark Russinovich's blog
- WordPress:Akismet ----Feel the Power of BlogEngine.NET Spam Filtering
- [摘要]Pushing the Limits of Windows: Physical Memory - From Mark Russinovich's blog
- Postscript III:The Operand Stack of PostScript: Arrays, Variables, Loops and Macro Definitions
- Go to study out of the dormitory again
- Go on talk about the process of developing software.
- A description of the blog
- Knowledge Representation in The Many Faces of Go
- Start The Life of Blog
- test of the blog
- Arrays(Chapter 6 of JavaScript: The Good Parts)
- The Popularity of Blog