Skip to content

Commit

Permalink
Go 1.21: What's new?
Browse files Browse the repository at this point in the history
  • Loading branch information
MarioCarrion committed Oct 20, 2023
1 parent f98ffab commit 609b7c2
Show file tree
Hide file tree
Showing 20 changed files with 369 additions and 0 deletions.
2 changes: 2 additions & 0 deletions 2023/go-1-21-0/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PATH_add bin
export GOBIN=$PWD/bin
1 change: 1 addition & 0 deletions 2023/go-1-21-0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bin/
4 changes: 4 additions & 0 deletions 2023/go-1-21-0/01-godebug/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
example.tar
godebug
godebug-with
godebug-without
22 changes: 22 additions & 0 deletions 2023/go-1-21-0/01-godebug/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Backward behavior using GODEBUG

**Note** This example is using the code describing the new [tarinsecurepath security improvement added in Go 1.20](../../../02/03/06-archive-sec).

Excerpt from official release notes:

> Go 1.20 introduced support for rejecting insecure paths in tar and zip archives, controlled by the tarinsecurepath setting and the zipinsecurepath setting. These default to tarinsecurepath=1 and zipinsecurepath=1, preserving the behavior of earlier versions of Go. A future version of Go may change the defaults to tarinsecurepath=0 and zipinsecurepath=0.
## Demo

There are two parts to this demo, first you need to create the unsecure tar file and then run the binary in two different modes:
1. Using the `go:debug` directive and
1. Not using the `go:debug` directive

### Steps

1. Create unsecure tar file: `tar -cvf example.tar example ../../../../LICENSE`
1. Compile binary: `go build -o godebug .`
1. Run binary with and without **GODEBUG=tarinsecurepath=0**
1. Running it preserving the default Go: `./godebug`
1. Running it enabling the new behavior: `GODEBUG=tarinsecurepath=0 ./godebug`
1. If the `main` package is modified to include `//go:debug tarinsecurepath=0` then it will override to fail by default
1 change: 1 addition & 0 deletions 2023/go-1-21-0/01-godebug/example/one.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11111
1 change: 1 addition & 0 deletions 2023/go-1-21-0/01-godebug/example/two.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
22222
40 changes: 40 additions & 0 deletions 2023/go-1-21-0/01-godebug/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:debug tarinsecurepath=0

package main

import (
"archive/tar"
"fmt"
"io"
"log"
"os"
)

func main() {
f, err := os.Open("example.tar")

if err != nil {
log.Fatalf("open failed %v\n", err)
}
defer f.Close()

reader := tar.NewReader(f)

for {
hdr, err := reader.Next()
if err == io.EOF {
break
}

if err != nil {
log.Fatalf("reader.Next %v\n", err)
}

fmt.Printf("Contents of %s:\n", hdr.Name)
if _, err := io.Copy(os.Stdout, reader); err != nil {
log.Fatalf("io.Copy %v\n", err)
}

fmt.Println()
}
}
9 changes: 9 additions & 0 deletions 2023/go-1-21-0/02-new-built-in-funcs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# New built-in functions: min, max and clear.

Excerpt from official release notes:

> Go 1.21 adds three new built-ins to the language.
> * The new functions min and max compute the smallest (or largest, for max) value of a fixed number of given arguments. See the language spec for details.
> * The new function clear deletes all elements from a map or zeroes all elements of a slice. See the language spec for details.
37 changes: 37 additions & 0 deletions 2023/go-1-21-0/02-new-built-in-funcs/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import "fmt"

func main() {
// `min`

fmt.Println("min(1,0,-1) =", min(1, 0, -1)) // Outputs: -1
fmt.Println(`min("c","cat","a") =`, min("c", "cat", "a"), "\n") // Outputs: "a"

// `max`

fmt.Println("max(10,100,3) =", max(10, 100, 3)) // Outputs: 100
fmt.Println(`max("dat","xaz","xyz") =`, max("dat", "xaz", "xyz"), "\n") // Outputs: "xyz"

// `clear` using slice

strs := make([]string, 2)
strs[0] = "hello"
strs[1] = "world"

fmt.Printf("%#v - %p\n", strs, &strs) // []string{"hello", "world"}

clear(strs)
fmt.Printf("%#v - %p\n\n", strs, &strs) // []string{"", ""}

// `clear` using map

clients := make(map[string]int)
clients["mario"] = 99
clients["ruby"] = 89

fmt.Printf("%#v - %p\n", clients, &clients)
clear(clients)

fmt.Printf("%#v -%p\n", clients, &clients)
}
5 changes: 5 additions & 0 deletions 2023/go-1-21-0/03-slices/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# New `slices` package

