0% found this document useful (0 votes)
102 views69 pages

(2022) Generics, Reflection, and Efficient Collections (GoLab Edition)

The document discusses predefined collection types in Go including arrays, slices, strings, maps, and channels. It provides code examples of using each type and demonstrates their basic functionality and behaviors.

Uploaded by

feyeleanor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
102 views69 pages

(2022) Generics, Reflection, and Efficient Collections (GoLab Edition)

The document discusses predefined collection types in Go including arrays, slices, strings, maps, and channels. It provides code examples of using each type and demonstrates their basic functionality and behaviors.

Uploaded by

feyeleanor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 69

Talk’s Name- Speaker

Generics,
Reflection,
15/09/2022

and
Efficient Collections
Eleanor McHugh
ELEANOR MCHUGH
GENERICS, REFLECTION,
AND EFFICIENT COLLECTIONS
PORTRAIT OF A HACKER...

PORTRAIT OF A HACKER...
/G o Note b o o k
▸ physics leanp u b : /

▸ cryptography

g ithub://feye
an o r
▸ embedded systems

eye le
▸ dynamic languages

e : //f

leanor
▸ dns provisioning

sli deshar
▸ network scaling

▸ highly questionable taste in music McH u g h


Eleanor
github://feyeleanor/

GoGenericsTalk
PREDEFINED COLLECTION TYPES IN GO
ARRAYS
001_array.go 002_array.go

package main package main

import "fmt" func main() {


var a [3]int
func main() {
var a [3]int _ = append(a, 1)
}
fmt.Println("len(a):", len(a))
fmt.Println("cap(a):", cap(a)) go run 002_array.go
fmt.Printf("a: %v (%T)\n", a, a) # command-line-arguments
fmt.Printf("a[1]: %v (%T)\n", a[1], a[1]) ./002_array.go:6:13: first argument to append must be a slice;
fmt.Printf("a[0:1]: %v (%T)\n", a[0:1], a[0:1]) have a (variable of type [3]int)

a = [3]int{3, 2, 1}
fmt.Printf("a: %v (%T)\n", a, a)
a[0] = a[1]
for i, v := range a {
fmt.Printf("a[%v]: %v\n", i, v)
}
}

go run 001_array.go
len(a): 3
cap(a): 3
a: [0 0 0] ([3]int)
a[1]: 0 (int)
a[0:1]: [0] ([]int)
a: [3 2 1] ([3]int)
a[0]: 2
a[1]: 2
a[2]: 1
SLICES
003_slice.go 004_slice.go

package main package main

import "fmt" import "fmt"

func main() { func main() {


var s []int var s []int

fmt.Println("len(s):", len(s)) s = append(s, 0, 1, 2)


fmt.Println("cap(s):", cap(s)) fmt.Printf("s: %v (%T)\n", s, s)
fmt.Printf("s: %v (%T)\n", s, s) fmt.Printf("s[:1]: %v (%T)\n", s[:1], s[:1])
fmt.Printf("s[0:1]: %v (%T)\n", s[0:1], s[0:1]) fmt.Printf("s[1:]: %v (%T)\n", s[1:], s[1:])
} s = append(s, s...)
fmt.Printf("s: %v (%T)\n", s, s)
go run 003_slice.go s = make([]int, 3, 6)
len(s): 0 fmt.Printf("s: %v (%T)\n", s, s)
cap(s): 0 s = []int{2, 4, 6}
s: [] ([]int) s[1] = s[2]
panic: runtime error: slice bounds out of range [:1] with for i, v := range s {
capacity 0 fmt.Printf("s[%v]: %v\n", i, v)
}
goroutine 1 [running]:
main.main() }
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/003_slice.go:11 +0x171 go run 004_slice.go
exit status 2 s: [0 1 2] ([]int)
s[:1]: [0] ([]int)
s[1:]: [1 2] ([]int)
s: [0 1 2 0 1 2] ([]int)
s: [0 0 0] ([]int)
s[0]: 2
s[1]: 6
s[2]: 6
SLICES
005_string.go 006_string.go

package main package main

import "fmt" import "fmt"

func main() { func main() {


var s string s := "abc"
fmt.Println("len(s):", len(s))
fmt.Println("len(s):", len(s)) fmt.Printf("s: %v (%T)\n", s, s)
fmt.Printf("s: %v (%T)\n", s, s) fmt.Printf("s[0:1]: %v (%T)\n", s[0:1], s[0:1])
fmt.Printf("s[0:1]: %v (%T)\n", s[0:1], s[0:1]) s = "cba"
} for i, v := range s {
fmt.Printf("s[%v]: %v (%T)\n", i, v, v)
go run 005_string.go }
len(s): 0 b := []byte(s)
s: (string) for i, v := range b {
panic: runtime error: slice bounds out of range [:1] with length fmt.Printf("b[%v]: %v (%T)\n", i, v, v)
0 }
}
goroutine 1 [running]:
main.main() go run 006_string.go
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ len(s): 3
GoGenericsTalk/005_string.go:10 +0xf1 s: abc (string)
exit status 2 s[0:1]: a (string)
s[0]: 99 (int32)
s[1]: 98 (int32)
s[2]: 97 (int32)
b[0]: 99 (uint8)
b[1]: 98 (uint8)
b[2]: 97 (uint8)
MAPS
007_map.go 008_map.go

package main package main

import "fmt" import "fmt"

func main() { func main() {


var m map[int]int var m map[int]int

fmt.Println("len(m):", len(m)) m = make(map[int]int)


fmt.Println("m[1]", m[1]) m[1] = 1
m[1] = 1 fmt.Println("m[1]:", m[1])
} delete(m, 1)
fmt.Println("m:", m)
go run 007_map.go x, ok := m[1]
len(m): 0 fmt.Printf("x: %v, ok: %v\n", x, ok)
m[1] 0 m = map[int]int{0: 2, 3: 6}
panic: assignment to entry in nil map fmt.Println("m:", m)
for k, v := range m {
goroutine 1 [running]: fmt.Printf("m[%v]: %v\n", k, v)
main.main() }
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ }
GoGenericsTalk/005_map.go:10 +0xf9
exit status 2 go run 008_map.go
m[1]: 1
m: map[]
x: 0, ok: false
m: map[0:2 3:6]
m[0]: 2
m[3]: 6
CHANNELS
009_channel.go

package main go run 009_channel.go


# command-line-arguments
import "fmt" ./007_channel.go:15:3: invalid operation: cannot send to
receive-only channel c (variable of type <-chan int)
func main() { ./007_channel.go:17:8: invalid operation: cannot close receive-
var c chan int only channel c (variable of type <-chan int)
./007_channel.go:21:17: cannot range over c (variable of type
c = make(chan int) chan<- int) (receive from send-only channel)
go send(c, 0, 2, 4, 6)
receive(c)
}

func send(c <-chan int, v ...int) {


for _, n := range v {
c <- n
}
close(c)
}

func receive(c chan<- int) {


for n := range c {
fmt.Println("n:", n)
}
}
CHANNELS
010_channel.go

package main go run 010_channel.go


cap(c): 0
import "fmt" sending: 0
sending: 2
func main() { len(c): 0, n: 0
var c chan int len(c): 0, n: 2
sending: 4
c = make(chan int) sending: 6
fmt.Println("cap(c):", cap(c)) len(c): 0, n: 4
go send(c, 0, 2, 4, 6) len(c): 0, n: 6
receive(c)
}

func send(c chan<- int, v ...int) {


for _, n := range v {
fmt.Println("sending:", n)
c <- n
}
close(c)
}

func receive(c <-chan int) {


for n := range c {
fmt.Printf("len(c): %v, n: %v\n", len(c), n)
}
}
CHANNELS
011_channel.go

package main go run 011_channel.go


