mirror of
https://gitlab.com/djdietrick/docs
synced 2026-05-03 03:50:54 -04:00
Compare commits
2 Commits
df494fbc70
...
15b2440d19
| Author | SHA1 | Date | |
|---|---|---|---|
| 15b2440d19 | |||
| d17eb8dfce |
46
docs/.vitepress/cache/deps/@theme_index.js
vendored
46
docs/.vitepress/cache/deps/@theme_index.js
vendored
@@ -9,31 +9,31 @@ import {
|
|||||||
} from "./chunk-3YS4HNIT.js";
|
} from "./chunk-3YS4HNIT.js";
|
||||||
|
|
||||||
// node_modules/vitepress/dist/client/theme-default/index.js
|
// node_modules/vitepress/dist/client/theme-default/index.js
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
|
||||||
|
|
||||||
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
|
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
|
||||||
import "C:/git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
|
import "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
|
||||||
import VPBadge from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
import VPBadge from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
||||||
import Layout from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
|
import Layout from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
|
||||||
import { default as default2 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
import { default as default2 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
|
||||||
import { default as default3 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
|
import { default as default3 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
|
||||||
import { default as default4 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
|
import { default as default4 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
|
||||||
import { default as default5 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
|
import { default as default5 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
|
||||||
import { default as default6 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
|
import { default as default6 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
|
||||||
import { default as default7 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
|
import { default as default7 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
|
||||||
import { default as default8 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
|
import { default as default8 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
|
||||||
import { default as default9 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
|
import { default as default9 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
|
||||||
import { default as default10 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
|
import { default as default10 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
|
||||||
import { default as default11 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
|
import { default as default11 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
|
||||||
import { default as default12 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
|
import { default as default12 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
|
||||||
import { default as default13 } from "C:/git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
|
import { default as default13 } from "/Users/djdietrick/Git/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
|
||||||
|
|
||||||
// node_modules/vitepress/dist/client/shared.js
|
// node_modules/vitepress/dist/client/shared.js
|
||||||
var inBrowser = typeof document !== "undefined";
|
var inBrowser = typeof document !== "undefined";
|
||||||
|
|||||||
16
docs/.vitepress/cache/deps/_metadata.json
vendored
16
docs/.vitepress/cache/deps/_metadata.json
vendored
@@ -1,31 +1,31 @@
|
|||||||
{
|
{
|
||||||
"hash": "cb1f9d5c",
|
"hash": "b31dd5f2",
|
||||||
"configHash": "9ebaad5b",
|
"configHash": "9af315cb",
|
||||||
"lockfileHash": "6f849b3a",
|
"lockfileHash": "951d497c",
|
||||||
"browserHash": "c342cb39",
|
"browserHash": "14d9b0dd",
|
||||||
"optimized": {
|
"optimized": {
|
||||||
"vue": {
|
"vue": {
|
||||||
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
|
||||||
"file": "vue.js",
|
"file": "vue.js",
|
||||||
"fileHash": "d958a5e2",
|
"fileHash": "9f6650f2",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
},
|
},
|
||||||
"vitepress > @vue/devtools-api": {
|
"vitepress > @vue/devtools-api": {
|
||||||
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
|
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
|
||||||
"file": "vitepress___@vue_devtools-api.js",
|
"file": "vitepress___@vue_devtools-api.js",
|
||||||
"fileHash": "7d35fe85",
|
"fileHash": "87d887f1",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
},
|
},
|
||||||
"vitepress > @vueuse/core": {
|
"vitepress > @vueuse/core": {
|
||||||
"src": "../../../../node_modules/@vueuse/core/index.mjs",
|
"src": "../../../../node_modules/@vueuse/core/index.mjs",
|
||||||
"file": "vitepress___@vueuse_core.js",
|
"file": "vitepress___@vueuse_core.js",
|
||||||
"fileHash": "c964aa0c",
|
"fileHash": "3179a954",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
},
|
},
|
||||||
"@theme/index": {
|
"@theme/index": {
|
||||||
"src": "../../../../node_modules/vitepress/dist/client/theme-default/index.js",
|
"src": "../../../../node_modules/vitepress/dist/client/theme-default/index.js",
|
||||||
"file": "@theme_index.js",
|
"file": "@theme_index.js",
|
||||||
"fileHash": "8c3760fb",
|
"fileHash": "1bd77338",
|
||||||
"needsInterop": false
|
"needsInterop": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export default {
|
|||||||
"/interview/": require("../interview/sidebar.json"),
|
"/interview/": require("../interview/sidebar.json"),
|
||||||
"/server/": require("../server/sidebar.json"),
|
"/server/": require("../server/sidebar.json"),
|
||||||
"/aws/": require("../aws/sidebar.json"),
|
"/aws/": require("../aws/sidebar.json"),
|
||||||
|
"/go": require("../go/sidebar.json"),
|
||||||
"/": [
|
"/": [
|
||||||
{
|
{
|
||||||
text: "Home",
|
text: "Home",
|
||||||
|
|||||||
173
docs/go/basics/collection.md
Normal file
173
docs/go/basics/collection.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
# Collections
|
||||||
|
|
||||||
|
## Arrays
|
||||||
|
|
||||||
|
Arrays in Go are fixed length and must be declared at initialization.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var a [10]int
|
||||||
|
a[0] = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Slices
|
||||||
|
|
||||||
|
A slice is like an array but it does not have a fixed size. You can further slice a slice be specifying a low and high index, inclusive of the first and exclusive of the last.
|
||||||
|
|
||||||
|
```go
|
||||||
|
primes := [6]int{2, 3, 5, 7, 11, 13}
|
||||||
|
|
||||||
|
var s []int = primes[1:4]
|
||||||
|
fmt.Println(s) // 3 5 7
|
||||||
|
s = primes[3:] // 7, 11, 13
|
||||||
|
s = primes[:2] // 2, 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Slices are references to an underlying array, so if you create a slice of an array and edit that slice, you will also edit the underlying array.
|
||||||
|
|
||||||
|
```go
|
||||||
|
names := [4]string{
|
||||||
|
"John",
|
||||||
|
"Paul",
|
||||||
|
"George",
|
||||||
|
"Ringo",
|
||||||
|
}
|
||||||
|
fmt.Println(names) // John Paul George Ringo
|
||||||
|
|
||||||
|
a := names[0:2]
|
||||||
|
b := names[1:3]
|
||||||
|
fmt.Println(a, b) // John Paul, Paul George
|
||||||
|
|
||||||
|
b[0] = "XXX"
|
||||||
|
fmt.Println(a, b) // John XXX, XXX George
|
||||||
|
fmt.Println(names) // John XXX George Ringo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Length vs Capacity
|
||||||
|
|
||||||
|
The length of a slice is how many items are actually stored in the array, and the capacity is how many slots the array has. A slice is considered a nil slice if it has 0 length and capacity and no underlying array.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := []int{2, 3, 5, 7, 11, 13}
|
||||||
|
printSlice(s)
|
||||||
|
|
||||||
|
// Slice the slice to give it zero length.
|
||||||
|
s = s[:0]
|
||||||
|
printSlice(s)
|
||||||
|
|
||||||
|
// Extend its length.
|
||||||
|
s = s[:4]
|
||||||
|
printSlice(s)
|
||||||
|
|
||||||
|
// Drop its first two values.
|
||||||
|
s = s[2:]
|
||||||
|
printSlice(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSlice(s []int) {
|
||||||
|
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
// len=6 cap=6 [2 3 5 7 11 13]
|
||||||
|
// len=0 cap=6 []
|
||||||
|
// len=4 cap=6 [2 3 5 7]
|
||||||
|
// len=2 cap=4 [5 7]
|
||||||
|
```
|
||||||
|
|
||||||
|
You can create slices with specific length and capacity using `make`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
x := make([]int, 0, 5) // len(x)=0, cap(x)=5
|
||||||
|
|
||||||
|
x = x[:cap(x)] // len(x)=5, cap(x)=5
|
||||||
|
x = x[1:] // len(x)=4, cap(x)=4
|
||||||
|
|
||||||
|
a := make([]int, 5)
|
||||||
|
// a len=5 cap=5 [0 0 0 0 0]
|
||||||
|
|
||||||
|
b := make([]int, 0, 5)
|
||||||
|
// b len=0 cap=5 []
|
||||||
|
|
||||||
|
c := b[:2]
|
||||||
|
// c len=2 cap=5 [0 0]
|
||||||
|
|
||||||
|
d := c[2:5]
|
||||||
|
// d len=3 cap=3 [0 0 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Appending
|
||||||
|
|
||||||
|
If the underlying array of the slice is too small to accommodate the new elements, the returned slice will point to a newly allocated array.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var s []int
|
||||||
|
// len=0 cap=0 []
|
||||||
|
|
||||||
|
// append works on nil slices.
|
||||||
|
s = append(s, 0)
|
||||||
|
// len=1 cap=1 [0]
|
||||||
|
|
||||||
|
// The slice grows as needed.
|
||||||
|
s = append(s, 1)
|
||||||
|
// len=2 cap=2 [0 1]
|
||||||
|
|
||||||
|
// We can add more than one element at a time.
|
||||||
|
s = append(s, 2, 3, 4)
|
||||||
|
// len=5 cap=6 [0 1 2 3 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Maps
|
||||||
|
|
||||||
|
Maps are key-value pairs. They can be created with `make`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Vertex struct {
|
||||||
|
Lat, Long float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var m map[string]Vertex // cannot be used
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
m = make(map[string]Vertex) // now can be used
|
||||||
|
m["Bell Labs"] = Vertex{
|
||||||
|
40.68433, -74.39967,
|
||||||
|
}
|
||||||
|
fmt.Println(m["Bell Labs"])
|
||||||
|
|
||||||
|
// Map literal
|
||||||
|
var n = map[string]Vertex{
|
||||||
|
"Bell Labs": Vertex{
|
||||||
|
40.68433, -74.39967,
|
||||||
|
},
|
||||||
|
"Google": Vertex{
|
||||||
|
37.42202, -122.08408,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shorthand
|
||||||
|
var o = map[string]Vertex{
|
||||||
|
"Bell Labs": {40.68433, -74.39967},
|
||||||
|
"Google": {37.42202, -122.08408},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manipulating the map
|
||||||
|
|
||||||
|
```go
|
||||||
|
m[key] = elem
|
||||||
|
elem = m[key]
|
||||||
|
delete(m, key)
|
||||||
|
|
||||||
|
// Check if element exists
|
||||||
|
elem, ok = m[key]
|
||||||
|
```
|
||||||
205
docs/go/basics/concurrency.md
Normal file
205
docs/go/basics/concurrency.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
# Cocurrency
|
||||||
|
|
||||||
|
One of the strengths of Go is the simplicity of its cocurrency paradigm. A `goroutine` is essentially a thread that gets managed by the runtime.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func say(s string) {
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
fmt.Println(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
go say("world")
|
||||||
|
say("hello")
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Channels
|
||||||
|
|
||||||
|
Channels are typed pipelines that you can send and receive values between goroutines. Sending and receiving through a channel block the thread until the otherside is ready.
|
||||||
|
|
||||||
|
```go
|
||||||
|
ch := make(chan int)
|
||||||
|
ch <- v // Send v to channel ch.
|
||||||
|
v := <-ch // Receive from ch, and assign value to v.
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func sum(s []int, c chan int) {
|
||||||
|
sum := 0
|
||||||
|
for _, v := range s {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
c <- sum // send sum to c
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s := []int{7, 2, 8, -9, 4, 0}
|
||||||
|
|
||||||
|
c := make(chan int)
|
||||||
|
go sum(s[:len(s)/2], c)
|
||||||
|
go sum(s[len(s)/2:], c)
|
||||||
|
x, y := <-c, <-c // receive from c
|
||||||
|
|
||||||
|
fmt.Println(x, y, x+y)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Buffering
|
||||||
|
|
||||||
|
Channels can also be buffered to allow senders to continue sending messages to a channel as long as the buffer is not full. Receivers block when the buffer is empty.
|
||||||
|
|
||||||
|
```go
|
||||||
|
ch := make(chan int, 100)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Closing
|
||||||
|
|
||||||
|
Channels can be closed to denote when no more values are going to be sent through the channel. Receivers can test for a closed channel by receiving a second parameter from the channel. `ok` will be false if the channel is closed. The sender should always close the channel, as sending on a closed channel will cause a panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
v, ok := <-ch
|
||||||
|
|
||||||
|
close(ch)
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be used with `range` to automatically receive the values from the channel and break the loop after the channel closes.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fibonacci(n int, c chan int) {
|
||||||
|
x, y := 0, 1
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
c <- x
|
||||||
|
x, y = y, x+y
|
||||||
|
}
|
||||||
|
close(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := make(chan int, 10)
|
||||||
|
go fibonacci(cap(c), c)
|
||||||
|
for i := range c {
|
||||||
|
fmt.Println(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Select
|
||||||
|
|
||||||
|
Select is like a switch statement for channels. It blocks until a condition occurs and then runs that condition. If multiple are ready at the same time it will choose randomly. You can add a default case to do something without blocking.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func fibonacci(c, quit chan int) {
|
||||||
|
x, y := 0, 1
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case c <- x:
|
||||||
|
x, y = y, x+y
|
||||||
|
case <-quit:
|
||||||
|
fmt.Println("quit")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func bomb() {
|
||||||
|
tick := time.Tick(100 * time.Millisecond)
|
||||||
|
boom := time.After(500 * time.Millisecond)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-tick:
|
||||||
|
fmt.Println("tick.")
|
||||||
|
case <-boom:
|
||||||
|
fmt.Println("BOOM!")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
fmt.Println(" .")
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := make(chan int)
|
||||||
|
quit := make(chan int)
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
fmt.Println(<-c)
|
||||||
|
}
|
||||||
|
quit <- 0
|
||||||
|
}()
|
||||||
|
fibonacci(c, quit)
|
||||||
|
bomb()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mutex
|
||||||
|
|
||||||
|
Mutexes can be used to pass variables to multiple goroutines and making sure only one can operate on it at a time.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SafeCounter is safe to use concurrently.
|
||||||
|
type SafeCounter struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
v map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inc increments the counter for the given key.
|
||||||
|
func (c *SafeCounter) Inc(key string) {
|
||||||
|
c.mu.Lock()
|
||||||
|
// Lock so only one goroutine at a time can access the map c.v.
|
||||||
|
c.v[key]++
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the current value of the counter for the given key.
|
||||||
|
func (c *SafeCounter) Value(key string) int {
|
||||||
|
c.mu.Lock()
|
||||||
|
// Lock so only one goroutine at a time can access the map c.v.
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.v[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := SafeCounter{v: make(map[string]int)}
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
go c.Inc("somekey")
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
fmt.Println(c.Value("somekey"))
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
108
docs/go/basics/control.md
Normal file
108
docs/go/basics/control.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# Control Flow
|
||||||
|
|
||||||
|
For the most part, control flow keywords in Go do not require parenthesis `()` for the conditional statements but do require brackets `{}` to contain the logic.
|
||||||
|
|
||||||
|
## For loops
|
||||||
|
|
||||||
|
For loops in Go are similar to C++ in that they have an inital, conditional, and post statement in the declaration. Initial and post statements are optional if not needed. In that case, this becomes Go's `while` loop. You can go even further by dropping the condition all together to create an forever loop.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sum := 0
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
sum += i
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// While
|
||||||
|
sum = 1
|
||||||
|
for sum < 1000 {
|
||||||
|
sum += sum
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
|
||||||
|
// Forever loop
|
||||||
|
for {
|
||||||
|
// repeats forever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the `range` keyword to iterate over a slice or map. With a slice, you will get both the index and a copy of the element for each iteration.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
|
||||||
|
for i, v := range pow { // i or v can be ignored with _
|
||||||
|
fmt.Printf("2**%d = %d\n", i, v)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## If/Else
|
||||||
|
|
||||||
|
If statements in Go can also include short statements to execute before the condition, and variables in these statements are scoped to the if/else block.
|
||||||
|
|
||||||
|
```go
|
||||||
|
func pow(x, n, lim float64) float64 {
|
||||||
|
if v := math.Pow(x, n); v < lim {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
else if v == lim {
|
||||||
|
fm.Printf("%g == %g\n", v, lim)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmt.Printf("%g >= %g\n", v, lim)
|
||||||
|
}
|
||||||
|
return lim
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Switch
|
||||||
|
|
||||||
|
In Go, only the matching case is run, meaning you do not need to include `break` like you would in C++. The switch case stops evaluating after one of the cases matches, so you can not run multiple cases even if it matches multiple. Switch can also be written with no condition, effectively turning it into a long if/else block.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
switch os := runtime.GOOS; os {
|
||||||
|
case "darwin":
|
||||||
|
fmt.Println("OS X.")
|
||||||
|
case "linux":
|
||||||
|
fmt.Println("Linux.")
|
||||||
|
default:
|
||||||
|
fmt.Printf("%s.\n", os)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
switch {
|
||||||
|
case t.Hour() < 12:
|
||||||
|
fmt.Println("Good morning!")
|
||||||
|
case t.Hour() < 17:
|
||||||
|
fmt.Println("Good afternoon.")
|
||||||
|
default:
|
||||||
|
fmt.Println("Good evening.")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Defer
|
||||||
|
|
||||||
|
Defer can be used to delay a function call until the surrounding function returns. Defers can be stacked, and will execute on a last-in, first-out order.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer fmt.Println("world")
|
||||||
|
|
||||||
|
fmt.Println("hello")
|
||||||
|
}
|
||||||
|
```
|
||||||
113
docs/go/basics/functions.md
Normal file
113
docs/go/basics/functions.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Functions
|
||||||
|
|
||||||
|
Functions are declared with the `func` keyword. They can have zero or more arguments, and the types of the arguments come after the names with a space. Functions can also return multiple values, and this is how error checking is done in Go. You can even instantiate the return values of the function in the function definition (only use in short functions).
|
||||||
|
|
||||||
|
By default, arguments are passed by value. To pass by reference, you need to take a pointer as the argument to modify the reference.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func add(x int, y int) int {
|
||||||
|
return x + y
|
||||||
|
}
|
||||||
|
|
||||||
|
func swap(x, y string) (string, string) {
|
||||||
|
return y, x
|
||||||
|
}
|
||||||
|
|
||||||
|
func split(sum int) (x, y int) {
|
||||||
|
x = sum * 4 / 9
|
||||||
|
y = sum - x
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(add(42, 13))
|
||||||
|
fmt.Println(swap("foo", "bar"))
|
||||||
|
fmt.Println(split(17))
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Functions can also be saved as variables and passed to other functions.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compute(fn func(float64, float64) float64) float64 {
|
||||||
|
return fn(3, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
hypot := func(x, y float64) float64 {
|
||||||
|
return math.Sqrt(x*x + y*y)
|
||||||
|
}
|
||||||
|
fmt.Println(hypot(5, 12))
|
||||||
|
|
||||||
|
fmt.Println(compute(hypot))
|
||||||
|
fmt.Println(compute(math.Pow))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Closures
|
||||||
|
|
||||||
|
Closures are functions that reference variables outside of the function body. In the below example, the inner function of `adder` has access to its own sum.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func adder() func(int) int {
|
||||||
|
sum := 0
|
||||||
|
return func(x int) int {
|
||||||
|
sum += x
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pos, neg := adder(), adder()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
fmt.Println(
|
||||||
|
pos(i),
|
||||||
|
neg(-2*i),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 0
|
||||||
|
// 1 -2
|
||||||
|
// 3 -6
|
||||||
|
// 6 -12
|
||||||
|
// 10 -20
|
||||||
|
// 15 -30
|
||||||
|
// 21 -42
|
||||||
|
// 28 -56
|
||||||
|
// 36 -72
|
||||||
|
// 45 -90
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generics
|
||||||
|
|
||||||
|
Functions can also take generic types with the below syntax. In the below example the generic type must implement the `comparable` constraint, meaning it has the `==` and `!=` operators.
|
||||||
|
|
||||||
|
```go
|
||||||
|
func Index[T comparable](s []T, x T) int {
|
||||||
|
for i, v := range s {
|
||||||
|
// v and x are type T, which has the comparable
|
||||||
|
// constraint, so we can use == here.
|
||||||
|
if v == x {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
```
|
||||||
19
docs/go/basics/packages.md
Normal file
19
docs/go/basics/packages.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Packages
|
||||||
|
|
||||||
|
Every Go program is made up of packages. When importing packages into a file, it is proper to use factored import statements, meaning combining all of the imports within parenthesis. The `main` package symbolizes code that will be run as a binary. Otherwise the package is a library.
|
||||||
|
|
||||||
|
Only names starting with Capital letters are exported from a package (public). Lowercase names will remain private within the package.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Now you have %g problems.\n", math.Sqrt(7))
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
25
docs/go/basics/pointers.md
Normal file
25
docs/go/basics/pointers.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Pointers
|
||||||
|
|
||||||
|
Pointers, like C++, hold memory addresses of a value. The zero value of a pointer is `nil`. Pointers are declared with `*T` which is a pointer to type T. The `&` operator creates a pointer to its operand. You can access the pointer value with `*` to get and set.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var p *int
|
||||||
|
i := 42
|
||||||
|
p = &i
|
||||||
|
fmt.Println(*p)
|
||||||
|
*p = 21
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structs
|
||||||
|
|
||||||
|
To access values of a struct you are referencing with a pointer, you can use the shorthand of the `.` operator to access the value.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Vertex struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
||||||
|
p := &Vertex{1,2}
|
||||||
|
fmt.Println(p.Y)
|
||||||
|
p.X = 4
|
||||||
|
```
|
||||||
164
docs/go/basics/struct.md
Normal file
164
docs/go/basics/struct.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
# Structs
|
||||||
|
|
||||||
|
Structs are collections of fields. They are defined as types and then created using brackets to declare the values.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Vertex struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
||||||
|
|
||||||
|
v := Vertex{1, 2}
|
||||||
|
v2 := Vertex{X: 2, Y: 4}
|
||||||
|
fmt.Println(v.X)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
Go does not have classes. Instead, functions can have `receivers` which relates to an instance of a struct and gets passed to the function. Methods can only be defined with a receiver that is in the same package, including built-in types.
|
||||||
|
|
||||||
|
By default, receivers are passed by value meaning any modifications to the receiver will not stick to the initial object. You can pass pointers as receivers to pass by reference and modify the reference. While functions require you to explicitly pass a pointer or a value, methods will automatically call the pointer method on a normal object and vice versa. In the below example, we call Scale on `v` and not `(%v).Scale(10)`. Pointer receivers also don't require you to copy the object which can be expensive for larger objects.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Vertex struct {
|
||||||
|
X, Y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vertex) Abs() float64 {
|
||||||
|
return math.Sqrt(v.X*v.X + v.Y*v.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Vertex) Scale(f float64) {
|
||||||
|
v.X = v.X * f
|
||||||
|
v.Y = v.Y * f
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
v := Vertex{3, 4}
|
||||||
|
fmt.Println(v.Abs()) // 5
|
||||||
|
v.Scale(10)
|
||||||
|
fmt.Println(v.Abs()) // 50
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interfaces
|
||||||
|
|
||||||
|
Interfaces are definitions of structs that all implement the declared methods. One note is that if the type implements the method with a pointer receiver, then the pointer to that class is considered that interface but the underlying type is not (If M took a \*T, then you would not be able to instantiate an instance of T as I).
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type I interface {
|
||||||
|
M()
|
||||||
|
}
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
S string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method means type T implements the interface I,
|
||||||
|
// but we don't need to explicitly declare that it does so.
|
||||||
|
func (t T) M() {
|
||||||
|
fmt.Println(t.S)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var i I = T{"hello"}
|
||||||
|
i.M()
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also check that a pointer is nil within the function to gracefully handle nil pointer exceptions at the function level.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type T struct {
|
||||||
|
S string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *T) M() {
|
||||||
|
if t == nil {
|
||||||
|
fmt.Println("<nil>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(t.S)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Empty Interfaces
|
||||||
|
|
||||||
|
Empty interfaces in Go are essentially an `any` type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var i interface{}
|
||||||
|
// (<nil>, <nil>)
|
||||||
|
|
||||||
|
i = 42
|
||||||
|
// (42, int)
|
||||||
|
|
||||||
|
i = "hello"
|
||||||
|
// (hello, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type any interface{}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type Assertions
|
||||||
|
|
||||||
|
To check if an instance of an interface is actually an instance of an underlying class, you can check with the below syntax.
|
||||||
|
|
||||||
|
```go
|
||||||
|
t := i.(T) // Will panic if not type T
|
||||||
|
|
||||||
|
t, ok := i.(T) // Returns T instance and true if that type, or zero-value of T and false if not
|
||||||
|
|
||||||
|
// With switch
|
||||||
|
switch v := i.(type) {
|
||||||
|
case T:
|
||||||
|
// here v has type T
|
||||||
|
case S:
|
||||||
|
// here v has type S
|
||||||
|
default:
|
||||||
|
// no match; here v has the same type as i
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Interfaces
|
||||||
|
|
||||||
|
#### Stringers
|
||||||
|
|
||||||
|
This is an object that has a function to describe itself as a string. Many functions from `fmt` look for this method.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Stringer interface {
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Errors
|
||||||
|
|
||||||
|
Return a string when the error occurs.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type error interface {
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
```
|
||||||
84
docs/go/basics/variables.md
Normal file
84
docs/go/basics/variables.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Variables and Types
|
||||||
|
|
||||||
|
Variables are declared using the `var` keyword or using the initial assignment operator `:=` (only inside functions). The type of the variable comes last, and can be inferred if using the assignment operator. Variables can be at the package or function level. You can also declare constants with the `const` keyword, but cannot use the `:=` operator. Numeric constants can be used for high precision.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var c, python, java bool
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var i int
|
||||||
|
j := 3 // int inferred
|
||||||
|
const k = "Can't change this"
|
||||||
|
const Big = 1 << 100 // 1 shifted left 100 times
|
||||||
|
fmt.Println(i, c, python, java)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
The basic types in go are:
|
||||||
|
|
||||||
|
- bool
|
||||||
|
- string
|
||||||
|
- int, int8, int16, int32, int64
|
||||||
|
- uint, uint8, uint16, uint32, uint64, uintptr
|
||||||
|
- byte (alias for uint8)
|
||||||
|
- rune (alias for int32, represents a Unicode code point)
|
||||||
|
- float32, float64
|
||||||
|
- complex64, complex128
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/cmplx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ToBe bool = false
|
||||||
|
MaxInt uint64 = 1<<64 - 1
|
||||||
|
z complex128 = cmplx.Sqrt(-5 + 12i)
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe) // bool, false
|
||||||
|
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt) // uint64, 18446744073709551615
|
||||||
|
fmt.Printf("Type: %T Value: %v\n", z, z) // complex128, (2+3i)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Default Values (Zero values)
|
||||||
|
|
||||||
|
When not given an initial value, the below types default to:
|
||||||
|
|
||||||
|
- bool - false
|
||||||
|
- string - ""
|
||||||
|
- numeric - 0
|
||||||
|
|
||||||
|
### Type Conversion
|
||||||
|
|
||||||
|
You can cast variables to different types by specifying the type in the below syntax.
|
||||||
|
|
||||||
|
```go
|
||||||
|
var i int = 42
|
||||||
|
var f float64 = float64(i)
|
||||||
|
var u uint = uint(f)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generic Types
|
||||||
|
|
||||||
|
Types can also be generic to work with multiple different types of arguments.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Singly linked list
|
||||||
|
type Node[T any] struct {
|
||||||
|
next *Node[T]
|
||||||
|
val T
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"text": "Go Basics",
|
"text": "Go Basics",
|
||||||
"items": [{ "text": "Introduction", "link": "/go/" }]
|
"items": [
|
||||||
|
{ "text": "Introduction", "link": "/go/" },
|
||||||
|
{ "text": "Packages", "link": "/go/basics/packages" },
|
||||||
|
{ "text": "Variables and Types", "link": "/go/basics/variables" },
|
||||||
|
{ "text": "Functions", "link": "/go/basics/functions" },
|
||||||
|
{ "text": "Control Flow", "link": "/go/basics/control" },
|
||||||
|
{ "text": "Collections", "link": "/go/basics/collection" },
|
||||||
|
{ "text": "Pointers", "link": "/go/basics/pointers" },
|
||||||
|
{ "text": "Structs", "link": "/go/basics/struct" },
|
||||||
|
{ "text": "Concurrency", "link": "/go/basics/concurrency" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,3 +3,5 @@
|
|||||||
[Python](/python/)
|
[Python](/python/)
|
||||||
|
|
||||||
[Rust](/rust/)
|
[Rust](/rust/)
|
||||||
|
|
||||||
|
[Go](/go/)
|
||||||
|
|||||||
Reference in New Issue
Block a user