Excerpt from official release notes:

> The new slices package provides many common operations on slices, using generic functions that work with slices of any element type.
26 changes: 26 additions & 0 deletions 2023/go-1-21-0/03-slices/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
"slices"
)

func main() {
// slices.Index
indexNumbers := []int{100, 2, 99, 2}
fmt.Println(`indexNumbers := []int{100, 2, 99, 2}`)
fmt.Println("\tslices.Index(indexNumbers, 1) =", slices.Index(indexNumbers, 1)) // Returns -1, not found
fmt.Println("\tslices.Index(indexNumbers, 2) =", slices.Index(indexNumbers, 2), "\n") // Returns 1

// slices.Sort
sortNumbers := []int64{100, 2, 99, 2}
slices.Sort(sortNumbers)
fmt.Println(`sortNumbers := []int64{100, 2, 99, 2}`)
fmt.Println("\tslices.Sort(sortNumbers) =", sortNumbers, "\n")

// slices.Min + slices.Max
minMaxNumbers := []int{100, 2, 99, 2}
fmt.Println(`minMaxNumbers := []int{100, 2, 99, 2}`)
fmt.Println("\tslices.Max(minMaxNumbers)", slices.Max(minMaxNumbers))
fmt.Println("\tslices.Min(minMaxNumbers)", slices.Min(minMaxNumbers))
}
5 changes: 5 additions & 0 deletions 2023/go-1-21-0/04-maps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# New `maps` package

Excerpt from official release notes:

> The new maps package provides several common operations on maps, using generic functions that work with maps of any key or element type.
41 changes: 41 additions & 0 deletions 2023/go-1-21-0/04-maps/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"fmt"
"maps"
)

func main() {
clients := map[string]int{
"mario": 99,
"ruby": 89,
}

fmt.Println(`clients := map[string]int{"mario": 99, "ruby": 89}`)

// Clone
cloned := maps.Clone(clients)
fmt.Printf("\tcloned = %v, clients = %v\n", cloned, clients)
fmt.Printf("\tcloned = %p, clients = %p\n", &cloned, &clients)

// Equal
fmt.Println("\n\tmaps.Equal(cloned, clients)", maps.Equal(clients, clients))

// Copy
dest := map[string]int{"mario": 0, "other": -1}
fmt.Println("\n", `dest := map[string]int{"mario": 0, "other": -1}`)

maps.Copy(dest, clients)
fmt.Println("\tmaps.Copy(clients, dest) =", dest)

// DeleteFunc
maps.DeleteFunc(dest, func(_ string, v int) bool {
if v > 90 {
return true
}

return false
})

fmt.Println("\tmaps.DeleteFunc(dest, v > 90) =", dest)
}
9 changes: 9 additions & 0 deletions 2023/go-1-21-0/05-context/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# New `context` functions

Excerpt from official release notes:

> The new `WithoutCancel` function returns a copy of a context that is not canceled when the original context is canceled.
> The new `WithDeadlineCause` and `WithTimeoutCause` functions provide a way to set a context cancellation cause when a deadline or timer expires. The cause may be retrieved with the `Cause` function.
> The new `AfterFunc` function registers a function to run after a context has been cancelled.
75 changes: 75 additions & 0 deletions 2023/go-1-21-0/05-context/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"context"
"fmt"
"time"
)

func main() {
ch := make(chan struct{})
ctx := context.Background()

// context.WithoutCancel

ctxTimeout, cancel := context.WithTimeout(ctx, time.Millisecond*10)
defer cancel()

ctxNoCancel := context.WithoutCancel(ctx)

select {
case <-ctxTimeout.Done():
fmt.Println("ctxTimeout.Error:", ctxTimeout.Err())
close(ch)
}

<-ch

fmt.Println("context.WithoutCancel=Error:", ctxNoCancel.Err())

// context.WithDeadlineCause (WithTimeoutCause works similarly)

fmt.Println("")

ch = make(chan struct{})
ctx = context.Background()

ctxDeadline, cancelDeadline := context.WithDeadlineCause(ctx, time.Now().Add(time.Millisecond*10), fmt.Errorf("deadline cause"))
defer cancelDeadline()

select {
case <-ctxDeadline.Done():
fmt.Println("ctxDeadline.Error:", ctxDeadline.Err())
close(ch)
}

<-ch

fmt.Println("context.WithDeadlineCause=Error:", ctxDeadline.Err())
fmt.Println("context.WithDeadlineCause=Cause:", context.Cause(ctxDeadline))

// context.AfterFunc

fmt.Println("")

ch = make(chan struct{})
ctx = context.Background()

ctxTimeout, cancelTimeout := context.WithTimeout(ctx, time.Millisecond*10)
defer cancelTimeout()

afterFunc := context.AfterFunc(ctxTimeout, func() {
fmt.Println("AfterFunc called")
close(ch)
})

select {
case <-ctxTimeout.Done():
fmt.Println("ctxTimeout.Error:", ctxTimeout.Err())
afterFunc()
}

<-ch

fmt.Println("context.WithTimeout=Error:", ctxDeadline.Err())
}
5 changes: 5 additions & 0 deletions 2023/go-1-21-0/06-sync-once/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# New `sync` functions