cap(c): 16
import "fmt" sending: 0
sending: 2
func main() { sending: 4
var c chan int sending: 6
len(c): 3, n: 0
c = make(chan int, 16) len(c): 2, n: 2
fmt.Println("cap(c):", cap(c)) len(c): 1, n: 4
go send(c, 0, 2, 4, 6) len(c): 0, n: 6
receive(c)
}

func send(c chan<- int, v ...int) {


for _, n := range v {
fmt.Println("sending:", n)
c <- n
}
close(c)
}

func receive(c <-chan int) {


for n := range c {
fmt.Printf("len(c): %v, n: %v\n", len(c), n)
}
}
CHANNELS
012_channel.go

package main

import "fmt"

func main() {
var c chan int

c = make(chan int, 16)


go func(c chan<- int, v ...int) {
for _, n := range v {
fmt.Println("sending:", n)
c <- n
}
close(c)
}(c, 0, 2, 4, 6)

for n := range c {
fmt.Println("n:", n)
}

fmt.Println("n:", <-c)
}

go run 012_channel.go
sending: 0
sending: 2
sending: 4
sending: 6
n: 0
n: 2
n: 4
n: 6
n: 0
CHANNELS
013_channel.go

package main go run 013_channel.go


sending: 0
import "fmt" sending: 2
sending: 4
func main() { sending: 6
var c chan int n: 0
n: 2
c = make(chan int, 16) n: 4
go func(c chan<- int, v ...int) { n: 6
for _, n := range v { n: 0, open: false
fmt.Println("sending:", n)
c <- n
}
close(c)
}(c, 0, 2, 4, 6)

for n := range c {
fmt.Println("n:", n)
}

n, open := <-c
fmt.Printf("n: %v, open: %v\n", n, open)
}
CHANNELS
014_channel.go

package main go run 014_channel.go


sending: 0
import "fmt" sending: 2
sending: 4
func main() { sending: 6
c := make(chan int, 16) len(c): 3, n: 0
done := make(chan bool)
go run 014_channel.go
go func(v ...int) { sending: 0
for _, n := range v { sending: 2
fmt.Println("sending:", n) sending: 4
c <- n sending: 6
} len(c): 3, n: 0
close(c) len(c): 2, n: 2
done <- true len(c): 1, n: 4
}(0, 2, 4, 6)

Receiver:
for {
select {
case n, ok := <-c:
if ok {
fmt.Printf("len(c): %v, n: %v\n", len(c), n)
}
case <-done:
break Receiver
}
}
}
CHANNELS
015_channel.go

package main go run 015_channel.go


sending: 0
import "fmt" sending: 2
len(c): 0, n: 0
func main() { len(c): 0, n: 2
c := make(chan int) sending: 4
done := make(chan bool) sending: 6
len(c): 0, n: 4
go func(v ...int) { len(c): 0, n: 6
for _, n := range v {
fmt.Println("sending:", n) go run 015_channel.go
c <- n sending: 0
} sending: 2
close(c) len(c): 0, n: 0
done <- true len(c): 0, n: 2
}(0, 2, 4, 6) sending: 4
sending: 6
Receiver: len(c): 0, n: 4
for { len(c): 0, n: 6
select {
case n, ok := <-c:
if ok {
fmt.Printf("len(c): %v, n: %v\n", len(c), n)
}
case <-done:
break Receiver
}
}
}
USER-DEFINED COLLECTIONS
USER-DEFINED COLLECTIONS
016_udt.go

package main

import "fmt"

type ISlice []int

func (s ISlice) Sum() (r int) {


for _, x := range s {
r += x
}
return
}

func main() {
s := ISlice{0, 1, 2, 3, 4}
fmt.Printf("%v.Sum() = %v\n", s, s.Sum())
}

go run 014_udt.go
[0 1 2 3 4].Sum() = 10
USER-DEFINED COLLECTIONS
017_udt.go

package main func main() {


var s Summable
import "fmt"
s = ISlice{0, 1, 2, 3, 4}
type Summable interface { fmt.Printf("%v.Sum() = %v\n", s, s.Sum())
Sum() any
} s = FSlice{0, 1, 2, 3, 4}
fmt.Printf("%v.Sum() = %v\n", s, s.Sum())
type ISlice []int }

func (s ISlice) Sum() any { go run 017_udt.go


r := 0 (main.ISlice)[0 1 2 3 4].Sum() = 10
for x := len(s) - 1; x > -1; x-- { (main.FSlice)[0 1 2 3 4].Sum() = 10
r += s[x]
}
return r
}

type FSlice []float32

func (s FSlice) Sum() any {


r := float32(0)
for x := len(s) - 1; x > -1; x-- {
r += s[x]
}
return r
}
USER-DEFINED COLLECTIONS
018_udt.go

package main go run 018_udt.go


(main.Summable[int])[0 1 2 3 4].Sum() = 10
import "fmt" (main.Summable[int])[0 1 2 3 4].Sum() = 10
(main.Summable[float32])[0 1 2 3 4].Sum() = 10
type Numeric interface { (main.Summable[float32])[0 1 2 3 4].Sum() = 10
~int | ~float32
}

type Summable[T Numeric] []T

func (s Summable[T]) Sum() (r T) {


for _, x := range s {
r += x
}
return
}

type ISlice = Summable[int]


type FSlice = Summable[float32]

func main() {
i := Summable[int]{0, 1, 2, 3, 4}
fmt.Printf("(%T)%v.Sum() = %v\n", i, i, i.Sum())

i = ISlice{0, 1, 2, 3, 4}
fmt.Printf("(%T)%v.Sum() = %v\n", i, i, i.Sum())

f := Summable[float32]{0, 1, 2, 3, 4}
fmt.Printf("(%T)%v.Sum() = %v\n", f, f, f.Sum())

f = FSlice{0, 1, 2, 3, 4}
fmt.Printf("(%T)%v.Sum() = %v\n", f, f, f.Sum())
}
USER-DEFINED COLLECTIONS
019_generic_func.go

package main go run 019_generic_func.go


Sum([]int[0 1 2 3 4]) = 10
import "fmt" Sum([]float32[0 1 2 3 4]) = 10
r = 10
func Sum(s any) (r any) {
switch s := s.(type) {
case []float32:
var f float32
for _, x := range s {
f += x
}
r = f
case []int:
var i int
for _, x := range s {
i += x
}
r = i
}
return
}

func main() {
i := []int{0, 1, 2, 3, 4}
fmt.Printf("Sum(%T%v) = %v\n", i, i, Sum(i))

f := []float32{0, 1, 2, 3, 4}
fmt.Printf("Sum(%T%v) = %v\n", f, f, Sum(i))

r := Sum(f).(float32)
fmt.Println("r =", r)
}
USER-DEFINED COLLECTIONS
020_generic_func.go

package main func main() {


i := []int{0, 1, 2, 3, 4}
import ( fmt.Printf("Sum(%T%v) = %v\n", i, i, Sum(i))
"fmt"
"reflect" f := []float32{0, 1, 2, 3, 4}
) fmt.Printf("Sum(%T%v) = %v\n", f, f, Sum(f))

type ISlice []int in := []interface{}{int(0), float32(1), int(2)}


type FSlice []float32 fmt.Printf("Sum(%T%v) = %v\n", in, in, Sum(in))

func Sum(s any) (r any) { is := ISlice{0, 1, 2, 3, 4}


if s := reflect.ValueOf(s); s.Kind() == reflect.Slice { fmt.Printf("Sum(%T%v) = %v\n", is, is, Sum(is))
switch s.Type().Elem().Kind() {
case reflect.Int: fs := FSlice{0, 1, 2, 3, 4}
var x int fmt.Printf("Sum(%T%v) = %v\n", fs, fs, Sum(fs))
for i := 0; i < s.Len(); i++ { }
x += int(s.Index(i).Int())
} go run 020_generic_func.go
r = x Sum([]int[0 1 2 3 4]) = 10
case reflect.Float32: Sum([]float32[0 1 2 3 4]) = 10
var x float32 Sum([]interface {}[0 1 2]) = <nil>
for i := 0; i < s.Len(); i++ { Sum(main.ISlice[0 1 2 3 4]) = 10
x += float32(s.Index(i).Float()) Sum(main.FSlice[0 1 2 3 4]) = 10
}
r = x
}
}
return
}
USER-DEFINED COLLECTIONS
021_generic_func.go

