Today is the weekend, although it is only one day. Let me share with you a little news about Go1.17. Gain a fish-attracting skill every day!
In the Go language, a slice contains a reference to its supporting array, whether the array exists somewhere as an independent variable, or is just an array allocated to support slicing. anonymous array.
The basic structure of slicing is as follows:
// runtime/slice.go type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 长度 cap int // 容量 }
The current way of slicing to support arrays may cause interesting memory leaks in slicing or produce surprising changes to your slicing.
Another very important point is that in Go 1.16 and before, there is no safe method to convert from slice type to array type, which is quite helpless.
We can only do this by calling the standard library reflect or unsafe and writing unsafe code:
(*[10]byte)(unsafe.Pointer(&b[0]))
Obviously this is not elegant, and the official itself does not recommend using unsafe , once the processing goes wrong, it may lead to fatal errors, which is relatively uncontrollable.
In fact, as early as 2009, shortly after Go was released (long before Go 1.0 was released), some people raised relevant doubts and hoped to solve this problem:
Finally, in the upcoming Go 1.17, this will be possible thanks to a series of changes starting with commit-id #1c268431f4, which updates the specification:
The description of this in the new specification is very straightforward:
Converting a slice to an array pointer yields a pointer to the underlying array of the slice. If the length of the slice is less than the length of the array, a run-time panic occurs.
- If the slice is longer than the length of the array, it is harmless and can run normally.
- If the slice is longer than the array, it means that your array will not be able to access all the supporting arrays of the original slice.
In addition, the specification provides some new examples, which we can use in Go1.17:
s := make([]byte, 2, 4) s0 := (*[0]byte)(s) // s0 != nil s2 := (*[2]byte)(s) // &s2[0] == &s[0] s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s) var t []string t0 := (*[0]string)(t) // t0 == nil t1 := (*[1]string)(t) // panics: len([1]string) > len(s)
- Conversion of variable s2: It will slice the underlying array Converted out, this conversion does not (and cannot) allocate a new array, thus ensuring its efficiency.
- Conversion of variables s0 and t0: It converts a non-empty fragment into a 0-length array. Although you can't do anything with an array of length 0, you still have to give it a valid pointer, which is nil.
It should be noted that there is currently no way to check whether a panic event will occur due to out-of-bounds reasons like type assertion. If you think you may have a snippet that is too short and may cause a panic event, then you need to use if to pre-determine.
At the same time, the standard library reflect will also be updated to support conversion from slices to array pointers. If you are using reflect to do related conversion work, it is recommended to read the notes in this submission.
Do you have any other ideas and demands on type conversion in Go language, or have you encountered any pitfalls?
We welcome everyone to leave messages and communicate in the comment area.