add: slice internals backing array and slice header

This commit is contained in:
Inanc Gumus
2019-02-08 13:10:55 +03:00
parent ff4eb232d1
commit 04c5e2bec7
16 changed files with 642 additions and 36 deletions

View File

@ -0,0 +1,60 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"math/rand"
"time"
)
// ---------------------------------------------------------
// EXERCISE: Fix the backing array problem
//
// You receive numbers from an API. After you're done working
// with it, the API needs to continue using those numbers.
//
// But your program changes the numbers (changes the API's slice).
//
// Fix the program so that your program doesn't modify
// the original numbers.
//
//
// RESTRICTION
//
// Fix your problem only in the designated area of the code below.
//
//
// EXPECTED OUTPUT
//
// Mine : [-50 -100 -150]
// Original nums: [56 89 15]
//
// Note: Original nums may vary (they're random)
// But your slice should look like the above (mine slice)
//
// Yes, it should output only three numbers for the both slices!
//
// ---------------------------------------------------------
func main() {
// API returns random numbers in an int slice
rand.Seed(time.Now().UnixNano())
nums := rand.Perm(100)
// ----------------------------------------
// RESTRICTIONS — ONLY ADD YOUR CODE HERE
//
mine := nums
//
// ----------------------------------------
mine[0], mine[1], mine[2] = -50, -100, -150
fmt.Println("Mine :", mine)
fmt.Println("Original nums:", nums[:3])
}

View File

@ -0,0 +1,35 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
nums := rand.Perm(100)
// ----------------------------------------
// breaks the connection:
// mine and nums now have different backing arrays
// verbose solution:
// var mine []int
// mine = append(mine, nums[:3]...)
// better solution (almost the same thing):
mine := append([]int(nil), nums[:3]...)
// ----------------------------------------
mine[0], mine[1], mine[2] = -50, -100, -150
fmt.Println("Mine :", mine)
fmt.Println("Original nums:", nums[:3])
}

View File

@ -0,0 +1,52 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
)
// ---------------------------------------------------------
// EXERCISE: Sort the backing array
//
// 1. Sort only the middle 3 items.
//
// 2. All the slices should see your change.
//
//
// RESTRICTION
//
// Do not sort manually. Sort by slicing then by using the sort package.
//
//
// EXPECTED OUTPUT
//
// Original: [pacman mario tetris doom galaga frogger asteroids simcity metroid defender rayman tempest ultima]
//
// Sorted : [pacman mario tetris doom galaga asteroids frogger simcity metroid defender rayman tempest ultima]
//
//
// HINT:
//
// Middle items are : [frogger asteroids simcity]
//
// After sorting they become: [asteroids frogger simcity]
//
// ---------------------------------------------------------
func main() {
items := []string{
"pacman", "mario", "tetris", "doom", "galaga", "frogger",
"asteroids", "simcity", "metroid", "defender", "rayman",
"tempest", "ultima",
}
fmt.Println("Original:", items)
fmt.Println()
fmt.Println("Sorted :", items)
}

View File

@ -0,0 +1,33 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"sort"
)
func main() {
items := []string{
"pacman", "mario", "tetris", "doom", "galaga", "frogger",
"asteroids", "simcity", "metroid", "defender", "rayman",
"tempest", "ultima",
}
fmt.Println("Original:", items)
mid := len(items) / 2
smid := items[mid-1 : mid+2]
// sorting the smid will affect the items
// as well. their backing array is the same.
sort.Strings(smid)
fmt.Println()
fmt.Println("Sorted :", items)
}

View File