package main func main() {


i := []int{0, 1, 2, 3, 4}
import ( fmt.Printf("Sum(%T%v) = %v\n", i, i, Sum(i))
"fmt"
"reflect" f := []float32{0, 1, 2, 3, 4}
) fmt.Printf("Sum(%T%v) = %v\n", f, f, Sum(f))

type ISlice []int in := []interface{}{int(0), float32(1), int(2)}


type FSlice []float32 fmt.Printf("Sum(%T%v) = %v\n", in, in, Sum(in))

func Sum(s any) (r any) { is := ISlice{0, 1, 2, 3, 4}


if s := R.ValueOf(s); s.Kind() == R.Slice { fmt.Printf("Sum(%T%v) = %v\n", is, is, Sum(is))
T := s.Type().Elem()
V := R.New(T) fs := FSlice{0, 1, 2, 3, 4}
E := V.Elem() fmt.Printf("Sum(%T%v) = %v\n", fs, fs, Sum(fs))
switch T.Kind() { }
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:
for i := 0; i < s.Len(); i++ { go run 021_generic_func.go
E.SetInt(E.Int() + s.Index(i).Int()) Sum([]int[0 1 2 3 4]) = 10
} Sum([]float32[0 1 2 3 4]) = 10
case R.Float32, R.Float64: Sum([]interface {}[0 1 2]) = <nil>
for i := 0; i < s.Len(); i++ { Sum(main.ISlice[0 1 2 3 4]) = 10
E.SetFloat(E.Float() + s.Index(i).Float()) Sum(main.FSlice[0 1 2 3 4]) = 10
}
}
r = E.Interface()
}
return
}
USER-DEFINED COLLECTIONS
022_generic_func.go

package main go run 022_generic_func.go


Sum[int]([0 1 2 3 4]) = 10
import "fmt" Sum[float32]([0 1 2 3 4]) = 10
Sum[int]([0 1 2 3 4]) = 10
type Numeric interface { Sum[float32]([0 1 2 3 4]) = 10
~int | ~float32
}

func Sum[T Numeric](s []T) (r T) {


for _, x := range s {
r += x
}
return
}

type ISlice []int


type FSlice []float32

