SliceTricks
Pages 127
- Home
- Articles
- Benchmarks
- Blogs
- Books
- BoundingResourceUse
- cgo
- ChromeOS
- CodeReview
- CodeReviewComments
- CodeTools
- Comments
- CommonMistakes
- CompilerOptimizations
- Conferences
- CoreDumpDebugging
- Courses
- CustomPprofProfiles
- Darwin
- DashboardBuilders
- DesignDocuments
- DevExp
- Diagnostics
- DragonFly BSD
- Errors
- ExperienceReports
- FileTreeDocumentation
- FreeBSD
- FromXToGo
- Gardening
- GccgoCrossCompilation
- GcToolchainTricks
- GerritAccess
- GithubAccess
- GitHubCodeLayout
- Go 1.6 release party
- Go 1.8 Release Party
- Go Release Cycle
- Go1point1Gotchas
- GoArm
- GoForCPPProgrammers
- GoGenerateTools
- GoGetProxyConfig
- GoGetTools
- Gomote
- GOPATH
- Gopher
- GoStrings
- GoTalks
- GoUserGroups
- GoUsers
- GoVsGenerics
- HandlingIssues
- Hashing
- heapdump13
- heapdump14
- heapdump15
- HostedContinuousIntegration
- HowToAsk
- HttpFetch
- HttpStaticFiles
- IDEsAndTextEditorPlugins
- InstallFromSource
- InstallTroubleshooting
- InterfaceSlice
- Iota
- IssueLabels
- Learn
- LearnConcurrency
- LearnErrorHandling
- LearnServerProgramming
- LearnTesting
- Linux
- LockOSThread
- MethodSets
- MinimumRequirements
- Mobile
- MultipleGoRoots
- MutexOrChannel
- NativeClient
- NetBSD
- NoMeToo
- NonEnglish
- OlderVersions
- OpenBSD
- PackageManagementTools
- PackagePublishing
- PanicAndRecover
- PerfDashboard
- Performance
- Plan9
- Podcasts
- PortingPolicy
- PriorDiscussion
- Projects
- ProviderIntegration
- Questions
- RaceDetector
- Range
- RateLimiting
- Rationales
- ResearchPapers
- Screencasts
- SendingMail
- Setting GOPATH
- SettingGOPATH
- SignalHandling
- SimultaneousAssignment
- SliceTricks
- Solaris
- SQLDrivers
- SQLInterface
- Style
- SubRepositories
- SuccessStories
- Switch
- TableDrivenTests
- Timeouts
- Training
- Ubuntu
- WebAccessibilityResourcesAndTips
- Well known struct tags
- WhyGo
- WindowsBuild
- WindowsCrossCompiling
- WindowsDLLs
- WindowsSupport
- Show 112 more pages…
Clone this wiki locally
Since the introduction of the append built-in, most of the functionality of the container/vector package, which was removed in Go 1, can be replicated using append and copy.
Here are the vector methods and their slice-manipulation analogues:
AppendVector
a = append(a, b...)Copy
b = make([]T, len(a))
copy(b, a)
// or
b = append([]T(nil), a...)Cut
a = append(a[:i], a[j:]...)Delete
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]Delete without preserving order
a[i] = a[len(a)-1]
a = a[:len(a)-1]
NOTE If the type of the element is a pointer or a struct with pointer fields, which need to be garbage collected, the above implementations of Cut and Delete have a potential memory leak problem: some elements with values are still referenced by slice a and thus can not be collected. The following code can fix this problem:
Cut
copy(a[i:], a[j:])
for k, n := len(a)-j+i, len(a); k < n; k++ {
a[k] = nil // or the zero value of T
}
a = a[:len(a)-j+i]Delete
copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]Delete without preserving order
a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]Expand
a = append(a[:i], append(make([]T, j), a[i:]...)...)Extend
a = append(a, make([]T, j)...)Insert
a = append(a[:i], append([]T{x}, a[i:]...)...)NOTE The second append creates a new slice with its own underlying storage and copies elements in a[i:] to that slice, and these elements are then copied back to slice a (by the first append). The creation of the new slice (and thus memory garbage) and the second copy can be avoided by using an alternative way:
Insert
s = append(s, 0)
copy(s[i+1:], s[i:])
s[i] = xInsertVector
a = append(a[:i], append(b, a[i:]...)...)Pop
x, a = a[0], a[1:]Pop Back
x, a = a[len(a)-1], a[:len(a)-1]Push
a = append(a, x)Push Front
a = append([]T{ x }, a...)Shift
x, a := a[0], a[1:]Unshift
a = append([]T{x}, a...)Additional Tricks
Filtering without allocating
This trick uses the fact that a slice shares the same backing array and capacity as the original, so the storage is reused for the filtered slice. Of course, the original contents are modified.
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}Reversing
To replace the contents of a slice with the same elements but in reverse order:
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}The same thing, except with two indices:
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}Shuffling
Fisher–Yates algorithm:
for i := len(a) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}