Excerpt from official release notes:

> The new `OnceFunc`, `OnceValue`, and `OnceValues` functions capture a common use of `Once` to lazily initialize a value on first use.
35 changes: 35 additions & 0 deletions 2023/go-1-21-0/06-sync-once/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"fmt"
"sync"
"time"
)

func main() {
// sync.OnceValue (sync.OnceValues works the same)

onceString := sync.OnceValue[string](func() string {
time.Sleep(time.Second)
return "sync.OnceValue: computed once!"
})

fmt.Println(time.Now(), onceString())
fmt.Println(time.Now(), onceString())
fmt.Println(time.Now(), onceString())

// sync.OnceFunc
fmt.Println("")

onceFunc := sync.OnceFunc(func() {
time.Sleep(time.Second)
fmt.Println("sync.OnceFunc: computed once!")
})

fmt.Println(time.Now())
onceFunc()
fmt.Println(time.Now())
onceFunc()
fmt.Println(time.Now())
onceFunc()
}
5 changes: 5 additions & 0 deletions 2023/go-1-21-0/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
install:
go install golang.org/dl/go1.21.0@latest
go1.21.0 download
mkdir -p bin/
ln -sf `pwd`/bin/go1.21.0 `pwd`/bin/go
43 changes: 43 additions & 0 deletions 2023/go-1-21-0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Go 1.21: What is new?

[<img src="https://github.com/MarioCarrion/MarioCarrion/blob/main/youtube.svg" width="20" height="20" alt="YouTube video"> Watch the video!](https://youtu.be/fO2a-5Wyh0I)

**NOTE** Install [`direnv`](https://mariocarrion.com/2020/11/20/golang-go-tool-direnv.html) and then run `make install` to install the version you get by using `go install`.

---

Go 1.21.0 was released on August 8th, 2023; this directory includes examples of some new features I consider worth mentioning added in this release.

* [@Golang Twitter announcement](https://twitter.com/golang/status/1688944844490539008)
* [Download](https://go.dev/dl/#go1.21)
* [Release notes](https://go.dev/doc/go1.21)
* [Official Blog Post](https://go.dev/blog/go1.21)
* [New API Changes for 1.21](https://github.com/golang/go/issues/60560)

* Other ways to use Go:
* Docker Images
* [All](https://hub.docker.com/_/golang/tags?page=1&name=1.21)
* [Debian Bookworm](https://hub.docker.com/layers/library/golang/1.21.0-bookworm/images/sha256-291849f9186a989b8f5bce22fd10c361d9e446d56ecf335c5f7e8572e98e45a9?context=explore) `docker pull golang:1.21.0-bookworm`
* [Alpine 3.18](https://hub.docker.com/layers/library/golang/1.21.0-alpine3.18/images/sha256-4c16f271b38a57f79514b432c329decc71af3868d914191ba767256e9c504e65?context=explore): `docker pull golang:1.21.0-alpine3.18`
* [Homebrew Formula PR](https://github.com/Homebrew/homebrew-core/pull/134468)

## New features

### Tool improvements

* [Backward behavior using GODEBUG](01-godebug/)

### Language changes

* [New built-in functions: min, max and clear](02-new-built-in-funcs/)

### Core library

* New `log/slog` package, this is _basically_ the same package as the one I covered [in a previous episode](../04/07/). You can watch that [video here](https://youtu.be/htbGdhW3JdQ).
* [New `slices` package](03-slices/)
* [New `maps` package](04-maps/)

### Minor changes to the library

* [New `context` functions](05-context)
* [New `sync` functions](06-sync-once)
3 changes: 3 additions & 0 deletions 2023/go-1-21-0/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/MarioCarrion/videos/2023/go-1-21

go 1.21

0 comments on commit 609b7c2

Please sign in to comment.