func main() {
i := []int{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", i[0], i, Sum[int](i))

f := []float32{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", f[0], f, Sum[float32](f))

is := ISlice{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", is[0], is, Sum[int](is))

fs := FSlice{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", fs[0], fs, Sum[float32](fs))
}
USER-DEFINED COLLECTIONS
023_generic_func.go

package main go run 023_generic_func.go


Sum[int]([0 1 2 3 4]) = 10
import "fmt" Sum[float32]([0 1 2 3 4]) = 10
Sum[int]([0 1 2 3 4]) = 10
type Numeric interface { Sum[float32]([0 1 2 3 4]) = 10
~int | ~float32
}

func Sum[T Numeric](s []T) (r T) {


for _, x := range s {
r += x
}
return
}

type ISlice []int


type FSlice []float32

func main() {
i := []int{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", i[0], i, Sum(i))

f := []float32{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", f[0], f, Sum(f))

is := ISlice{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", is[0], is, Sum(is))

fs := FSlice{0, 1, 2, 3, 4}
fmt.Printf("Sum[%T](%v) = %v\n", fs[0], fs, Sum(fs))

}
USER-DEFINED COLLECTIONS
024_generic_func.go 025_generic_func.go

package main package main

import "fmt" import "fmt"

type Numeric interface { type Numeric interface {


~int | ~float32 ~int | ~float32
} }

type Indexable[T any] interface { func Sum[T Indexable[E], E Numeric](s T) (r E) {


~[]T for _, x := range s {
} r += x
}
func Sum[T Indexable[E], E Numeric](s T) (r E) { return
for _, x := range s { }
r += x
} type Indexable[T any] interface {
return ~[]T
} }

type ISlice Indexable[int] type ISlice []int


type FSlice []float32
func main() {
is := ISlice{0, 1, 2, 3, 4} func main() {
fmt.Printf("Sum[%T](%v) = %v\n", is[0], is, Sum(is)) is := ISlice{0, 1, 2, 3, 4}
} fmt.Printf("Sum[%T](%v) = %v\n", is[0], is, Sum(is))

go run 024_generic_func.go fs := FSlice{0, 1, 2, 3, 4}


# command-line-arguments fmt.Printf("Sum[%T](%v) = %v\n", fs[0], fs, Sum(fs))
./023_generic_func.go:23:8: invalid composite literal type }
ISlice
go run 025_generic_func.go
Sum[int]([0 1 2 3 4]) = 10
Sum[float32]([0 1 2 3 4]) = 10
USER-DEFINED COLLECTIONS
026_generic_func.go

package main go run 026_generic_func.go


Append[main.ISlice]([0 1 2 3 4], 5) = main.ISlice[0 1 2 3 4 5]
import "fmt" Append[[]float32]([0 1 2 3 4], 6) = []float32[0 1 2 3 4 6]

type Indexable[T any] interface {


~[]T
}

func Append[T Indexable[E], E any](s *T, e E) {


*s = append(*s, e)
}

type ISlice []int

func main() {
is := ISlice{0, 1, 2, 3, 4}
is2 := append(make(ISlice, 0), is...)
Append(&is2, 5)
fmt.Printf("Append[%T](%v, %v) = %T%v\n", is, is, 5, is2, is2)

fs := []float32{0, 1, 2, 3, 4}
fs2 := append(make([]float32, 0), fs...)
Append(&fs2, 6)
fmt.Printf("Append[%T](%v, %v) = %T%v\n", fs, fs, 6, fs2, fs2)
}
HIGHER ORDER FUNCTIONS
HIGHER ORDER FUNCTIONS
027_high_order_func.go

package main

import "fmt"

type Iterable interface {


Range(f func(int, int))
}

func Sum(s Iterable) (r int) {


s.Range(func(i, v int) {
r += v
})
return
}

type ISlice []int

func (s ISlice) Range(f func(int, int)) {


for i, v := range s {
f(i, v)
}
}

func main() {
is := ISlice{0, 1, 2, 3, 4}
fmt.Printf("Sum(%v) = %v\n", is, Sum(is))
}

go run 027_high_order_func.go
Sum([0 1 2 3 4]) = 10
HIGHER ORDER FUNCTIONS
028_high_order_func.go 029_high_order_func.go

package main package main

import "fmt" import "fmt"

type Iterable interface { type Iterable interface {


Range(f func(int, int)) Range(f func(int, int))
} }

func Sum(s Iterable) (r int) { func Sum(s Iterable) (r int) {


s.Range(func(i, v int) { s.Range(func(i, v int) {
r += v r += v
}) })
return return
} }

func main() { type FSlice []float32


f := []float32{0, 1, 2, 3, 4}
fmt.Printf("Sum(%v) = %v\n", f, Sum(f)) func (s FSlice) Range(f func(int, int)) {
} for i, v := range s {
f(i, v)
go run 028_high_order_func.go }
# command-line-arguments }
./028_high_order_func.go:29:38: cannot use f (variable of type
[]float32) as type Iterable in argument to Sum: func main() {
[]float32 does not implement Iterable (missing Range method) fs := FSlice{0, 1, 2, 3, 4}
fmt.Printf("Sum(%v) = %v\n", fs, Sum(fs))
}

go run 029_high_order_func.go
# command-line-arguments
./029_high_order_func.go:13:8: cannot use v (variable of type
float32) as type int in argument to f
HIGHER ORDER FUNCTIONS
030_high_order_func.go

package main func main() {


is := FSlice{0, 1, 2, 3, 4}
import "fmt" fmt.Printf("Sum(%v) = %v\n", is, Sum(is))

type Iterable interface { fs := FSlice{0, 1, 2, 3, 4}


Range(f func(int, any)) fmt.Printf("Sum(%v) = %v\n", fs, Sum(fs))
} }

func Sum(s Iterable) (r any) { go 030_high_order_func.go


s.Range(func(i int, v any) { # command-line-arguments
r += v ./030_high_order_func.go:11:3: invalid operation: operator + not
}) defined on r (variable of type any)
return
}

type ISlice []int

func (s ISlice) Range(f func(int, any)) {


for i, v := range s {
f(i, v)
}
}

type FSlice []float32

func (s FSlice) Range(f func(int, any)) {


for i, v := range s {
f(i, v)
}
}
HIGHER ORDER FUNCTIONS
031_high_order_func.go

package main go 031_high_order_func.go


# command-line-arguments
import "fmt" ./031_high_order_func.go:30:39: type ISlice of is does not match
Iterable[T] (cannot infer T)
type Numeric interface {
~int | ~float32
}

type Iterable[T Numeric] interface {


Range(func(int, T))
}

func Sum[T Numeric](s Iterable[T]) (r T) {


s.Range(func(i int, v T) {
r += v
})
return
}

type ISlice []int

func (s ISlice) Range(f func(int, int)) {


for i, v := range s {
f(i, v)
}
}

func main() {
is := ISlice{0, 1, 2, 3, 4}
fmt.Printf("Sum(%v) = %v\n", is, Sum(is))
}
HIGHER ORDER FUNCTIONS
032_high_order_func.go

package main type FSlice []float32

import "fmt" func (s FSlice) Range(f func(int, float32)) {


for i, v := range s {
type Numeric interface { f(i, v)
~int | ~float32 }
} }

type Iterable[T Numeric] interface { func main() {


Range(func(int, T)) is := ISlice{0, 1, 2, 3, 4}
} fmt.Printf("Sum(%v) = %v\n", is, Sum[int](is))

func Sum[T Numeric](s Iterable[T]) (r T) { fs := FSlice{0, 1, 2, 3, 4}


s.Range(func(i int, v T) { fmt.Printf("Sum(%v) = %v\n", fs, Sum[float32](fs))
r += v }
})
return go 032_high_order_func.go
} Sum([0 1 2 3 4]) = 10
Sum([0 1 2 3 4]) = 10
type ISlice []int

func (s ISlice) Range(f func(int, int)) {


for i, v := range s {
f(i, v)
}
}
HIGHER ORDER FUNCTIONS
033_high_order_func.go

package main type ISlice []int

import "fmt" func (s ISlice) Range(f func(int, int)) {


for i, v := range s {
type Numeric interface { f(i, v)
~int | ~float32 }
} }

type Iterable[T Numeric] interface { func main() {


Range(f func(int, T)) is := ISlice{0, 1, 2, 3, 4}
} fmt.Printf("Sum(%v) = %v[%T]\n", is, Sum[int](is), is[0])

func Sum[T Numeric](s any) (r any) { fs := []float32{0, 1, 2, 3, 4}


switch s := s.(type) { fmt.Printf("Sum(%v) = %v[%T]\n", fs, Sum[float32](fs), fs[0])
case Iterable[T]: }
fmt.Printf("case Iterable[%T]\n", s)
var x T go 033_high_order_func.go
s.Range(func(i int, v T) { case Iterable[main.ISlice]
x += v Sum([0 1 2 3 4]) = 10 [int]
}) case []float32
r = x Sum([0 1 2 3 4]) = 10 [float32]
case []T:
fmt.Printf("case %T\n", s)
var x T
for _, v := range s {
x += v
}
r = x
}
return
}
REDUCING COLLECTIONS
REDUCING COLLECTIONS
034_reduce.go

package main go 034_reduce.go


Reduce([0 1 2 3 4], f()) = 10 [int]
import "fmt" Reduce([0 1 2 3 4], f()) = 10 [float32]

type Numeric interface {


~int | ~float32
}

type Indexable[T any] interface {


~[]T
}

func Reduce[T Indexable[E], E Numeric](s T, f func(E, E) E) (r E) {


for _, v := range s {
r = f(r, v)
}
return
}

func main() {
is := []int{0, 1, 2, 3, 4}
ir := Reduce(is, func(x, v int) int {
return x + v
})
fmt.Printf("Reduce(%v, f()) = %v [%T]\n", is, ir, ir)

fs := []float32{0, 1, 2, 3, 4}
fr := Reduce(fs, func(x, v float32) float32 {
return x + v
})
fmt.Printf("Reduce(%v, f()) = %v [%T]\n", fs, fr, fr)
}
REDUCING COLLECTIONS
035_reduce.go

package main func main() {


is := []int{0, 1, 2, 3, 4}
import "fmt" ir := Reduce(is, func(x any, v any) any {
return x.(int) + v.(int)
func Reduce(s any, f func(any, any) any) (r any) { })
switch s := s.(type) { fmt.Printf("Reduce(%v, f()) = %v [%T]\n", is, ir, ir)
case []int:
var x int fs := []float32{0, 1, 2, 3, 4}
for _, v := range s { fr := Reduce(fs, func(x any, v any) any {
x = f(x, v).(int) return x.(float32) + v.(float32)
} })
r = x fmt.Printf("Reduce(%v, f()) = %v [%T]\n", fs, fr, fr)
case []float32: }
var x float32
for _, v := range s { go 035_reduce.go
x = f(x, v).(float32) Reduce([0 1 2 3 4], f()) = 10 [int]
} Reduce([0 1 2 3 4], f()) = 10 [float32]
r = x
}
return
}
REDUCING COLLECTIONS
036_reduce.go

package main func main() {


is := []int{0, 1, 2, 3, 4}
import ( ir := Reduce(is, func(x any, v any) any {
"fmt" return x.(int) + v.(int)
R "reflect" })
) fmt.Printf("Reduce(%v, f()) = %v [%T]\n", is, ir, ir)

func Reduce(s any, f func(any, any) any) (r any) { fs := []float32{0, 1, 2, 3, 4}


if s := R.ValueOf(s); s.Kind() == R.Slice { fr := Reduce(fs, func(x any, v any) any {
T := s.Type().Elem() return x.(float32) + v.(float32)
V := R.New(T) })
E := V.Elem() fmt.Printf("Reduce(%v, f()) = %v [%T]\n", fs, fr, fr)
switch T.Kind() { }
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:
for i := 0; i < s.Len(); i++ { go 036_reduce.go
v := R.ValueOf(f( Reduce([0 1 2 3 4], f()) = 10 [int]
E.Interface(), Reduce([0 1 2 3 4], f()) = 10 [float32]
s.Index(i).Interface()))
E.SetInt(v.Int())
}
case R.Float32, R.Float64:
for i := 0; i < s.Len(); i++ {
v := R.ValueOf(f(
E.Interface(),
s.Index(i).Interface()))
E.SetFloat(v.Float())
}
}
r = E.Interface()
}
return
}
REDUCING COLLECTIONS
037_reduce.go

package main go 037_reduce.go


(main.Reducible[int])[0 1 2 3 4].Reduce(f()) = 10 [int]
import "fmt" (main.Reducible[float32])[0 1 2 3 4].Reduce(f()) = 10 [float32]

type Numeric interface {


~int | ~float32
}

type Reducible[T Numeric] []T

func (s Reducible[T]) Reduce(f func(T, T) T) (r T) {


for _, x := range s {
r = f(r, x)
}
return
}

type ISlice = Reducible[int]

func main() {
is := ISlice{0, 1, 2, 3, 4}
ir := is.Reduce(func(x, v int) int {
return x + v
})
fmt.Printf("(%T)%v.Reduce(f()) = %v [%T]\n", is, is, ir, ir)

fs := Reducible[float32]{0, 1, 2, 3, 4}
fr := fs.Reduce(func(x, v float32) float32 {
return x + v
})
fmt.Printf("(%T)%v.Reduce(f()) = %v [%T]\n", fs, fs, fr, fr)
}
REDUCING COLLECTIONS
038_reduce.go

package main go 038_reduce.go


map[0:0 1:1 2:2 3:3 4:4].Reduce(f()) = 10 [int]
import "fmt" map[0:0 1:1 2:2 3:3 4:4].Reduce(f()) = 10 [float32]

type Numeric interface {


~int | ~float32
}

type Reducible[K comparable, E Numeric] map[K]E

func (m Reducible[K, E]) Reduce(f func(E, E) E) (r E) {


for _, x := range m {
r = f(r, x)
}
return
}

type IMap = Reducible[int, int]

func main() {
im := IMap{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
ir := im.Reduce(func(x, v int) int {
return x + v
})
fmt.Printf("%v.Reduce(f()) = %v [%T]\n", im, ir, ir)

fm := Reducible[int, float32]{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
fr := fm.Reduce(func(x, v float32) float32 {
return x + v
})
fmt.Printf("%v.Reduce(f()) = %v [%T]\n", fm, fr, fr)
}
REDUCING COLLECTIONS
039_reduce.go

package main func main() {


ic := make(IChan)
import "fmt" go ic.Pump(0, 1, 2, 3, 4)
ir := ic.Reduce(func(x, v int) int {
type Numeric interface { return x + v
~int | ~float32 })
} fmt.Printf("(chan ic).Reduce(f()) = %v [%T]\n", ir, ir)

type Reducible[T Numeric] chan T fc := make(FChan)


go fc.Pump(0, 1, 2, 3, 4)
func (c Reducible[T]) Reduce(f func(T, T) T) (r T) { fr := fc.Reduce(func(x, v float32) float32 {
for x := range c { return x + v
r = f(r, x) })
} fmt.Printf("(chan fc).Reduce(f()) = %v [%T]\n", fr, fr)
return }
}
go 039_reduce.go
func (c Reducible[T]) Pump(v ...T) { (chan ic).Reduce(f()) = 10 [int]
for _, v := range v { (chan fc).Reduce(f()) = 10 [float32]
c <- v
}
close(c)
}

type IChan = Reducible[int]


type FChan = Reducible[float32]
REDUCING COLLECTIONS
040_reduce.go

package main func main() {


is := []int{0, 1, 2, 3, 4}
import "fmt" ir := Reduce(is, func(x, v int) int {
return x + v
type Numeric interface { })
~int | ~float32 fmt.Printf("Reduce(%v, f()) = %v [%T]\n", is, ir, ir)
}
im := map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { ir = Reduce(im, func(x, v int) int {
switch c := c.(type) { return x + v
case []T: })
for _, x := range c { fmt.Printf("Reduce(%v, f()) = %v [%T]\n", im, ir, ir)
r = f(r, x)
} ic := make(chan int)
case map[int]T: go Pump(ic, 0, 1, 2, 3, 4)
for _, x := range c { ir = Reduce(ic, func(x, v int) int {
r = f(r, x) return x + v
} })
case chan T: fmt.Printf("(chan ic).Reduce(f()) = %v [%T]\n", ir, ir)
for x := range c { }
r = f(r, x)
} go 040_reduce.go
} Reduce([0 1 2 3 4], f()) = 10 [int]
return Reduce(map[0:0 1:1 2:2 3:3 4:4], f()) = 10 [int]
} (chan ic).Reduce(f()) = 10 [int]

func Pump[T Numeric](ic chan<- T, v ...T) {


for _, v := range v {
ic <- v
}
close(ic)
}
REDUCING COLLECTIONS
041_reduce.go

package main func Pump[T Numeric](ic chan<- T, v ...T) {


for _, v := range v {
import ( ic <- v
"fmt" }
R "reflect" close(ic)
) }

type Numeric interface { func DoReduce(c any) {


~int | ~float32 ir := Reduce(c, func(x, v int) int {
} return x + v
})
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, ir, ir)
switch c := c.(type) { }
case chan T:
for x := range c { func main() {
r = f(r, x) ic := make(chan int)
} go Pump(ic, 0, 1, 2, 3, 4)
case string: DoReduce(ic)
for _, x := range c { DoReduce("01234")
r = f(r, T(x)) DoReduce(map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
} DoReduce(map[string]int{
default: "0": 0, "1": 1, "2": 2, "3": 3, "4": 4})
switch c := R.ValueOf(c); c.Kind() { }
case R.Map:
for i := c.MapRange(); i.Next(); { go 041_reduce.go
r = f(r, i.Value().Interface().(T)) [chan int]Reduce(0xc00001c0c0, f()) = 10[int]
} [string]Reduce(01234, f()) = 250[int]
} [map[int]int]Reduce(map[0:0 1:1 2:2 3:3 4:4], f()) = 10[int]
} [map[string]int]Reduce(map[0:0 1:1 2:2 3:3 4:4], f()) = 10[int]
return
}
REDUCING COLLECTIONS
042_reduce.go

package main func DoReduce(c any) {


ir := Reduce(c, func(x, v int) int {
import ( return x + v
"fmt" })
R "reflect" fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, ir, ir)
) }

type Numeric interface { func main() {


~int | ~float32 DoReduce([0]int{})
} DoReduce([1]int{0})
DoReduce([2]int{0, 1})
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { DoReduce([5]int{0, 1, 2, 3, 4})
switch c := c.(type) { }
case [1]T:
for x := range c { go 042_reduce.go
r = f(r, T(x)) [[0]int]Reduce([], f()) = 0[int]
} [[1]int]Reduce([0], f()) = 0[int]
case [2]T: [[2]int]Reduce([0 1], f()) = 1[int]
for _, x := range c { [[5]int]Reduce([0 1 2 3 4], f()) = 10[int]
r = f(r, T(x))
}
default:
switch c := R.ValueOf(c); c.Kind() {
case R.Array:
for i := 0; i < c.Len(); i++ {
r = f(r, c.Index(i).Interface().(T))
}
}
}
return
}
REDUCING COLLECTIONS
043_reduce.go

package main func Reduce[T Numeric](c any, f func(T, T) T) (r T) {


switch c := c.(type) {
import "fmt" case Reducible[T]:
r = c.Reduce(f)
type Numeric interface { }
~int | ~float32 return
} }

type Reducible[T Numeric] interface { func DoReduce[T Numeric](c any, f func(T, T) T) {


Reduce(func(T, T) T) T r := Reduce(c, f)
} fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
}
type ISlice []int
func main() {
func (s ISlice) Reduce(f func(x, v int) int) (r int) { DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int {
for _, v := range s { return x + v
r = f(r, v) })
}
return DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 {
} return x + v
})
type FArray [3]float32 }

func (a FArray) Reduce(f func(x, v float32) float32) (r float32) {


for _, v := range a { go 043_reduce.go
r = f(r, v) [main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int]
} [main.FArray]Reduce([0 1 2], f()) = 3[float32]
return
}
REDUCING COLLECTIONS
044_reduce.go

package main func DoReduce[T Numeric](c any, f func(T, T) T) {


r := Reduce(c, f)
import "fmt" fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
}
type Numeric interface {
~int | ~float32 func Adder[T Numeric]() func(T, T) T {
} return func(x, v T) T {
return x + v
type Iterable[T Numeric] interface { }
Range(f func(int, T)) }
}
func main() {
type Reducible[T Numeric] interface { DoReduce(func(x int) (int, bool) {
Reduce(func(T, T) T) T return x, (x < 5)
} }, Adder[int]())
DoReduce(func(x int) (float32, bool) {
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { return float32(x), (x < 5)
switch c := c.(type) { }, Adder[float32]())
case func(int) (T, bool): }
for i := 0; ; i++ {
if v, ok := c(i); ok { go 044_reduce.go
r = f(r, v) [func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]
} else { [func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
break
}
}
}
return
}
REDUCING COLLECTIONS
045_reduce.go

package main func DoReduce[T Numeric](c any, f func(T, T) T) {


r := Reduce(c, f)
import "fmt" fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
}
type Numeric interface {
~int | ~float32 func Adder[T func(I) (E, bool), I, E Numeric](f T) func(E, E) E {
} return func(x, v E) E {
return x + v
type Iterable[T Numeric] interface { }
Range(f func(int, T)) }
}
func main() {
type Reducible[T Numeric] interface { i := func(x int) (int, bool) {
Reduce(func(T, T) T) T return x, (x < 5)
} }
DoReduce(i, Adder(i))
func Reduce[T Numeric](c any, f func(T, T) T) (r T) {
switch c := c.(type) { f := func(x int) (float32, bool) {
case func(int) (T, bool): return float32(x), (x < 5)
for i := 0; ; i++ { }
if v, ok := c(i); ok { DoReduce(f, Adder(f))
r = f(r, v) }
} else {
break go 045_reduce.go
} [func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]
} [func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
}
return
}
REDUCING COLLECTIONS
046_reduce.go

package main func DoReduce[T Numeric](c any, f func(T, T) T) {


r := Reduce(c, f)
import "fmt" fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
}
type Numeric interface {
~int | ~float32 func Adder[T Numeric]() func(T, T) T {
} return func(x, v T) T {
return x + v
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { }
switch c := c.(type) { }
case func(int) (T, bool):
for i := 0; ; i++ { func main() {
if v, ok := c(i); ok { DoReduce(func(x int) (int, bool) {
r = f(r, v) return x, (x < 5)
} else { }, Adder[int]())
break DoReduce(func(x int) (float32, bool) {
} return float32(x), (x < 5)
} }, Adder[float32]())
case NFunc[T]: DoReduce(NFunc[int](func(x int) (int, bool) {
r = Reduce((func(int) (T, bool))(c), f) return x, (x < 5)
} }), Adder[int]())
return }
}
go 046_reduce.go
type NFunc[T Numeric] func(int) (T, bool) [func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]
[func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
[main.NFunc[int]]Reduce(0x108e740, f()) = 10[int]
REDUCING COLLECTIONS
047_reduce.go

package main func DoReduce[T Numeric](c any, f func(T, T) T) {


r := Reduce(c, f)
import ( fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
"fmt" }
R "reflect"
) func Adder[T Numeric]() func(T, T) T {
return func(x, v T) T {
type Numeric interface { return x + v
~int | ~float32 }
} }

func Reduce[T Numeric](c any, f func(T, T) T) (r T) { func main() {


if c := R.ValueOf(c); c.Kind() == R.Func { DoReduce(func(x int) (int, bool) {
for i := 0; ; i++ { return x, (x < 5)
p := []R.Value{R.ValueOf(i)} }, Adder[int]())
if p = c.Call(p); p[1].Interface() == true { DoReduce(func(x int) (float32, bool) {
r = f(r, p[0].Interface().(T)) return float32(x), (x < 5)
} else { }, Adder[float32]())
break DoReduce(NFunc[int](func(x int) (int, bool) {
} return x, (x < 5)
} }), Adder[int]())
} }
return
} go 047_reduce.go
[func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]
type NFunc[T Numeric] func(int) (T, bool) [func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
[main.NFunc[int]]Reduce(0x108e740, f()) = 10[int]
REDUCING COLLECTIONS
048_reduce.go

package main case map[int]T:


for _, x := range c {
import ( r = f(r, x)
"fmt" }
R "reflect" case func(int) (T, bool):
) for i := 0; ; i++ {
if v, ok := c(i); ok {
type Numeric interface { r = f(r, v)
~int | ~int8 | ~int16 | ~int32 | ~int64 | } else {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | break
~float32 | ~float64 }
} }
case chan T:
type Iterable[T Numeric] interface { for x := range c {
Range(f func(int, T)) r = f(r, x)
} }
default:
type Reducible[T Numeric] interface { switch c := R.ValueOf(c); c.Kind() {
Reduce(func(T, T) T) T case R.Map:
} for i := c.MapRange(); i.Next(); {
r = f(r, i.Value().Interface().(T))
func Reduce[T Numeric](c any, f func(T, T) T) (r T) { }
switch c := c.(type) { case R.Array:
case Iterable[T]: for i := 0; i < c.Len(); i++ {
c.Range(func(i int, v T) { r = f(r, c.Index(i).Interface().(T))
r = f(r, v) }
}) case R.Func:
case Reducible[T]: for i := 0; ; i++ {
r = c.Reduce(f) p := []R.Value{R.ValueOf(i)}
case string: if p = c.Call(p); p[1].Interface() == true {
for _, x := range c { r = f(r, p[0].Interface().(T))
r = f(r, T(x)) } else {
} break
case T: }
r = f(r, c) }
case []T: }
for _, x := range c { }
r = f(r, x) return
} }
REDUCING COLLECTIONS
049_reduce.go

package main case chan T:


for x := range c {
import R "reflect" r = f(r, x)
}
func Reduce[T any](c any, f func(T, T) T) (r T) { default:
switch c := c.(type) { switch c := R.ValueOf(c); c.Kind() {
case interface{ Range(f func(int, T)) }: case R.Map:
c.Range(func(i int, v T) { for i := c.MapRange(); i.Next(); {
r = f(r, v) r = f(r, i.Value().Interface().(T))
}) }
case interface{ Reduce(func(T, T) T) T }: case R.Array:
r = c.Reduce(f) for i := 0; i < c.Len(); i++ {
case string: r = f(r, c.Index(i).Interface().(T))
for _, x := range c { }
r = f(r, x) case R.Func:
} for i := 0; ; i++ {
case T: p := []R.Value{R.ValueOf(i)}
r = f(r, c) if p = c.Call(p); p[1].Interface() == true {
case []T: r = f(r, p[0].Interface().(T))
for _, x := range c { } else {
r = f(r, x) break
} }
case map[int]T: }
for _, x := range c { }
r = f(r, x) }
} return
case func(int) (T, bool): }
for i := 0; ; i++ {
if v, ok := c(i); ok { func main() {}
r = f(r, v)
} else { go 049_reduce.go
break # command-line-arguments
} ./049_reduce.go:15:13: cannot use x (variable of type rune) as
} type T in argument to f
REDUCING COLLECTIONS
050_reduce.go

package main type FArray [3]float32

import "fmt" func (a FArray) Reduce(f func(x, v float32) float32) (r float32) {


for _, v := range a {
func Reduce[T any](c any, f func(T, T) T) (r T) { r = f(r, v)
switch c := c.(type) { }
case interface{ Range(f func(int, T)) }: return
c.Range(func(i int, v T) { }
r = f(r, v)
}) func main() {
case interface{ Reduce(func(T, T) T) T }: DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int {
r = c.Reduce(f) return x + v
} })
return
} DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 {
return x + v
func DoReduce[T any](c any, f func(T, T) T) { })
r := Reduce(c, f) }
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
} go 050_reduce.go
[main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int]
type ISlice []int [main.FArray]Reduce([0 1 2], f()) = 3[float32]

func (s ISlice) Range(f func(int, int)) {


for i, v := range s {
f(i, v)
}
}
REDUCING COLLECTIONS
051_reduce.go 052_reduce.go

package main package main

import "fmt" import (


"fmt"
func Reduce[T any](c any, f func(T, T) T) (r T) { R "reflect"
switch c := c.(type) { )
case string:
for _, x := range c { func Reduce[T any](c any, f func(T, T) T) (r T) {
r = f(r, any(x).(T)) switch c := R.ValueOf(c); c.Kind() {
} case R.String:
} for _, x := range c.Interface().(string) {
return r = f(r, any(x).(T))
} }
}
func DoReduce[T any](c any, f func(T, T) T) { return
r := Reduce(c, f) }
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
} func DoReduce[T any](c any, f func(T, T) T) {
r := Reduce(c, f)
func main() { fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]\n", c, c, r, r)
DoReduce[rune]("01234", func(r, x rune) rune { }
return r + x - 48
}) func main() {
} DoReduce("01234", func(x, v rune) rune {
return x + v - 48
go 051_reduce.go })
[string]Reduce(01234, f()) = 10[int32] }

go 052_reduce.go
[string]Reduce(01234, f()) = 10[int32]
REDUCING COLLECTIONS
053_reduce.go

package main case chan T:


for x := range c {
import R "reflect" r = f(r, x)
}
func Reduce[T any](c any, f func(T, T) T) (r T) { default:
switch c := c.(type) { switch c := R.ValueOf(c); c.Kind() {
case interface{ Range(f func(int, T)) }: case R.Map:
c.Range(func(i int, v T) { for i := c.MapRange(); i.Next(); {
r = f(r, v) r = f(r, i.Value().Interface().(T))
}) }
case interface{ Reduce(func(T, T) T) T }: case R.Array:
r = c.Reduce(f) for i := 0; i < c.Len(); i++ {
case string: r = f(r, c.Index(i).Interface().(T))
for _, x := range c { }
r = f(r, any(x).(T)) case R.Func:
} for i := 0; ; i++ {
case T: p := []R.Value{R.ValueOf(i)}
r = f(r, c) if p = c.Call(p); p[1].Interface() == true {
case []T: r = f(r, p[0].Interface().(T))
for _, x := range c { } else {
r = f(r, x) break
} }
case map[int]T: }
for _, x := range c { }
r = f(r, x) }
} return
case func(int) (T, bool): }
for i := 0; ; i++ {
if v, ok := c(i); ok { func main() {}
r = f(r, v)
} else {
break
}
}
MAPPING COLLECTIONS
MAPPING COLLECTIONS
054_map.go

package main

import "fmt"

func Map[T any](s []T, f func(T) T) (r []T) {


for _, v := range s {
r = append(r, f(v))
}
return
}

func DoMap[T ~int | ~float32](s []T) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}

func main() {
DoMap([]int{0, 1, 2, 3, 4})
DoMap([]float32{0, 1, 2, 3, 4})
}

054_map.go
Map([0 1 2 3 4], func()): [0 2 4 6 8]
Map([0 1 2 3 4], func()): [0 2 4 6 8]
MAPPING COLLECTIONS
055_high_order_func.go

package main type ISlice []int

import "fmt" func (s ISlice) Range(f func(i, v int)) {


for i, v := range s {
type Iterable[T any] interface { f(i, v)
Range(func(int, T)) }
} }

func Map[T any](s any, f func(T) T) (r []T) { func main() {


switch s := s.(type) { DoMap(ISlice{0, 1, 2, 3, 4})
case Iterable[T]: DoMap([]int{0, 1, 2, 3, 4})
s.Range(func(i int, v T) { DoMap([]float32{0, 1, 2, 3, 4})
r = append(r, f(v)) }
})
case []T: 055_high_order_func.go
for _, v := range s { Map([0 1 2 3 4], func()): [0 2 4 6 8]
r = append(r, f(v)) Map([0 1 2 3 4], func()): [0 2 4 6 8]
} Map([0 1 2 3 4], func()): [0 2 4 6 8]
}
return
}

func DoMap[T ~int | ~float32](s []T) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}
MAPPING COLLECTIONS
056_map.go

package main func Limit[T any](i, j int, f NFunc[T]) NFunc[T] {


return func(x int) (r T, ok bool) {
import "fmt" if i <= x && x <= j {
r, ok = f(x)
func Map[T any](s any, f func(T) T) (r []T) { }
switch s := s.(type) { return
case interface{ Range(func(int, T)) }: }
s.Range(func(i int, v T) { }
r = append(r, f(v))
}) func main() {
} DoMap[int](Limit(0, 4, func(x int) (int, bool) {
return return x, true
} }))
DoMap[float32](func(x int) (float32, bool) {
func DoMap[T ~int | ~float32](s any) { return float32(x), (x < 5)
r := Map(s, func(v T) T { })
return v * 2 }
})
fmt.Printf("Map(%v, func()): %v\n", s, r) 056_map.go
} Map(0x108afc0, func()): [0 2 4 6 8]
Map(0x108ae20, func()): []
type NFunc[T any] func(int) (T, bool)

func (f NFunc[T]) Range(p func(i int, v T)) {


for i := 0; ; i++ {
if r, ok := f(i); ok {
p(i, r)
} else {
break
}
}
}
MAPPING COLLECTIONS
057_map.go

package main func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
import "fmt" return v * 2
})
func Map[T any](s any, f func(T) T) (r []T) { fmt.Printf("Map(%v, func()): %v\n", s, r)
switch s := s.(type) { }
case func(int) (T, bool):
for i := 0; ; i++ { func Limit[T any](i, j int, f NFunc[T]) NFunc[T] {
if v, ok := s(i); ok { return func(x int) (r T, ok bool) {
r = append(r, f(v)) if i <= x && x <= j {
} else { r, ok = f(x)
break }
} return
} }
} }
return
} func main() {
DoMap[int](Limit(0, 4, func(x int) (int, bool) {
type NFunc[T any] func(int) (T, bool) return x, true
}))
func (f NFunc[T]) Range(p func(i int, v T)) { DoMap[float32](func(x int) (float32, bool) {
for i := 0; ; i++ { return float32(x), (x < 5)
if r, ok := f(i); ok { })
p(i, r) }
} else {
break 057_map.go
} Map(0x108aee0, func()): []
} Map(0x108ae20, func()): [0 2 4 6 8]
}
MAPPING COLLECTIONS
058_map.go

package main func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
import "fmt" return v * 2
})
func Map[T any](s any, f func(T) T) (r []T) { fmt.Printf("Map(%v, func()): %v\n", s, r)
switch s := s.(type) { }
case NFunc[T]:
for i := 0; ; i++ { func Limit[T any](i, j int, f NFunc[T]) NFunc[T] {
if v, ok := s(i); ok { return func(x int) (r T, ok bool) {
r = append(r, f(v)) if i <= x && x <= j {
} else { r, ok = f(x)
break }
} return
} }
} }
return
} func main() {
DoMap[int](Limit(0, 4, func(x int) (int, bool) {
type NFunc[T any] func(int) (T, bool) return x, true
}))
func (f NFunc[T]) Range(p func(i int, v T)) { DoMap[float32](func(x int) (float32, bool) {
for i := 0; ; i++ { return float32(x), (x < 5)
if r, ok := f(i); ok { })
p(i, r) }
} else {
break 058_map.go
} Map(0x108aee0, func()): [0 2 4 6 8]
} Map(0x108ae20, func()): []
}
MAPPING COLLECTIONS
059_map.go