@ -0,0 +1,115 @@
package main
import (
"fmt"
"runtime"
"runtime/debug"
)
// ---------------------------------------------------------
// EXERCISE: Observe the memory allocations
//
// In this exercise, your goal is to observe the memory allocation
// differences between arrays and slices.
//
// You will create, assign arrays and slices then you will print
// the memory usage of your program on each step.
//
// Please follow the instructions inside the code.
//
//
// EXPECTED OUTPUT
//
// Note that, your memory usage numbers may vary. These are on my
// own system. However, the size of the arrays and slices should be
// the same on your own system as well (if you're on 64-bit machine).
//
//
// <<< initial memory usage >>>
// > Memory Usage: 104 KB
// <<< after declaring an array >>>
// > Memory Usage: 78235 KB
// <<< after copying the array >>>
// > Memory Usage: 156365 KB
// <<< inside passArray >>>
// > Memory Usage: 234495 KB
// <<< after slicings >>>
// > Memory Usage: 234497 KB
// <<< inside passSlice >>>
// > Memory Usage: 234497 KB
//
// Array's size : 80000000 bytes.
// Array2's size: 80000000 bytes.
// Slice1's size: 24 bytes.
// Slice2's size: 24 bytes.
// Slice3's size: 24 bytes.
//
//
// HINTS
//
// I've declared a few function to help you.
//
// report function prints the memory usage.
// Just call it with a message that matches to the expected output.
//
// passArray function accepts a [size]int array, so you can pass it
// your array. It automatically prints the memory usage.
//
// passSlice function accepts an int slice, so you can pass it
// your one of your slices. It automatically prints the memory usage.
//
// ---------------------------------------------------------
const size = 1e7
func main() {
// stops the gc: prevents cleaning up the memory
debug.SetGCPercent(-1)
// run the program to see what this prints
report("initial memory usage")
// 1. allocate an array with 10 million int elements
// this array's size is equal to ~80MB
// hint: use the `size` constant
//
// 2. print the memory usage
// 3. copy the array to a new array (just assign)
// 4. print the memory usage
// 5. pass the array to passArray function
// 6. convert the array to a slice (by slicing)
// 7. slice only the first 1000 elements of the array
// 8. slice only the elements of the array between 1000 and 10000
// 9. print the memory usage
// 10. pass the one of the slices to passSlice function
// 11. print the sizes of the arrays and slices
// hint: use the unsafe.Sizeof function
}
// observe that passing an array affects the memory usage dramatically
//
// passes [size]int array — about 80MB!
func passArray(items [size]int) {
items[0] = 100
report("inside passArray")
}
// observe that passing a slice doesn't affect the memory usage
//
// only passes 24-bytes of slice header
func passSlice(items []int) {
items[0] = 100
report("inside passSlice")
}
func report(msg string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("<<< %s >>>\n", msg)
fmt.Printf("\t> Memory Usage: %v KB\n", m.Alloc/1024)
}

View File

@ -0,0 +1,62 @@
// For more tutorials: https://blog.learngoprogramming.com
//
// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
package main
import (
"fmt"
"runtime"
"runtime/debug"
"unsafe"
)
const size = 1e7
func main() {
// stops the gc: prevents cleaning up the memory
debug.SetGCPercent(-1)
report("initial memory usage")
var array [size]int
report("after declaring an array")
array2 := array
report("after copying the array")
passArray(array)
slice1 := array[:]
slice2 := array[1e3:]
slice3 := array[1e3:1e4]
report("after slicings")
passSlice(slice3)
fmt.Println()
fmt.Printf("Array's size : %d bytes.\n", unsafe.Sizeof(array))
fmt.Printf("Array2's size: %d bytes.\n", unsafe.Sizeof(array2))
fmt.Printf("Slice1's size: %d bytes.\n", unsafe.Sizeof(slice1))
fmt.Printf("Slice2's size: %d bytes.\n", unsafe.Sizeof(slice2))
fmt.Printf("Slice3's size: %d bytes.\n", unsafe.Sizeof(slice3))
}
func passArray(items [size]int) {
items[0] = 100
report("inside passArray")
}
func passSlice(items []int) {
report("inside passSlice")
}
func report(msg string) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("<<< %s >>>\n", msg)
fmt.Printf("\t> Memory Usage: %v KB\n", m.Alloc/1024)
}

View File

@ -41,4 +41,14 @@ These are warm-up exercises that will reinforce your knowledge of slices.
2. **[Slicing by arguments](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/14-slicing-by-args)**
3. **[Slicing the Housing Prices](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/15-slicing-housing-prices)**
3. **[Slicing the Housing Prices](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/15-slicing-housing-prices)**
---
## Exercises Level IV - Internals
1. **[Fix the backing array problems](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/16-internals-backing-array-fix)**
2. **[Sort the backing array](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/17-internals-backing-array-sort)**
3. **[Observe the memory allocations](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/18-internals-slice-header)**