Skip to content

Commit

Permalink
Go 1.23: What's new?
Browse files Browse the repository at this point in the history
  • Loading branch information
MarioCarrion committed Aug 31, 2024
1 parent 25bea82 commit b2afde2
Show file tree
Hide file tree
Showing 16 changed files with 420 additions and 0 deletions.
1 change: 1 addition & 0 deletions 2024/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

* [Go 1.22: What's new?](go-1-22-0/)
* [ Neovim configuration for Golang development using lazy.nvim and go.nvim](nvim-configuration/)
* [Go 1.23: What's new?](go-1-23-0/)
1 change: 1 addition & 0 deletions 2024/go-1-23-0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go123/
13 changes: 13 additions & 0 deletions 2024/go-1-23-0/01-range-over-func/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Range over func

Excerpt from official release notes:

> The "range" clause in a "for-range" loop now accepts iterator functions of the following types
>
> func(func() bool)
> func(func(K) bool)
> func(func(K, V) bool)
>
> as range expressions.
[Go Wiki: Rangefunc Experiment](https://go.dev/wiki/RangefuncExperiment)
113 changes: 113 additions & 0 deletions 2024/go-1-23-0/01-range-over-func/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package main

import (
"fmt"
"time"
)

// func(func() bool)
func Iter1() func(func() bool) {
return func(yield func() bool) {
var i int

for {
if !yield() {
return
}
i++

fmt.Println(i, time.Now())
}
}
}

// func(func(K) bool)
func Iter2() func(func(int) bool) {
return func(yield func(int) bool) {
var v int

for {
if !yield(v) {
return
}
v += 10
}
}
}

// func(func(K, V) bool)
func Iter3() func(func(int, int) bool) {
return func(yield func(int, int) bool) {
var v int

for {
if !yield(v, v+10) {
return
}
v++
}
}
}

func MultiplyBy2(vals ...int) []int {
res := make([]int, len(vals))
for i, v := range vals {
res[i] = v * 2
}
return res
}

func MultiplyBy2Iter(vals ...int) func(func(int, int) bool) {
return func(yield func(int, int) bool) {
for i, v := range vals {
if !yield(i, v*2) {
return
}
}
}
}

func main() {
var i = 0
for range Iter1() { // can't "for _ = range Basic()"
if i == 5 {
break
}
i++
time.Sleep(10 * time.Millisecond)
}

fmt.Println("---")

for v := range Iter2() {
if v == 50 {
break
}

fmt.Println(v, time.Now())
}

fmt.Println("---")

for i, v := range Iter3() {
if i == 5 {
break
}

fmt.Println(i, v, time.Now())
}

//-

fmt.Println("---")

for i, v := range MultiplyBy2(1, 2, 3, 4, 5, 6) {
fmt.Println(i, v)
}

fmt.Println("---")

for i, v := range MultiplyBy2Iter(1, 2, 3, 4, 5, 6) {
fmt.Println(i, v)
}
}
15 changes: 15 additions & 0 deletions 2024/go-1-23-0/02-unique/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# `unique` package

Excerpt from official release notes:

> The new unique package provides facilities for canonicalizing values (like
> “interning” or “hash-consing”).
>
> Any value of comparable type may be canonicalized with the new Make[T]
> function, which produces a reference to a canonical copy of the value in the
> form of a Handle[T]. Two Handle[T] are equal if and only if the values used
> to produce the handles are equal, allowing programs to deduplicate values and
> reduce their memory footprint. Comparing two Handle[T] values is efficient,
> reducing down to a simple pointer comparison.
[pkg.go.dev/unique](https://pkg.go.dev/unique)
29 changes: 29 additions & 0 deletions 2024/go-1-23-0/02-unique/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package main

import (
"fmt"
"unique"
)

// `comparable`
type User struct {
Name string
LastName string
}

// Not `comparable`
type Group struct {
Name string
Users []User
}

func main() {
h1 := unique.Make(User{Name: "Mario", LastName: "Carrion"})
h2 := unique.Make(User{Name: "Mario", LastName: "Carrion"})

fmt.Println("same values?", h1 == h2)
fmt.Printf("addresses: %v - %v\n", h1, h2)

// Group does not satisfy comparable
// g1 := unique.Make(Group{Name: "Mario",Users: []User{}})
}
8 changes: 8 additions & 0 deletions 2024/go-1-23-0/03-iter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# `iter` package

Excerpt from official release notes:

> Package iter provides basic definitions and operations related to iterators
> over sequences.
[pkg.go.dev/iter](https://pkg.go.dev/iter)
52 changes: 52 additions & 0 deletions 2024/go-1-23-0/03-iter/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"fmt"
"iter"
"time"
)

// iter.Seq[V any] func(yield func(V) bool) -- One value
// iter.Seq2[K, V any] func(yield func(K, V) bool) -- Two values: typically key-value or index-value pairs

// func(func(K, V) bool)
func Iter() func(func(int, int) bool) {
return func(yield func(int, int) bool) {
var v int

for {
if !yield(v, v+10) {
return
}
v++
}
}
}

func main() {
for i, v := range Iter() {
if i == 5 {
break
}

fmt.Println(i, v, time.Now())
}

//-

next, stop := iter.Pull2(Iter())
defer stop()

for {
i, v, ok := next()
if !ok {
break
}

if i == 5 {
break
}

fmt.Println(i, v, time.Now())
}
}
16 changes: 16 additions & 0 deletions 2024/go-1-23-0/04-slices/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# `slices` package changes

The `slices` package adds **9 functions** that support iterators:

* [All](https://go.dev/pkg/slices#All) returns an iterator over slice indexes and values.
* [AppendSeq](https://go.dev/pkg/slices#AppendSeq) appends values from an iterator to an existing slice.
* [Backward](https://go.dev/pkg/slices#Backward) returns an iterator that loops over a slice backward.
* [Chunk](https://go.dev/pkg/slices#Chunk) returns an iterator over consecutive sub-slices of up to n elements of a slice.
* [Collect](https://go.dev/pkg/slices#Collect) collects values from an iterator into a new slice.
* [Sorted](https://pkg.go.dev/slices#Sorted) Sorted collects values from seq into a new slice, sorts the slice, and returns it.
* [SortedFunc](https://go.dev/pkg/slices#SortedFunc) is like Sorted but with a comparison function.
* [SortedStableFunc](https://go.dev/pkg/slices#SortedStableFunc) is like SortFunc but uses a stable sort algorithm.
* [Sorted](https://go.dev/pkg/slices#Sorted) collects values from an iterator into a new slice, and then sorts the slice.
* [Values](https://go.dev/pkg/slices#Values) returns an iterator over slice elements.

[pkg.go.dev/slices](https://pkg.go.dev/slices)
32 changes: 32 additions & 0 deletions 2024/go-1-23-0/04-slices/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"fmt"
"slices"
)

func main() {
numbers := []string{"5", "4", "3", "2", "1"}
fmt.Printf("numbers = %v\n", numbers)

// slices.Chunk
fmt.Printf("\nslices.Chunk(numbers, 2)\n")
for c := range slices.Chunk(numbers, 2) {
fmt.Printf("\t%s\n", c)
}

// slices.Collect
fmt.Printf("\nslices.Collect(slices.Chunk(numbers, 2))\n")
numbers1 := slices.Collect(slices.Chunk(numbers, 2))
fmt.Printf("\t%s\n", numbers1)

// slices.Sorted + slices.Values
fmt.Printf("\nslices.Sorted(slices.Values(numbers))\n")
sorted := slices.Sorted(slices.Values(numbers))
fmt.Printf("\t%v\n", sorted)

fmt.Printf("\nslices.Backward(numbers)\n")
for i, v := range slices.Backward(numbers) {
fmt.Printf("\ti: %d, v: %s\n", i, v)
}
}
11 changes: 11 additions & 0 deletions 2024/go-1-23-0/05-maps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# `maps` package changes

The `maps` package adds **5 functions** that support iterators:

* [All](https://pkg.go.dev/maps#All) returns an iterator over key-value pairs from a map.
* [Collect](https://pkg.go.dev/maps#Collect) collects key-value pairs from an iterator into a new map and returns it.
* [Insert](https://pkg.go.dev/maps#Insert) adds the key-value pairs from an iterator to an existing map.
* [Keys](https://pkg.go.dev/maps#Keys) returns an iterator over keys in a map.
* [Values](https://pkg.go.dev/maps#Values) returns an iterator over values in a map.

[pkg.go.dev/maps](https://pkg.go.dev/maps)
28 changes: 28 additions & 0 deletions 2024/go-1-23-0/05-maps/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import (
"fmt"
"maps"
"slices"
)

func main() {
numbers := map[string]int{
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
}
fmt.Printf("numbers = %v\n", numbers)

// maps.Values
fmt.Printf("\nslices.Sorted(maps.Values(numbers))\n")
sortedValues := slices.Sorted(maps.Values(numbers))
fmt.Printf("\t%v\n", sortedValues)

// maps.Keys
fmt.Printf("\nslices.Sorted(maps.Keys(numbers))\n")
sortedKeys := slices.Sorted(maps.Keys(numbers))
fmt.Printf("\t%q\n", sortedKeys)
}
19 changes: 19 additions & 0 deletions 2024/go-1-23-0/06-minor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Minor changes to the library: `net/http.Request.Pattern` and `slices.Repeat`

## `net/http.Request.Pattern`

Excerpt from official release notes:

> Pattern is the `ServeMux` pattern that matched the request.
> It is empty if the request was not matched against a pattern.
[pkg.go.dev/net/http#Request.Pattern](https://pkg.go.dev/net/http#Request.Pattern)

## `net/http.Request.Pattern`

Excerpt from official release notes:

> Repeat returns a new slice that repeats the provided slice the given number
> of times.
[pkg.go.dev/slices#Repeat](https://pkg.go.dev/slices#Repeat)
43 changes: 43 additions & 0 deletions 2024/go-1-23-0/06-minor/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main_test

import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"slices"
"testing"
)

func TestMe(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("GET /hi", func(w http.ResponseWriter, req *http.Request) {
// New function: slices.Repeat + http.Request.Pattern
v, _ := json.Marshal(slices.Repeat([]string{req.Pattern}, 2))
w.Write(v)
})

server := httptest.NewServer(mux)

req, err := http.NewRequest(http.MethodGet, server.URL+"/hi", nil)
if err != nil {
t.Fatalf("new request: %v", err)
}

client := http.Client{}
resp, err := client.Do(req)
if err != nil {
t.Fatalf("do failed: %v", err)
}
defer resp.Body.Close()

val, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("do failed: %v", err)
}

valStr := string(val)
if valStr != `["GET /hi","GET /hi"]` {
t.Fatalf("invalid value: %v", valStr)
}
}
Loading

0 comments on commit b2afde2

Please sign in to comment.