package main 059_map.go


panic: interface conversion: interface {} is float64, not
import ( float32
"fmt"
R "reflect" goroutine 1 [running]:
) main.Map[...]({0x1099520, 0x10b0678?}, 0xc000107f10?)
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
func Map[T any](s any, f func(T) T) (r []T) { GoGenericsTalk/050_high_order_func.go:21 +0x325
if s := R.ValueOf(s); s.Kind() == R.Func { main.DoMap[...]({0x1099520, 0x10b0678})
for i := 0; ; i++ { /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
p := []R.Value{R.ValueOf(i)} GoGenericsTalk/050_high_order_func.go:31 +0x52
if p = s.Call(p); p[1].Interface() == true { main.main()
r = append(r, f(p[0].Interface().(T))) /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
} else { GoGenericsTalk/050_high_order_func.go:65 +0x79
break exit status 2
}
}
}
return
}

func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}

func main() {
DoMap[float32](func(x int) (float64, bool) {
return float64(x), (x < 5)
})
}
MAPPING COLLECTIONS
060_map.go

package main func main() {


DoMap[float32](func(x int) (float32, bool) {
import ( return float32(x), (x < 5)
"fmt" })
R "reflect" DoMap[float32](func(x int) (float64, bool) {
) return float64(x), (x < 5)
})
func Map[T any](s any, f func(T) T) (r []T) { }
if s := R.ValueOf(s); s.Kind() == R.Func {
defer func() { 060_map.go
recover() Map(0x108f560, func()): [0 2 4 6 8]
}() Map(0x108f580, func()): []
for i := 0; ; i++ {
p := []R.Value{R.ValueOf(i)}
if p = s.Call(p); p[1].Interface() == true {
r = append(r, f(p[0].Interface().(T)))
} else {
break
}
}
}
return
}

func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}
MAPPING COLLECTIONS
061_map.go

package main func DoMap[T Numeric](s any) {


r := Map(s, func(v T) T {
import ( return v * 2
"fmt" })
R "reflect" fmt.Printf("Map(%v, func()): %v\n", s, r)
) }

type Numeric interface { func main() {


~int | ~float32 DoMap[float32](func(x int) (float32, bool) {
} return float32(x), (x < 5)
})
func Map[T Numeric](s any, f func(T) T) (r []T) { DoMap[float32](func(x int) (float64, bool) {
if s := R.ValueOf(s); s.Kind() == R.Func { return float64(x), (x < 5)
V := R.ValueOf(r).Type().Elem() })
for i := 0; ; i++ { }
p := []R.Value{R.ValueOf(i)}
if p = s.Call(p); p[1].Interface() == true { 061_map.go
switch V.Kind() { Map(0x108f560, func()): [0 2 4 6 8]
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: Map(0x108f580, func()): [0 2 4 6 8]
r = append(r, f(T(p[0].Int())))
case R.Float32, R.Float64:
r = append(r, f(T(p[0].Float())))
}
} else {
break
}
}
}
return
}
MAPPING COLLECTIONS
062_map.go

package main func main() {


DoMap[int](func(x int) (int, bool) {
import ( return x, (x < 5)
"fmt" })
R "reflect" DoMap[float32](func(x int) (float32, bool) {
) return float32(x), (x < 5)
})
func Map[T any](s any, f func(T) T) (r []T) { DoMap[float64](func(x int) (float64, bool) {
if s := R.ValueOf(s); s.Kind() == R.Func { return float64(x), (x < 5)
for i := 0; ; i++ { })
p := []R.Value{R.ValueOf(i)} }
if p = s.Call(p); p[1].Interface() == true {
r = append(r, f(p[0].Interface().(T))) 062_map.go
} else { Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
break Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
} Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
}
}
return
}

func DoMap[T ~int | ~float32 | ~float64](s any) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}
MAPPING COLLECTIONS
062_map.go

package main func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
import ( return v * 2
"fmt" })
R "reflect" fmt.Printf("Map(%v, func()): %v\n", s, r)
) }

func Map[T any](s any, f func(T) T) (r []T) { func main() {


switch s := R.ValueOf(s); s.Kind() { DoMap[int](map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
case R.Map: DoMap[int](map[int8]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
switch s.Type().Key().Kind() { DoMap[int](map[int32]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: }
r = make([]T, s.Len())
for i := s.MapRange(); i.Next(); { 062_map.go
x := int(i.Key().Int()) Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
if x >= len(r) { Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
n := make([]T, x+1) Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
copy(n, r)
r = n
}
r[x] = f(i.Value().Interface().(T))
}
}
}

return
}
MAPPING COLLECTIONS
063_map.go

package main 063_map.go


Map([0 1 2], func()): [0 2 4]
import ( Map([0 1 2], func()): [0 2 4]
"fmt" Map([0 1 2], func()): []
R "reflect"
)

func Map[T any](s any, f func(T) T) (r []T) {


if s := R.ValueOf(s); s.Kind() == R.Array {
defer func() {
recover()
}()
for i := 0; i < s.Len(); i++ {
r = append(r, f(s.Index(i).Interface().(T)))
}
}
return
}

func DoMap[T ~int | ~float32](s any) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}

func main() {
DoMap[int]([3]int{0, 1, 2})
DoMap[float32]([3]float32{0, 1, 2})
DoMap[float32]([3]float64{0, 1, 2})
}
MAPPING COLLECTIONS
064_map.go

package main func main() {


ic := make(chan int)
import "fmt" go Pump(ic, 0, 1, 2, 3, 4)

func Map[T any](s any, f func(T) T) (r []T) { DoMap[int](ic)


switch s := s.(type) { DoMap[rune]("01234")
case string: }
for _, x := range s {
r = append(r, f(any(x).(T))) 064_map.go
} Map(0xc00011c000, func()): [0 2 4 6 8]
case chan T: Map(01234, func()): [96 98 100 102 104]
for x := range s {
r = append(r, f(x))
}
}
return
}

func DoMap[T ~int | ~rune](s any) {


r := Map(s, func(v T) T {
return v * 2
})
fmt.Printf("Map(%v, func()): %v\n", s, r)
}

func Pump[T any](ic chan<- T, v ...T) {


for _, v := range v {
ic <- v
}
close(ic)
}
MAPPING COLLECTIONS
065_map.go

package main default:


switch s := R.ValueOf(s); s.Kind() {
import R "reflect" case R.Array:
for i := 0; i < s.Len(); i++ {
func Map[T any](s any, f func(T) T) (r []T) { r = append(r, f(s.Index(i).Interface().(T)))
switch s := s.(type) { }
case interface{ Range(f func(int, T)) }: case R.Map:
s.Range(func(i int, v T) { switch s.Type().Key().Kind() {
r = append(r, f(v)) case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:
}) r = make([]T, s.Len())
case string: for i := s.MapRange(); i.Next(); {
for _, x := range s { x := int(i.Key().Int())
r = append(r, f(any(x).(T))) if x >= len(r) {
} n := make([]T, x+1)
case []T: copy(n, r)
for _, v := range s { r = n
r = append(r, f(v)) }
} r[x] = f(i.Value().Interface().(T))
case map[int]T: }
r = make([]T, len(s)) }
for i, v := range s { case R.Func:
if i >= len(r) { for i := 0; ; i++ {
n := make([]T, i-1) p := []R.Value{R.ValueOf(i)}
copy(n, r) if p = s.Call(p); p[1].Interface() == true {
r = n r = append(r, f(p[0].Interface().(T)))
} } else {
r[i] = f(v) break
} }
case chan T: }
for x := range s { }
r = append(r, f(x)) }
} return
}
RESOURCES

‣ github.com/feyeleanor/GoGenericsTalk

‣ slideshare.net/feyeleanor

‣ leanpub.com/GoNotebook

‣ gobyexample.com/generics

‣ go.dev/blog/intro-generics

‣ go.dev/doc/tutorial/generics

You might also like