SlideShare a Scribd company logo
1 of 67
Download to read offline
GENERICS, REFLECTION,


AND EFFICIENT COLLECTIONS
ELEANOR MCHUGH
PORTRAIT OF AN ARTIST...
PORTRAIT OF AN ARTIST...
▸ physics


▸ cryptography


▸ embedded systems


▸ dynamic languages


▸ dns provisioning


▸ network scaling


▸ highly questionable taste in music
g
i
t
h
u
b
:
/
/
f
e
y
e
l
e
a
n
o
r
Eleanor McHugh
s
l
i
d
e
s
h
a
r
e
:
/
/
f
e
y
e
l
e
a
n
o
r
leanpub:/
/GoNotebook
PREDEFINED COLLECTION TYPES IN GO
ARRAYS
001_array.go


package main


import "fmt"


func main() {


	
var a [3]int


	
fmt.Println("len(a):", len(a))


	
fmt.Println("cap(a):", cap(a))


	
fmt.Printf("a: %v (%T)n", a, a)


	
fmt.Printf("a[1]: %v (%T)n", a[1], a[1])


	
fmt.Printf("a[0:1]: %v (%T)n", a[0:1], a[0:1])


	
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]: %vn", 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


002_array.go


package main


func main() {


	
var a [3]int


	
_ = append(a, 1)


}


go run 002_array.go


# command-line-arguments


./002_array.go:6:13: first argument to append must be a slice;
have a (variable of type [3]int)
SLICES
003_slice.go


package main


import "fmt"


func main() {


	
var s []int


	
fmt.Println("len(s):", len(s))


	
fmt.Println("cap(s):", cap(s))


	
fmt.Printf("s: %v (%T)n", s, s)


	
fmt.Printf("s[0:1]: %v (%T)n", s[0:1], s[0:1])


}


go run 003_slice.go


len(s): 0


cap(s): 0


s: [] ([]int)


panic: runtime error: slice bounds out of range [:1] with
capacity 0


goroutine 1 [running]:


main.main()


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/003_slice.go:11 +0x171


exit status 2


004_slice.go


package main


import "fmt"


func main() {


	
var s []int


	
s = append(s, 0, 1, 2)


	
fmt.Printf("s: %v (%T)n", s, s)


	
fmt.Printf("s[:1]: %v (%T)n", s[:1], s[:1])


	
fmt.Printf("s[1:]: %v (%T)n", s[1:], s[1:])


	
s = append(s, s...)


	
fmt.Printf("s: %v (%T)n", s, s)


	
s = make([]int, 3, 6)


	
fmt.Printf("s: %v (%T)n", s, s)


	
s = []int{2, 4, 6}


	
s[1] = s[2]


	
for i, v := range s {


	
	
fmt.Printf("s[%v]: %vn", i, v)


	
}


}


go run 004_slice.go


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


package main


import "fmt"


func main() {


	
var s string


	
fmt.Println("len(s):", len(s))


	
fmt.Printf("s: %v (%T)n", s, s)


	
fmt.Printf("s[0:1]: %v (%T)n", s[0:1], s[0:1])


}


go run 005_string.go


len(s): 0


s: (string)


panic: runtime error: slice bounds out of range [:1] with length
0


goroutine 1 [running]:


main.main()


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/005_string.go:10 +0xf1


exit status 2


006_string.go


package main


import "fmt"


func main() {


	
s := "abc"


	
fmt.Println("len(s):", len(s))


	
fmt.Printf("s: %v (%T)n", s, s)


	
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)


	
}


	
b := []byte(s)


	
for i, v := range b {


	
	
fmt.Printf("b[%v]: %v (%T)n", i, v, v)


	
}


}


go run 006_string.go


len(s): 3


s: abc (string)


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


package main


import "fmt"


func main() {


	
var m map[int]int


	
fmt.Println("len(m):", len(m))


	
fmt.Println("m[1]", m[1])


	
m[1] = 1


}


go run 007_map.go


len(m): 0


m[1] 0


panic: assignment to entry in nil map


goroutine 1 [running]:


main.main()


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/005_map.go:10 +0xf9


exit status 2


008_map.go


package main


import "fmt"


func main() {


	
var m map[int]int


	
m = make(map[int]int)


	
m[1] = 1


	
fmt.Println("m[1]:", m[1])


	
delete(m, 1)


	
fmt.Println("m:", m)


	
x, ok := m[1]


	
fmt.Printf("x: %v, ok: %vn", x, ok)


	
m = map[int]int{0: 2, 3: 6}


	
fmt.Println("m:", m)


	
for k, v := range m {


	
	
fmt.Printf("m[%v]: %vn", k, v)


	
}


}


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


import "fmt"


func main() {


	
var c chan int


	
c = make(chan int)


	
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)


	
}


}


go run 009_channel.go


# command-line-arguments


./007_channel.go:15:3: invalid operation: cannot send to
receive-only channel c (variable of type <-chan int)


./007_channel.go:17:8: invalid operation: cannot close receive-
only channel c (variable of type <-chan int)


./007_channel.go:21:17: cannot range over c (variable of type
chan<- int) (receive from send-only channel)
CHANNELS
010_channel.go


package main


import "fmt"


func main() {


	
var c chan int


	
c = make(chan int)


	
fmt.Println("cap(c):", cap(c))


	
go send(c, 0, 2, 4, 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: %vn", len(c), n)


	
}


}


go run 010_channel.go


cap(c): 0


sending: 0


sending: 2


len(c): 0, n: 0


len(c): 0, n: 2


sending: 4


sending: 6


len(c): 0, n: 4


len(c): 0, n: 6
CHANNELS
011_channel.go


package main


import "fmt"


func main() {


	
var c chan int


	
c = make(chan int, 16)


	
fmt.Println("cap(c):", cap(c))


	
go send(c, 0, 2, 4, 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: %vn", len(c), n)


	
}


}


go run 011_channel.go


cap(c): 16


sending: 0


sending: 2


sending: 4


sending: 6


len(c): 3, n: 0


len(c): 2, n: 2


len(c): 1, n: 4


len(c): 0, n: 6
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


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)


	
}


	
n, open := <-c


	
fmt.Printf("n: %v, open: %vn", n, open)


}


go run 013_channel.go


sending: 0


sending: 2


sending: 4


sending: 6


n: 0


n: 2


n: 4


n: 6


n: 0, open: false
CHANNELS
014_channel.go


package main


import "fmt"


func main() {


	
c := make(chan int, 16)


	
done := make(chan bool)


	
go func(v ...int) {


	
	
for _, n := range v {


	
	
	
fmt.Println("sending:", n)


	
	
	
c <- n


	
	
}


	
	
close(c)


	
	
done <- true


	
}(0, 2, 4, 6)


Receiver:


	
for {


	
	
select {


	
	
case n, ok := <-c:


	
	
	
if ok {


	
	
	
	
fmt.Printf("len(c): %v, n: %vn", len(c), n)


	
	
	
}


	
	
case <-done:


	
	
	
break Receiver


	
	
}


	
}


}


go run 014_channel.go


sending: 0


sending: 2


sending: 4


sending: 6


len(c): 3, n: 0


go run 014_channel.go


sending: 0


sending: 2


sending: 4


sending: 6


len(c): 3, n: 0


len(c): 2, n: 2


len(c): 1, n: 4
CHANNELS
015_channel.go


package main


import "fmt"


func main() {


	
c := make(chan int)


	
done := make(chan bool)


	
go func(v ...int) {


	
	
for _, n := range v {


	
	
	
fmt.Println("sending:", n)


	
	
	
c <- n


	
	
}


	
	
close(c)


	
	
done <- true


	
}(0, 2, 4, 6)


Receiver:


	
for {


	
	
select {


	
	
case n, ok := <-c:


	
	
	
if ok {


	
	
	
	
fmt.Printf("len(c): %v, n: %vn", len(c), n)


	
	
	
}


	
	
case <-done:


	
	
	
break Receiver


	
	
}


	
}


}


go run 015_channel.go


sending: 0


sending: 2


len(c): 0, n: 0


len(c): 0, n: 2


sending: 4


sending: 6


len(c): 0, n: 4


len(c): 0, n: 6


go run 015_channel.go


sending: 0


sending: 2


len(c): 0, n: 0


len(c): 0, n: 2


sending: 4


sending: 6


len(c): 0, n: 4


len(c): 0, n: 6
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() = %vn", s, s.Sum())


}


go run 014_udt.go


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


package main


import "fmt"


type Summable interface {


	
Sum() any


}


type ISlice []int


func (s ISlice) Sum() any {


	
r := 0


	
for x := len(s) - 1; x > -1; x-- {


	
	
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


}


func main() {


	
var s Summable


	
s = ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("%v.Sum() = %vn", s, s.Sum())


	
s = FSlice{0, 1, 2, 3, 4}


	
fmt.Printf("%v.Sum() = %vn", s, s.Sum())


}


go run 017_udt.go


(main.ISlice)[0 1 2 3 4].Sum() = 10


(main.FSlice)[0 1 2 3 4].Sum() = 10
USER-DEFINED COLLECTIONS
018_udt.go


package main


import "fmt"


type Numeric interface {


	
~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() = %vn", i, i, i.Sum())


	
i = ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("(%T)%v.Sum() = %vn", i, i, i.Sum())


	
f := Summable[float32]{0, 1, 2, 3, 4}


	
fmt.Printf("(%T)%v.Sum() = %vn", f, f, f.Sum())


	
f = FSlice{0, 1, 2, 3, 4}


	
fmt.Printf("(%T)%v.Sum() = %vn", f, f, f.Sum())


}


go run 018_udt.go


(main.Summable[int])[0 1 2 3 4].Sum() = 10


(main.Summable[int])[0 1 2 3 4].Sum() = 10


(main.Summable[float32])[0 1 2 3 4].Sum() = 10


(main.Summable[float32])[0 1 2 3 4].Sum() = 10
USER-DEFINED COLLECTIONS
019_generic_func.go


package main


import "fmt"


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) = %vn", i, i, Sum(i))


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(i))


	
r := Sum(f).(float32)


	
fmt.Println("r =", r)


}


go run 019_generic_func.go


Sum([]int[0 1 2 3 4]) = 10


Sum([]float32[0 1 2 3 4]) = 10


r = 10
USER-DEFINED COLLECTIONS
020_generic_func.go


package main


import (


	
"fmt"


	
"reflect"


)


type ISlice []int


type FSlice []float32


func Sum(s any) (r any) {


	
if s := reflect.ValueOf(s); s.Kind() == reflect.Slice {


	
	
switch s.Type().Elem().Kind() {


	
	
case reflect.Int:


	
	
	
var x int


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
x += int(s.Index(i).Int())


	
	
	
}


	
	
	
r = x


	
	
case reflect.Float32:


	
	
	
var x float32


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
x += float32(s.Index(i).Float())


	
	
	
}


	
	
	
r = x


	
	
}


	
}


	
return


}


func main() {


	
i := []int{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", i, i, Sum(i))


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(f))


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


	
fmt.Printf("Sum(%T%v) = %vn", in, in, Sum(in))


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", is, is, Sum(is))


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


	
fmt.Printf("Sum(%T%v) = %vn", fs, fs, Sum(fs))


}


go run 020_generic_func.go


Sum([]int[0 1 2 3 4]) = 10


Sum([]float32[0 1 2 3 4]) = 10


Sum([]interface {}[0 1 2]) = <nil>


Sum(main.ISlice[0 1 2 3 4]) = 10


Sum(main.FSlice[0 1 2 3 4]) = 10
USER-DEFINED COLLECTIONS
021_generic_func.go


package main


import (


	
"fmt"


	
"reflect"


)


type ISlice []int


type FSlice []float32


func Sum(s any) (r any) {


	
if s := R.ValueOf(s); s.Kind() == R.Slice {


	
	
T := s.Type().Elem()


	
	
V := R.New(T)


	
	
E := V.Elem()


	
	
switch T.Kind() {


	
	
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
E.SetInt(E.Int() + s.Index(i).Int())


	
	
	
}


	
	
case R.Float32, R.Float64:


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
E.SetFloat(E.Float() + s.Index(i).Float())


	
	
	
}


	
	
}


	
	
r = E.Interface()


	
}


	
return


}


func main() {


	
i := []int{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", i, i, Sum(i))


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(f))


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


	
fmt.Printf("Sum(%T%v) = %vn", in, in, Sum(in))


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%T%v) = %vn", is, is, Sum(is))


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


	
fmt.Printf("Sum(%T%v) = %vn", fs, fs, Sum(fs))


}


go run 021_generic_func.go


Sum([]int[0 1 2 3 4]) = 10


Sum([]float32[0 1 2 3 4]) = 10


Sum([]interface {}[0 1 2]) = <nil>


Sum(main.ISlice[0 1 2 3 4]) = 10


Sum(main.FSlice[0 1 2 3 4]) = 10
USER-DEFINED COLLECTIONS
022_generic_func.go


package main


import "fmt"


type Numeric interface {


	
~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) = %vn", i[0], i, Sum[int](i))


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", f[0], f, Sum[float32](f))


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum[int](is))


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


	
fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum[float32](fs))


}


go run 022_generic_func.go


Sum[int]([0 1 2 3 4]) = 10


Sum[float32]([0 1 2 3 4]) = 10


Sum[int]([0 1 2 3 4]) = 10


Sum[float32]([0 1 2 3 4]) = 10
USER-DEFINED COLLECTIONS
023_generic_func.go


package main


import "fmt"


type Numeric interface {


	
~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) = %vn", i[0], i, Sum(i))


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", f[0], f, Sum(f))


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is))


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


	
fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum(fs))


}


go run 023_generic_func.go


Sum[int]([0 1 2 3 4]) = 10


Sum[float32]([0 1 2 3 4]) = 10


Sum[int]([0 1 2 3 4]) = 10


Sum[float32]([0 1 2 3 4]) = 10
USER-DEFINED COLLECTIONS
024_generic_func.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Indexable[T any] interface {


	
~[]T


}


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


	
for _, x := range s {


	
	
r += x


	
}


	
return


}


type ISlice Indexable[int]


func main() {


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is))


}


go run 024_generic_func.go


# command-line-arguments


./023_generic_func.go:23:8: invalid composite literal type
ISlice


025_generic_func.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


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


	
for _, x := range s {


	
	
r += x


	
}


	
return


}


type Indexable[T any] interface {


	
~[]T


}


type ISlice []int


type FSlice []float32


func main() {


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is))


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


	
fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum(fs))


}


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


import "fmt"


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%vn", 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%vn", fs, fs, 6, fs2, fs2)


}


go run 026_generic_func.go


Append[main.ISlice]([0 1 2 3 4], 5) = main.ISlice[0 1 2 3 4 5]


Append[[]float32]([0 1 2 3 4], 6) = []float32[0 1 2 3 4 6]
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) = %vn", 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


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


}


func main() {


	
f := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%v) = %vn", f, Sum(f))


}


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:


	
[]float32 does not implement Iterable (missing Range method)


029_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 FSlice []float32


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


	
for i, v := range s {


	
	
f(i, v)


	
}


}


func main() {


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


	
fmt.Printf("Sum(%v) = %vn", 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


import "fmt"


type Iterable interface {


	
Range(f func(int, any))


}


func Sum(s Iterable) (r any) {


	
s.Range(func(i int, v any) {


	
	
r += v


	
})


	
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)


	
}


}


func main() {


	
is := FSlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%v) = %vn", is, Sum(is))


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


	
fmt.Printf("Sum(%v) = %vn", fs, Sum(fs))


}


go 030_high_order_func.go


# command-line-arguments


./030_high_order_func.go:11:3: invalid operation: operator + not
defined on r (variable of type any)
HIGHER ORDER FUNCTIONS
031_high_order_func.go


package main


import "fmt"


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) = %vn", is, Sum(is))


}


go 031_high_order_func.go


# command-line-arguments


./031_high_order_func.go:30:39: type ISlice of is does not match
Iterable[T] (cannot infer T)
HIGHER ORDER FUNCTIONS
032_high_order_func.go


package main


import "fmt"


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)


	
}


}


type FSlice []float32


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


	
for i, v := range s {


	
	
f(i, v)


	
}


}


func main() {


	
is := ISlice{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%v) = %vn", is, Sum[int](is))


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


	
fmt.Printf("Sum(%v) = %vn", fs, Sum[float32](fs))


}


go 032_high_order_func.go


Sum([0 1 2 3 4]) = 10


Sum([0 1 2 3 4]) = 10
HIGHER ORDER FUNCTIONS
033_high_order_func.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Iterable[T Numeric] interface {


	
Range(f func(int, T))


}


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


	
switch s := s.(type) {


	
case Iterable[T]:


	
	
fmt.Printf("case Iterable[%T]n", s)


	
	
var x T


	
	
s.Range(func(i int, v T) {


	
	
	
x += v


	
	
})


	
	
r = x


	
case []T:


	
	
fmt.Printf("case %Tn", s)


	
	
var x T


	
	
for _, v := range s {


	
	
	
x += v


	
	
}


	
	
r = x


	
}


	
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[%T]n", is, Sum[int](is), is[0])


	
fs := []float32{0, 1, 2, 3, 4}


	
fmt.Printf("Sum(%v) = %v[%T]n", fs, Sum[float32](fs), fs[0])


}


go 033_high_order_func.go


case Iterable[main.ISlice]


Sum([0 1 2 3 4]) = 10 [int]


case []float32


Sum([0 1 2 3 4]) = 10 [float32]
REDUCING COLLECTIONS
REDUCING COLLECTIONS
034_reduce.go


package main


import "fmt"


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)


}


go 034_reduce.go


Reduce([0 1 2 3 4], f()) = 10 [int]


Reduce([0 1 2 3 4], f()) = 10 [float32]
REDUCING COLLECTIONS
035_reduce.go


package main


import "fmt"


func Reduce(s any, f func(any, any) any) (r any) {


	
switch s := s.(type) {


	
case []int:


	
	
var x int


	
	
for _, v := range s {


	
	
	
x = f(x, v).(int)


	
	
}


	
	
r = x


	
case []float32:


	
	
var x float32


	
	
for _, v := range s {


	
	
	
x = f(x, v).(float32)


	
	
}


	
	
r = x


	
}


	
return


}


func main() {


	
is := []int{0, 1, 2, 3, 4}


	
ir := Reduce(is, func(x any, v any) any {


	
	
return x.(int) + v.(int)


	
})


	
fmt.Printf("Reduce(%v, f()) = %v [%T]n", is, ir, ir)


	
fs := []float32{0, 1, 2, 3, 4}


	
fr := Reduce(fs, func(x any, v any) any {


	
	
return x.(float32) + v.(float32)


	
})


	
fmt.Printf("Reduce(%v, f()) = %v [%T]n", fs, fr, fr)


}


go 035_reduce.go


Reduce([0 1 2 3 4], f()) = 10 [int]


Reduce([0 1 2 3 4], f()) = 10 [float32]
REDUCING COLLECTIONS
036_reduce.go


package main


import (


	
"fmt"


	
R "reflect"


)


func Reduce(s any, f func(any, any) any) (r any) {


	
if s := R.ValueOf(s); s.Kind() == R.Slice {


	
	
T := s.Type().Elem()


	
	
V := R.New(T)


	
	
E := V.Elem()


	
	
switch T.Kind() {


	
	
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
v := R.ValueOf(f(


	
	
	
	
	
E.Interface(),


	
	
	
	
	
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


}


func main() {


	
is := []int{0, 1, 2, 3, 4}


	
ir := Reduce(is, func(x any, v any) any {


	
	
return x.(int) + v.(int)


	
})


	
fmt.Printf("Reduce(%v, f()) = %v [%T]n", is, ir, ir)


	
fs := []float32{0, 1, 2, 3, 4}


	
fr := Reduce(fs, func(x any, v any) any {


	
	
return x.(float32) + v.(float32)


	
})


	
fmt.Printf("Reduce(%v, f()) = %v [%T]n", fs, fr, fr)


}


go 036_reduce.go


Reduce([0 1 2 3 4], f()) = 10 [int]


Reduce([0 1 2 3 4], f()) = 10 [float32]
REDUCING COLLECTIONS
037_reduce.go


package main


import "fmt"


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)


}


go 037_reduce.go


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


(main.Reducible[float32])[0 1 2 3 4].Reduce(f()) = 10 [float32]
REDUCING COLLECTIONS
038_reduce.go


package main


import "fmt"


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)


}


go 038_reduce.go


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


map[0:0 1:1 2:2 3:3 4:4].Reduce(f()) = 10 [float32]
REDUCING COLLECTIONS
039_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Reducible[T Numeric] chan T


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


	
for x := range c {


	
	
r = f(r, x)


	
}


	
return


}


func (c Reducible[T]) Pump(v ...T) {


	
for _, v := range v {


	
	
c <- v


	
}


	
close(c)


}


type IChan = Reducible[int]


type FChan = Reducible[float32]


func main() {


	
ic := make(IChan)


	
go ic.Pump(0, 1, 2, 3, 4)


	
ir := ic.Reduce(func(x, v int) int {


	
	
return x + v


	
})


	
fmt.Printf("(chan ic).Reduce(f()) = %v [%T]n", ir, ir)


	
fc := make(FChan)


	
go fc.Pump(0, 1, 2, 3, 4)


	
fr := fc.Reduce(func(x, v float32) float32 {


	
	
return x + v


	
})


	
fmt.Printf("(chan fc).Reduce(f()) = %v [%T]n", fr, fr)


}


go 039_reduce.go


(chan ic).Reduce(f()) = 10 [int]


(chan fc).Reduce(f()) = 10 [float32]
REDUCING COLLECTIONS
040_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


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


	
switch c := c.(type) {


	
case []T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case map[int]T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case chan T:


	
	
for x := range c {


	
	
	
r = f(r, x)


	
	
}


	
}


	
return


}


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


	
for _, v := range v {


	
	
ic <- v


	
}


	
close(ic)


}


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)


	
im := map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}


	
ir = Reduce(im, func(x, v int) int {


	
	
return x + v


	
})


	
fmt.Printf("Reduce(%v, f()) = %v [%T]n", im, ir, ir)


	
ic := make(chan int)


	
go Pump(ic, 0, 1, 2, 3, 4)


	
ir = Reduce(ic, func(x, v int) int {


	
	
return x + v


	
})


	
fmt.Printf("(chan ic).Reduce(f()) = %v [%T]n", ir, ir)


}


go 040_reduce.go


Reduce([0 1 2 3 4], f()) = 10 [int]


Reduce(map[0:0 1:1 2:2 3:3 4:4], f()) = 10 [int]


(chan ic).Reduce(f()) = 10 [int]
REDUCING COLLECTIONS
041_reduce.go


package main


import (


	
"fmt"


	
R "reflect"


)


type Numeric interface {


	
~int | ~float32


}


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


	
switch c := c.(type) {


	
case chan T:


	
	
for x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case string:


	
	
for _, x := range c {


	
	
	
r = f(r, T(x))


	
	
}


	
default:


	
	
switch c := R.ValueOf(c); c.Kind() {


	
	
case R.Map:


	
	
	
for i := c.MapRange(); i.Next(); {


	
	
	
	
r = f(r, i.Value().Interface().(T))


	
	
	
}


	
	
}


	
}


	
return


}


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


	
for _, v := range v {


	
	
ic <- v


	
}


	
close(ic)


}


func DoReduce(c any) {


	
ir := Reduce(c, func(x, v int) int {


	
	
return x + v


	
})


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, ir, ir)


}


func main() {


	
ic := make(chan int)


	
go Pump(ic, 0, 1, 2, 3, 4)


	
DoReduce(ic)


	
DoReduce("01234")


	
DoReduce(map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})


	
DoReduce(map[string]int{


	
	
"0": 0, "1": 1, "2": 2, "3": 3, "4": 4})


}


go 041_reduce.go


[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]
REDUCING COLLECTIONS
042_reduce.go


package main


import (


	
"fmt"


	
R "reflect"


)


type Numeric interface {


	
~int | ~float32


}


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


	
switch c := c.(type) {


	
case [1]T:


	
	
for x := range c {


	
	
	
r = f(r, T(x))


	
	
}


	
case [2]T:


	
	
for _, x := range c {


	
	
	
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


}


func DoReduce(c any) {


	
ir := Reduce(c, func(x, v int) int {


	
	
return x + v


	
})


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, ir, ir)


}


func main() {


	
DoReduce([0]int{})


	
DoReduce([1]int{0})


	
DoReduce([2]int{0, 1})


	
DoReduce([5]int{0, 1, 2, 3, 4})


}


go 042_reduce.go


[[0]int]Reduce([], f()) = 0[int]


[[1]int]Reduce([0], f()) = 0[int]


[[2]int]Reduce([0 1], f()) = 1[int]


[[5]int]Reduce([0 1 2 3 4], f()) = 10[int]
REDUCING COLLECTIONS
043_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Reducible[T Numeric] interface {


	
Reduce(func(T, T) T) T


}


type ISlice []int


func (s ISlice) Reduce(f func(x, v int) int) (r int) {


	
for _, v := range s {


	
	
r = f(r, v)


	
}


	
return


}


type FArray [3]float32


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


	
for _, v := range a {


	
	
r = f(r, v)


	
}


	
return


}


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


	
switch c := c.(type) {


	
case Reducible[T]:


	
	
r = c.Reduce(f)


	
}


	
return


}


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


	
r := Reduce(c, f)


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r)


}


func main() {


	
DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int {


	
	
return x + v


	
})


	
DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 {


	
	
return x + v


	
})


}


go 043_reduce.go


[main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int]


[main.FArray]Reduce([0 1 2], f()) = 3[float32]
REDUCING COLLECTIONS
044_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Iterable[T Numeric] interface {


	
Range(f func(int, T))


}


type Reducible[T Numeric] interface {


	
Reduce(func(T, T) T) T


}


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++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


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


	
r := Reduce(c, f)


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r)


}


func Adder[T Numeric]() func(T, T) T {


	
return func(x, v T) T {


	
	
return x + v


	
}


}


func main() {


	
DoReduce(func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}, Adder[int]())


	
DoReduce(func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
}, Adder[float32]())


}


go 044_reduce.go


[func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]


[func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
REDUCING COLLECTIONS
045_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


type Iterable[T Numeric] interface {


	
Range(f func(int, T))


}


type Reducible[T Numeric] interface {


	
Reduce(func(T, T) T) T


}


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++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


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


	
r := Reduce(c, f)


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r)


}


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


	
}


}


func main() {


	
i := func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}


	
DoReduce(i, Adder(i))


	
f := func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
}


	
DoReduce(f, Adder(f))


}


go 045_reduce.go


[func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int]


[func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
REDUCING COLLECTIONS
046_reduce.go


package main


import "fmt"


type Numeric interface {


	
~int | ~float32


}


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++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
case NFunc[T]:


	
	
r = Reduce((func(int) (T, bool))(c), f)


	
}


	
return


}


type NFunc[T Numeric] func(int) (T, bool)


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


	
r := Reduce(c, f)


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r)


}


func Adder[T Numeric]() func(T, T) T {


	
return func(x, v T) T {


	
	
return x + v


	
}


}


func main() {


	
DoReduce(func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}, Adder[int]())


	
DoReduce(func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
}, Adder[float32]())


	
DoReduce(NFunc[int](func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}), Adder[int]())


}


go 046_reduce.go


[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


import (


	
"fmt"


	
R "reflect"


)


type Numeric interface {


	
~int | ~float32


}


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


	
if c := R.ValueOf(c); c.Kind() == R.Func {


	
	
for i := 0; ; i++ {


	
	
	
p := []R.Value{R.ValueOf(i)}


	
	
	
if p = c.Call(p); p[1].Interface() == true {


	
	
	
	
r = f(r, p[0].Interface().(T))


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


type NFunc[T Numeric] func(int) (T, bool)


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


	
r := Reduce(c, f)


	
fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r)


}


func Adder[T Numeric]() func(T, T) T {


	
return func(x, v T) T {


	
	
return x + v


	
}


}


func main() {


	
DoReduce(func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}, Adder[int]())


	
DoReduce(func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
}, Adder[float32]())


	
DoReduce(NFunc[int](func(x int) (int, bool) {


	
	
return x, (x < 5)


	
}), Adder[int]())


}


go 047_reduce.go


[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
048_reduce.go


package main


import (


	
"fmt"


	
R "reflect"


)


type Numeric interface {


	
~int | ~int8 | ~int16 | ~int32 | ~int64 |


	
	
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |


	
	
~float32 | ~float64


}


type Iterable[T Numeric] interface {


	
Range(f func(int, T))


}


type Reducible[T Numeric] interface {


	
Reduce(func(T, T) T) T


}


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


	
switch c := c.(type) {


	
case Iterable[T]:


	
	
c.Range(func(i int, v T) {


	
	
	
r = f(r, v)


	
	
})


	
case Reducible[T]:


	
	
r = c.Reduce(f)


	
case string:


	
	
for _, x := range c {


	
	
	
r = f(r, T(x))


	
	
}


	
case T:


	
	
r = f(r, c)


	
case []T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case map[int]T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case func(int) (T, bool):


	
	
for i := 0; ; i++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
case chan T:


	
	
for x := range c {


	
	
	
r = f(r, x)


	
	
}


	
default:


	
	
switch c := R.ValueOf(c); c.Kind() {


	
	
case R.Map:


	
	
	
for i := c.MapRange(); i.Next(); {


	
	
	
	
r = f(r, i.Value().Interface().(T))


	
	
	
}


	
	
case R.Array:


	
	
	
for i := 0; i < c.Len(); i++ {


	
	
	
	
r = f(r, c.Index(i).Interface().(T))


	
	
	
}


	
	
case R.Func:


	
	
	
for i := 0; ; i++ {


	
	
	
	
p := []R.Value{R.ValueOf(i)}


	
	
	
	
if p = c.Call(p); p[1].Interface() == true {


	
	
	
	
	
r = f(r, p[0].Interface().(T))


	
	
	
	
} else {


	
	
	
	
	
break


	
	
	
	
}


	
	
	
}


	
	
}


	
}


	
return


}
REDUCING COLLECTIONS
049_reduce.go


package main


import R "reflect"


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


	
switch c := c.(type) {


	
case interface{ Range(f func(int, T)) }:


	
	
c.Range(func(i int, v T) {


	
	
	
r = f(r, v)


	
	
})


	
case interface{ Reduce(func(T, T) T) T }:


	
	
r = c.Reduce(f)


	
case string:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case T:


	
	
r = f(r, c)


	
case []T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case map[int]T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case func(int) (T, bool):


	
	
for i := 0; ; i++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
case chan T:


	
	
for x := range c {


	
	
	
r = f(r, x)


	
	
}


	
default:


	
	
switch c := R.ValueOf(c); c.Kind() {


	
	
case R.Map:


	
	
	
for i := c.MapRange(); i.Next(); {


	
	
	
	
r = f(r, i.Value().Interface().(T))


	
	
	
}


	
	
case R.Array:


	
	
	
for i := 0; i < c.Len(); i++ {


	
	
	
	
r = f(r, c.Index(i).Interface().(T))


	
	
	
}


	
	
case R.Func:


	
	
	
for i := 0; ; i++ {


	
	
	
	
p := []R.Value{R.ValueOf(i)}


	
	
	
	
if p = c.Call(p); p[1].Interface() == true {


	
	
	
	
	
r = f(r, p[0].Interface().(T))


	
	
	
	
} else {


	
	
	
	
	
break


	
	
	
	
}


	
	
	
}


	
	
}


	
}


	
return


}


func main() {}


go 049_reduce.go


# 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


import "fmt"


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


	
switch c := c.(type) {


	
case interface{ Range(f func(int, T)) }:


	
	
c.Range(func(i int, v T) {


	
	
	
r = f(r, v)


	
	
})


	
case interface{ Reduce(func(T, T) T) T }:


	
	
r = c.Reduce(f)


	
}


	
return


}


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)


}


type ISlice []int


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


	
for i, v := range s {


	
	
f(i, v)


	
}


}


type FArray [3]float32


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


	
for _, v := range a {


	
	
r = f(r, v)


	
}


	
return


}


func main() {


	
DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int {


	
	
return x + v


	
})


	
DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 {


	
	
return x + v


	
})


}


go 050_reduce.go


[main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int]


[main.FArray]Reduce([0 1 2], f()) = 3[float32]
REDUCING COLLECTIONS
051_reduce.go


package main


import "fmt"


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


	
switch c := c.(type) {


	
case string:


	
	
for _, x := range c {


	
	
	
r = f(r, any(x).(T))


	
	
}


	
}


	
return


}


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)


}


func main() {


	
DoReduce[rune]("01234", func(r, x rune) rune {


	
	
return r + x - 48


	
})


}


go 051_reduce.go


[string]Reduce(01234, f()) = 10[int32]


052_reduce.go


package main


import (


	
"fmt"


	
R "reflect"


)


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


	
switch c := R.ValueOf(c); c.Kind() {


	
case R.String:


	
	
for _, x := range c.Interface().(string) {


	
	
	
r = f(r, any(x).(T))


	
	
}


	
}


	
return


}


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)


}


func main() {


	
DoReduce("01234", func(x, v rune) rune {


	
	
return x + v - 48


	
})


}


go 052_reduce.go


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


package main


import R "reflect"


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


	
switch c := c.(type) {


	
case interface{ Range(f func(int, T)) }:


	
	
c.Range(func(i int, v T) {


	
	
	
r = f(r, v)


	
	
})


	
case interface{ Reduce(func(T, T) T) T }:


	
	
r = c.Reduce(f)


	
case string:


	
	
for _, x := range c {


	
	
	
r = f(r, any(x).(T))


	
	
}


	
case T:


	
	
r = f(r, c)


	
case []T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case map[int]T:


	
	
for _, x := range c {


	
	
	
r = f(r, x)


	
	
}


	
case func(int) (T, bool):


	
	
for i := 0; ; i++ {


	
	
	
if v, ok := c(i); ok {


	
	
	
	
r = f(r, v)


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
case chan T:


	
	
for x := range c {


	
	
	
r = f(r, x)


	
	
}


	
default:


	
	
switch c := R.ValueOf(c); c.Kind() {


	
	
case R.Map:


	
	
	
for i := c.MapRange(); i.Next(); {


	
	
	
	
r = f(r, i.Value().Interface().(T))


	
	
	
}


	
	
case R.Array:


	
	
	
for i := 0; i < c.Len(); i++ {


	
	
	
	
r = f(r, c.Index(i).Interface().(T))


	
	
	
}


	
	
case R.Func:


	
	
	
for i := 0; ; i++ {


	
	
	
	
p := []R.Value{R.ValueOf(i)}


	
	
	
	
if p = c.Call(p); p[1].Interface() == true {


	
	
	
	
	
r = f(r, p[0].Interface().(T))


	
	
	
	
} else {


	
	
	
	
	
break


	
	
	
	
}


	
	
	
}


	
	
}


	
}


	
return


}


func main() {}
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()): %vn", 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


import "fmt"


type Iterable[T any] interface {


	
Range(func(int, T))


}


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


	
switch s := s.(type) {


	
case Iterable[T]:


	
	
s.Range(func(i int, v T) {


	
	
	
r = append(r, f(v))


	
	
})


	
case []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()): %vn", s, r)


}


type ISlice []int


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


	
for i, v := range s {


	
	
f(i, v)


	
}


}


func main() {


	
DoMap(ISlice{0, 1, 2, 3, 4})


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


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


}


055_high_order_func.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]


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


package main


import "fmt"


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


	
switch s := s.(type) {


	
case interface{ Range(func(int, T)) }:


	
	
s.Range(func(i int, v T) {


	
	
	
r = append(r, f(v))


	
	
})


	
}


	
return


}


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


	
r := Map(s, func(v T) T {


	
	
return v * 2


	
})


	
fmt.Printf("Map(%v, func()): %vn", s, r)


}


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


	
	
}


	
}


}


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


	
return func(x int) (r T, ok bool) {


	
	
if i <= x && x <= j {


	
	
	
r, ok = f(x)


	
	
}


	
	
return


	
}


}


func main() {


	
DoMap[int](Limit(0, 4, func(x int) (int, bool) {


	
	
return x, true


	
}))


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


}


056_map.go


Map(0x108afc0, func()): [0 2 4 6 8]


Map(0x108ae20, func()): []
MAPPING COLLECTIONS
057_map.go


package main


import "fmt"


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


	
switch s := s.(type) {


	
case func(int) (T, bool):


	
	
for i := 0; ; i++ {


	
	
	
if v, ok := s(i); ok {


	
	
	
	
r = append(r, f(v))


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


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


	
	
}


	
}


}


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


	
r := Map(s, func(v T) T {


	
	
return v * 2


	
})


	
fmt.Printf("Map(%v, func()): %vn", s, r)


}


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


	
return func(x int) (r T, ok bool) {


	
	
if i <= x && x <= j {


	
	
	
r, ok = f(x)


	
	
}


	
	
return


	
}


}


func main() {


	
DoMap[int](Limit(0, 4, func(x int) (int, bool) {


	
	
return x, true


	
}))


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


}


057_map.go


Map(0x108aee0, func()): []


Map(0x108ae20, func()): [0 2 4 6 8]
MAPPING COLLECTIONS
058_map.go


package main


import "fmt"


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


	
switch s := s.(type) {


	
case NFunc[T]:


	
	
for i := 0; ; i++ {


	
	
	
if v, ok := s(i); ok {


	
	
	
	
r = append(r, f(v))


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


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


	
	
}


	
}


}


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


	
r := Map(s, func(v T) T {


	
	
return v * 2


	
})


	
fmt.Printf("Map(%v, func()): %vn", s, r)


}


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


	
return func(x int) (r T, ok bool) {


	
	
if i <= x && x <= j {


	
	
	
r, ok = f(x)


	
	
}


	
	
return


	
}


}


func main() {


	
DoMap[int](Limit(0, 4, func(x int) (int, bool) {


	
	
return x, true


	
}))


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


}


058_map.go


Map(0x108aee0, func()): [0 2 4 6 8]


Map(0x108ae20, func()): []
MAPPING COLLECTIONS
059_map.go


package main


import (


	
"fmt"


	
R "reflect"


)


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


	
if s := R.ValueOf(s); s.Kind() == R.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()): %vn", s, r)


}


func main() {


	
DoMap[float32](func(x int) (float64, bool) {


	
	
return float64(x), (x < 5)


	
})


}


059_map.go


panic: interface conversion: interface {} is float64, not
float32


goroutine 1 [running]:


main.Map[...]({0x1099520, 0x10b0678?}, 0xc000107f10?)


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/050_high_order_func.go:21 +0x325


main.DoMap[...]({0x1099520, 0x10b0678})


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/050_high_order_func.go:31 +0x52


main.main()


	
/Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/
GoGenericsTalk/050_high_order_func.go:65 +0x79


exit status 2
MAPPING COLLECTIONS
060_map.go


package main


import (


	
"fmt"


	
R "reflect"


)


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


	
if s := R.ValueOf(s); s.Kind() == R.Func {


	
	
defer func() {


	
	
	
recover()


	
	
}()


	
	
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()): %vn", s, r)


}


func main() {


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


	
DoMap[float32](func(x int) (float64, bool) {


	
	
return float64(x), (x < 5)


	
})


}


060_map.go


Map(0x108f560, func()): [0 2 4 6 8]


Map(0x108f580, func()): []
MAPPING COLLECTIONS
061_map.go


package main


import (


	
"fmt"


	
R "reflect"


)


type Numeric interface {


	
~int | ~float32


}


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


	
if s := R.ValueOf(s); s.Kind() == R.Func {


	
	
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 {


	
	
	
	
switch V.Kind() {


	
	
	
	
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:


	
	
	
	
	
r = append(r, f(T(p[0].Int())))


	
	
	
	
case R.Float32, R.Float64:


	
	
	
	
	
r = append(r, f(T(p[0].Float())))


	
	
	
	
}


	
	
	
} else {


	
	
	
	
break


	
	
	
}


	
	
}


	
}


	
return


}


func DoMap[T Numeric](s any) {


	
r := Map(s, func(v T) T {


	
	
return v * 2


	
})


	
fmt.Printf("Map(%v, func()): %vn", s, r)


}


func main() {


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


	
DoMap[float32](func(x int) (float64, bool) {


	
	
return float64(x), (x < 5)


	
})


}


061_map.go


Map(0x108f560, func()): [0 2 4 6 8]


Map(0x108f580, func()): [0 2 4 6 8]
MAPPING COLLECTIONS
062_map.go


package main


import (


	
"fmt"


	
R "reflect"


)


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


	
if s := R.ValueOf(s); s.Kind() == R.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 | ~float64](s any) {


	
r := Map(s, func(v T) T {


	
	
return v * 2


	
})


	
fmt.Printf("Map(%v, func()): %vn", s, r)


}


func main() {


	
DoMap[int](func(x int) (int, bool) {


	
	
return x, (x < 5)


	
})


	
DoMap[float32](func(x int) (float32, bool) {


	
	
return float32(x), (x < 5)


	
})


	
DoMap[float64](func(x int) (float64, bool) {


	
	
return float64(x), (x < 5)


	
})


}


062_map.go


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]


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


package main


import (


	
"fmt"


	
R "reflect"


)


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


	
switch s := R.ValueOf(s); s.Kind() {


	
case R.Map:


	
	
switch s.Type().Key().Kind() {


	
	
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:


	
	
	
r = make([]T, s.Len())


	
	
	
for i := s.MapRange(); i.Next(); {


	
	
	
	
x := int(i.Key().Int())


	
	
	
	
if x >= len(r) {


	
	
	
	
	
n := make([]T, x+1)


	
	
	
	
	
copy(n, r)


	
	
	
	
	
r = n


	
	
	
	
}


	
	
	
	
r[x] = f(i.Value().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()): %vn", s, r)


}


func main() {


	
DoMap[int](map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})


	
DoMap[int](map[int8]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})


	
DoMap[int](map[int32]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4})


}


062_map.go


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]


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


package main


import (


	
"fmt"


	
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()): %vn", 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})


}


063_map.go


Map([0 1 2], func()): [0 2 4]


Map([0 1 2], func()): [0 2 4]


Map([0 1 2], func()): []
MAPPING COLLECTIONS
064_map.go


package main


import "fmt"


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


	
switch s := s.(type) {


	
case string:


	
	
for _, x := range s {


	
	
	
r = append(r, f(any(x).(T)))


	
	
}


	
case chan T:


	
	
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()): %vn", s, r)


}


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


	
for _, v := range v {


	
	
ic <- v


	
}


	
close(ic)


}


func main() {


	
ic := make(chan int)


	
go Pump(ic, 0, 1, 2, 3, 4)


	
DoMap[int](ic)


	
DoMap[rune]("01234")


}


064_map.go


Map(0xc00011c000, func()): [0 2 4 6 8]


Map(01234, func()): [96 98 100 102 104]
MAPPING COLLECTIONS
065_map.go


package main


import R "reflect"


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


	
switch s := s.(type) {


	
case interface{ Range(f func(int, T)) }:


	
	
s.Range(func(i int, v T) {


	
	
	
r = append(r, f(v))


	
	
})


	
case string:


	
	
for _, x := range s {


	
	
	
r = append(r, f(any(x).(T)))


	
	
}


	
case []T:


	
	
for _, v := range s {


	
	
	
r = append(r, f(v))


	
	
}


	
case map[int]T:


	
	
r = make([]T, len(s))


	
	
for i, v := range s {


	
	
	
if i >= len(r) {


	
	
	
	
n := make([]T, i-1)


	
	
	
	
copy(n, r)


	
	
	
	
r = n


	
	
	
}


	
	
	
r[i] = f(v)


	
	
}


	
case chan T:


	
	
for x := range s {


	
	
	
r = append(r, f(x))


	
	
}


	
default:


	
	
switch s := R.ValueOf(s); s.Kind() {


	
	
case R.Array:


	
	
	
for i := 0; i < s.Len(); i++ {


	
	
	
	
r = append(r, f(s.Index(i).Interface().(T)))


	
	
	
}


	
	
case R.Map:


	
	
	
switch s.Type().Key().Kind() {


	
	
	
case R.Int, R.Int8, R.Int16, R.Int32, R.Int64:


	
	
	
	
r = make([]T, s.Len())


	
	
	
	
for i := s.MapRange(); i.Next(); {


	
	
	
	
	
x := int(i.Key().Int())


	
	
	
	
	
if x >= len(r) {


	
	
	
	
	
	
n := make([]T, x+1)


	
	
	
	
	
	
copy(n, r)


	
	
	
	
	
	
r = n


	
	
	
	
	
}


	
	
	
	
	
r[x] = f(i.Value().Interface().(T))


	
	
	
	
}


	
	
	
}


	
	
case R.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


}
RESOURCES
‣ github.com/feyeleanor/GoGenericsTalk


‣ slideshare.net/feyeleanor


‣ leanpub.com/GoNotebook


‣ gobyexample.com/generics


‣ go.dev/blog/intro-generics


‣ go.dev/doc/tutorial/generics


‣ bitfieldconsulting.com/golang/generics

More Related Content

What's hot (20)

Beer
BeerBeer
Beer
 
1 beer and beer service
1 beer and beer service1 beer and beer service
1 beer and beer service
 
Beer
BeerBeer
Beer
 
Vodka Production
Vodka ProductionVodka Production
Vodka Production
 
Kitchen equipments
Kitchen equipmentsKitchen equipments
Kitchen equipments
 
Glasswares
GlasswaresGlasswares
Glasswares
 
Beverages-Rasna
Beverages-RasnaBeverages-Rasna
Beverages-Rasna
 
pasteurization
pasteurizationpasteurization
pasteurization
 
Chapter 1 (Occupational Health and Safety Hazards)
Chapter 1 (Occupational Health and Safety Hazards)Chapter 1 (Occupational Health and Safety Hazards)
Chapter 1 (Occupational Health and Safety Hazards)
 
Principles of HACCP for processing and packaging of fresh cut fruits and vege...
Principles of HACCP for processing and packaging of fresh cut fruits and vege...Principles of HACCP for processing and packaging of fresh cut fruits and vege...
Principles of HACCP for processing and packaging of fresh cut fruits and vege...
 
Cleaning and sanitization of dairy barn
Cleaning and sanitization of dairy barnCleaning and sanitization of dairy barn
Cleaning and sanitization of dairy barn
 
Storage facilities, layout and design
Storage facilities, layout and designStorage facilities, layout and design
Storage facilities, layout and design
 
FOOD SERVICE EQUIPMENT
FOOD SERVICE EQUIPMENTFOOD SERVICE EQUIPMENT
FOOD SERVICE EQUIPMENT
 
Milk processing
Milk processingMilk processing
Milk processing
 
Cream
CreamCream
Cream
 
whey beverage
whey beveragewhey beverage
whey beverage
 
home made wine
home made winehome made wine
home made wine
 
Dining Room Presentation
Dining Room PresentationDining Room Presentation
Dining Room Presentation
 
Types of kitchen shapes
Types of kitchen shapesTypes of kitchen shapes
Types of kitchen shapes
 
Glassware
GlasswareGlassware
Glassware
 

Similar to Generics, Reflection, and Efficient Collections

Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
Fourier series example
Fourier series exampleFourier series example
Fourier series exampleAbi finni
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my dayTor Ivry
 
Fourier project presentation
Fourier project  presentationFourier project  presentation
Fourier project presentation志璿 楊
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with goEleanor McHugh
 
Applied Digital Signal Processing 1st Edition Manolakis Solutions Manual
Applied Digital Signal Processing 1st Edition Manolakis Solutions ManualApplied Digital Signal Processing 1st Edition Manolakis Solutions Manual
Applied Digital Signal Processing 1st Edition Manolakis Solutions Manualtowojixi
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoEleanor McHugh
 
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...Codemotion
 
Unit 5 Foc
Unit 5 FocUnit 5 Foc
Unit 5 FocJAYA
 
Concepts of C [Module 2]
Concepts of C [Module 2]Concepts of C [Module 2]
Concepts of C [Module 2]Abhishek Sinha
 
Testing CLI tools with Go
Testing CLI tools with GoTesting CLI tools with Go
Testing CLI tools with GoRicardo Gerardi
 
III MCS python lab (1).pdf
III MCS python lab (1).pdfIII MCS python lab (1).pdf
III MCS python lab (1).pdfsrxerox
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby HackersEleanor McHugh
 

Similar to Generics, Reflection, and Efficient Collections (20)

Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
Fourier series example
Fourier series exampleFourier series example
Fourier series example
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Fourier project presentation
Fourier project  presentationFourier project  presentation
Fourier project presentation
 
Dsp manual
Dsp manualDsp manual
Dsp manual
 
Mcq cpup
Mcq cpupMcq cpup
Mcq cpup
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with go
 
Applied Digital Signal Processing 1st Edition Manolakis Solutions Manual
Applied Digital Signal Processing 1st Edition Manolakis Solutions ManualApplied Digital Signal Processing 1st Edition Manolakis Solutions Manual
Applied Digital Signal Processing 1st Edition Manolakis Solutions Manual
 
OFDMA MATLAB CODE.pdf
OFDMA MATLAB CODE.pdfOFDMA MATLAB CODE.pdf
OFDMA MATLAB CODE.pdf
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with Go
 
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...
going loopy - adventures in iteration with go - Eleanor McHugh - Codemotion M...
 
About Go
About GoAbout Go
About Go
 
Let's golang
Let's golangLet's golang
Let's golang
 
Unit 5 Foc
Unit 5 FocUnit 5 Foc
Unit 5 Foc
 
Go Lang Tutorial
Go Lang TutorialGo Lang Tutorial
Go Lang Tutorial
 
Concepts of C [Module 2]
Concepts of C [Module 2]Concepts of C [Module 2]
Concepts of C [Module 2]
 
String Manipulation Function and Header File Functions
String Manipulation Function and Header File FunctionsString Manipulation Function and Header File Functions
String Manipulation Function and Header File Functions
 
Testing CLI tools with Go
Testing CLI tools with GoTesting CLI tools with Go
Testing CLI tools with Go
 
III MCS python lab (1).pdf
III MCS python lab (1).pdfIII MCS python lab (1).pdf
III MCS python lab (1).pdf
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby Hackers
 

More from Eleanor McHugh

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdfEleanor McHugh
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityEleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveEleanor McHugh
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionEleanor McHugh
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]Eleanor McHugh
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxEleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored SpacesEleanor McHugh
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignEleanor McHugh
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by designEleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trustEleanor McHugh
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoEleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleEleanor McHugh
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionEleanor McHugh
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goEleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountabilityEleanor McHugh
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CEleanor McHugh
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CEleanor McHugh
 
Implementing Software Machines in C and Go
Implementing Software Machines in C and GoImplementing Software Machines in C and Go
Implementing Software Machines in C and GoEleanor McHugh
 

More from Eleanor McHugh (20)

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd edition
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By Design
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by design
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google Go
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
 
Hello Go
Hello GoHello Go
Hello Go
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd edition
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in go
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
 
Implementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & CImplementing Virtual Machines in Go & C
Implementing Virtual Machines in Go & C
 
Implementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & CImplementing Virtual Machines in Ruby & C
Implementing Virtual Machines in Ruby & C
 
Implementing Software Machines in C and Go
Implementing Software Machines in C and GoImplementing Software Machines in C and Go
Implementing Software Machines in C and Go
 

Recently uploaded

Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slidesvaideheekore1
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptxVinzoCenzo
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsJean Silva
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfRTS corp
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...OnePlan Solutions
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxRTS corp
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingOpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingShane Coughlan
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITmanoharjgpsolutions
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...OnePlan Solutions
 
Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldRoberto Pérez Alcolea
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfmaor17
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesKrzysztofKkol1
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorTier1 app
 

Recently uploaded (20)

Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slides
 
Osi security architecture in network.pptx
Osi security architecture in network.pptxOsi security architecture in network.pptx
Osi security architecture in network.pptx
 
Strategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero resultsStrategies for using alternative queries to mitigate zero results
Strategies for using alternative queries to mitigate zero results
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
 
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
Revolutionizing the Digital Transformation Office - Leveraging OnePlan’s AI a...
 
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptxThe Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
The Role of IoT and Sensor Technology in Cargo Cloud Solutions.pptx
 
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full RecordingOpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
OpenChain Education Work Group Monthly Meeting - 2024-04-10 - Full Recording
 
Best Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh ITBest Angular 17 Classroom & Online training - Naresh IT
Best Angular 17 Classroom & Online training - Naresh IT
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
Tech Tuesday Slides - Introduction to Project Management with OnePlan's Work ...
 
Keeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository worldKeeping your build tool updated in a multi repository world
Keeping your build tool updated in a multi repository world
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 
Zer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdfZer0con 2024 final share short version.pdf
Zer0con 2024 final share short version.pdf
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilitiesAmazon Bedrock in Action - presentation of the Bedrock's capabilities
Amazon Bedrock in Action - presentation of the Bedrock's capabilities
 
Effectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryErrorEffectively Troubleshoot 9 Types of OutOfMemoryError
Effectively Troubleshoot 9 Types of OutOfMemoryError
 

Generics, Reflection, and Efficient Collections

  • 1. GENERICS, REFLECTION, AND EFFICIENT COLLECTIONS ELEANOR MCHUGH
  • 2. PORTRAIT OF AN ARTIST... PORTRAIT OF AN ARTIST... ▸ physics ▸ cryptography ▸ embedded systems ▸ dynamic languages ▸ dns provisioning ▸ network scaling ▸ highly questionable taste in music g i t h u b : / / f e y e l e a n o r Eleanor McHugh s l i d e s h a r e : / / f e y e l e a n o r leanpub:/ /GoNotebook
  • 4. ARRAYS 001_array.go package main import "fmt" func main() { var a [3]int fmt.Println("len(a):", len(a)) fmt.Println("cap(a):", cap(a)) fmt.Printf("a: %v (%T)n", a, a) fmt.Printf("a[1]: %v (%T)n", a[1], a[1]) fmt.Printf("a[0:1]: %v (%T)n", a[0:1], a[0:1]) 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]: %vn", 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 002_array.go package main func main() { var a [3]int _ = append(a, 1) } go run 002_array.go # command-line-arguments ./002_array.go:6:13: first argument to append must be a slice; have a (variable of type [3]int)
  • 5. SLICES 003_slice.go package main import "fmt" func main() { var s []int fmt.Println("len(s):", len(s)) fmt.Println("cap(s):", cap(s)) fmt.Printf("s: %v (%T)n", s, s) fmt.Printf("s[0:1]: %v (%T)n", s[0:1], s[0:1]) } go run 003_slice.go len(s): 0 cap(s): 0 s: [] ([]int) panic: runtime error: slice bounds out of range [:1] with capacity 0 goroutine 1 [running]: main.main() /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/003_slice.go:11 +0x171 exit status 2 004_slice.go package main import "fmt" func main() { var s []int s = append(s, 0, 1, 2) fmt.Printf("s: %v (%T)n", s, s) fmt.Printf("s[:1]: %v (%T)n", s[:1], s[:1]) fmt.Printf("s[1:]: %v (%T)n", s[1:], s[1:]) s = append(s, s...) fmt.Printf("s: %v (%T)n", s, s) s = make([]int, 3, 6) fmt.Printf("s: %v (%T)n", s, s) s = []int{2, 4, 6} s[1] = s[2] for i, v := range s { fmt.Printf("s[%v]: %vn", i, v) } } go run 004_slice.go 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
  • 6. SLICES 005_string.go package main import "fmt" func main() { var s string fmt.Println("len(s):", len(s)) fmt.Printf("s: %v (%T)n", s, s) fmt.Printf("s[0:1]: %v (%T)n", s[0:1], s[0:1]) } go run 005_string.go len(s): 0 s: (string) panic: runtime error: slice bounds out of range [:1] with length 0 goroutine 1 [running]: main.main() /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/005_string.go:10 +0xf1 exit status 2 006_string.go package main import "fmt" func main() { s := "abc" fmt.Println("len(s):", len(s)) fmt.Printf("s: %v (%T)n", s, s) 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) } b := []byte(s) for i, v := range b { fmt.Printf("b[%v]: %v (%T)n", i, v, v) } } go run 006_string.go len(s): 3 s: abc (string) 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)
  • 7. MAPS 007_map.go package main import "fmt" func main() { var m map[int]int fmt.Println("len(m):", len(m)) fmt.Println("m[1]", m[1]) m[1] = 1 } go run 007_map.go len(m): 0 m[1] 0 panic: assignment to entry in nil map goroutine 1 [running]: main.main() /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/005_map.go:10 +0xf9 exit status 2 008_map.go package main import "fmt" func main() { var m map[int]int m = make(map[int]int) m[1] = 1 fmt.Println("m[1]:", m[1]) delete(m, 1) fmt.Println("m:", m) x, ok := m[1] fmt.Printf("x: %v, ok: %vn", x, ok) m = map[int]int{0: 2, 3: 6} fmt.Println("m:", m) for k, v := range m { fmt.Printf("m[%v]: %vn", k, v) } } 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
  • 8. CHANNELS 009_channel.go package main import "fmt" func main() { var c chan int c = make(chan int) 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) } } go run 009_channel.go # command-line-arguments ./007_channel.go:15:3: invalid operation: cannot send to receive-only channel c (variable of type <-chan int) ./007_channel.go:17:8: invalid operation: cannot close receive- only channel c (variable of type <-chan int) ./007_channel.go:21:17: cannot range over c (variable of type chan<- int) (receive from send-only channel)
  • 9. CHANNELS 010_channel.go package main import "fmt" func main() { var c chan int c = make(chan int) fmt.Println("cap(c):", cap(c)) go send(c, 0, 2, 4, 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: %vn", len(c), n) } } go run 010_channel.go cap(c): 0 sending: 0 sending: 2 len(c): 0, n: 0 len(c): 0, n: 2 sending: 4 sending: 6 len(c): 0, n: 4 len(c): 0, n: 6
  • 10. CHANNELS 011_channel.go package main import "fmt" func main() { var c chan int c = make(chan int, 16) fmt.Println("cap(c):", cap(c)) go send(c, 0, 2, 4, 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: %vn", len(c), n) } } go run 011_channel.go cap(c): 16 sending: 0 sending: 2 sending: 4 sending: 6 len(c): 3, n: 0 len(c): 2, n: 2 len(c): 1, n: 4 len(c): 0, n: 6
  • 11. 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
  • 12. CHANNELS 013_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) } n, open := <-c fmt.Printf("n: %v, open: %vn", n, open) } go run 013_channel.go sending: 0 sending: 2 sending: 4 sending: 6 n: 0 n: 2 n: 4 n: 6 n: 0, open: false
  • 13. CHANNELS 014_channel.go package main import "fmt" func main() { c := make(chan int, 16) done := make(chan bool) go func(v ...int) { for _, n := range v { fmt.Println("sending:", n) c <- n } close(c) done <- true }(0, 2, 4, 6) Receiver: for { select { case n, ok := <-c: if ok { fmt.Printf("len(c): %v, n: %vn", len(c), n) } case <-done: break Receiver } } } go run 014_channel.go sending: 0 sending: 2 sending: 4 sending: 6 len(c): 3, n: 0 go run 014_channel.go sending: 0 sending: 2 sending: 4 sending: 6 len(c): 3, n: 0 len(c): 2, n: 2 len(c): 1, n: 4
  • 14. CHANNELS 015_channel.go package main import "fmt" func main() { c := make(chan int) done := make(chan bool) go func(v ...int) { for _, n := range v { fmt.Println("sending:", n) c <- n } close(c) done <- true }(0, 2, 4, 6) Receiver: for { select { case n, ok := <-c: if ok { fmt.Printf("len(c): %v, n: %vn", len(c), n) } case <-done: break Receiver } } } go run 015_channel.go sending: 0 sending: 2 len(c): 0, n: 0 len(c): 0, n: 2 sending: 4 sending: 6 len(c): 0, n: 4 len(c): 0, n: 6 go run 015_channel.go sending: 0 sending: 2 len(c): 0, n: 0 len(c): 0, n: 2 sending: 4 sending: 6 len(c): 0, n: 4 len(c): 0, n: 6
  • 16. 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() = %vn", s, s.Sum()) } go run 014_udt.go [0 1 2 3 4].Sum() = 10
  • 17. USER-DEFINED COLLECTIONS 017_udt.go package main import "fmt" type Summable interface { Sum() any } type ISlice []int func (s ISlice) Sum() any { r := 0 for x := len(s) - 1; x > -1; x-- { 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 } func main() { var s Summable s = ISlice{0, 1, 2, 3, 4} fmt.Printf("%v.Sum() = %vn", s, s.Sum()) s = FSlice{0, 1, 2, 3, 4} fmt.Printf("%v.Sum() = %vn", s, s.Sum()) } go run 017_udt.go (main.ISlice)[0 1 2 3 4].Sum() = 10 (main.FSlice)[0 1 2 3 4].Sum() = 10
  • 18. USER-DEFINED COLLECTIONS 018_udt.go package main import "fmt" type Numeric interface { ~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() = %vn", i, i, i.Sum()) i = ISlice{0, 1, 2, 3, 4} fmt.Printf("(%T)%v.Sum() = %vn", i, i, i.Sum()) f := Summable[float32]{0, 1, 2, 3, 4} fmt.Printf("(%T)%v.Sum() = %vn", f, f, f.Sum()) f = FSlice{0, 1, 2, 3, 4} fmt.Printf("(%T)%v.Sum() = %vn", f, f, f.Sum()) } go run 018_udt.go (main.Summable[int])[0 1 2 3 4].Sum() = 10 (main.Summable[int])[0 1 2 3 4].Sum() = 10 (main.Summable[float32])[0 1 2 3 4].Sum() = 10 (main.Summable[float32])[0 1 2 3 4].Sum() = 10
  • 19. USER-DEFINED COLLECTIONS 019_generic_func.go package main import "fmt" 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) = %vn", i, i, Sum(i)) f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(i)) r := Sum(f).(float32) fmt.Println("r =", r) } go run 019_generic_func.go Sum([]int[0 1 2 3 4]) = 10 Sum([]float32[0 1 2 3 4]) = 10 r = 10
  • 20. USER-DEFINED COLLECTIONS 020_generic_func.go package main import ( "fmt" "reflect" ) type ISlice []int type FSlice []float32 func Sum(s any) (r any) { if s := reflect.ValueOf(s); s.Kind() == reflect.Slice { switch s.Type().Elem().Kind() { case reflect.Int: var x int for i := 0; i < s.Len(); i++ { x += int(s.Index(i).Int()) } r = x case reflect.Float32: var x float32 for i := 0; i < s.Len(); i++ { x += float32(s.Index(i).Float()) } r = x } } return } func main() { i := []int{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", i, i, Sum(i)) f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(f)) in := []interface{}{int(0), float32(1), int(2)} fmt.Printf("Sum(%T%v) = %vn", in, in, Sum(in)) is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", is, is, Sum(is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", fs, fs, Sum(fs)) } go run 020_generic_func.go Sum([]int[0 1 2 3 4]) = 10 Sum([]float32[0 1 2 3 4]) = 10 Sum([]interface {}[0 1 2]) = <nil> Sum(main.ISlice[0 1 2 3 4]) = 10 Sum(main.FSlice[0 1 2 3 4]) = 10
  • 21. USER-DEFINED COLLECTIONS 021_generic_func.go package main import ( "fmt" "reflect" ) type ISlice []int type FSlice []float32 func Sum(s any) (r any) { if s := R.ValueOf(s); s.Kind() == R.Slice { T := s.Type().Elem() V := R.New(T) E := V.Elem() switch T.Kind() { case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: for i := 0; i < s.Len(); i++ { E.SetInt(E.Int() + s.Index(i).Int()) } case R.Float32, R.Float64: for i := 0; i < s.Len(); i++ { E.SetFloat(E.Float() + s.Index(i).Float()) } } r = E.Interface() } return } func main() { i := []int{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", i, i, Sum(i)) f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", f, f, Sum(f)) in := []interface{}{int(0), float32(1), int(2)} fmt.Printf("Sum(%T%v) = %vn", in, in, Sum(in)) is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", is, is, Sum(is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%T%v) = %vn", fs, fs, Sum(fs)) } go run 021_generic_func.go Sum([]int[0 1 2 3 4]) = 10 Sum([]float32[0 1 2 3 4]) = 10 Sum([]interface {}[0 1 2]) = <nil> Sum(main.ISlice[0 1 2 3 4]) = 10 Sum(main.FSlice[0 1 2 3 4]) = 10
  • 22. USER-DEFINED COLLECTIONS 022_generic_func.go package main import "fmt" type Numeric interface { ~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) = %vn", i[0], i, Sum[int](i)) f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", f[0], f, Sum[float32](f)) is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum[int](is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum[float32](fs)) } go run 022_generic_func.go Sum[int]([0 1 2 3 4]) = 10 Sum[float32]([0 1 2 3 4]) = 10 Sum[int]([0 1 2 3 4]) = 10 Sum[float32]([0 1 2 3 4]) = 10
  • 23. USER-DEFINED COLLECTIONS 023_generic_func.go package main import "fmt" type Numeric interface { ~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) = %vn", i[0], i, Sum(i)) f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", f[0], f, Sum(f)) is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum(fs)) } go run 023_generic_func.go Sum[int]([0 1 2 3 4]) = 10 Sum[float32]([0 1 2 3 4]) = 10 Sum[int]([0 1 2 3 4]) = 10 Sum[float32]([0 1 2 3 4]) = 10
  • 24. USER-DEFINED COLLECTIONS 024_generic_func.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Indexable[T any] interface { ~[]T } func Sum[T Indexable[E], E Numeric](s T) (r E) { for _, x := range s { r += x } return } type ISlice Indexable[int] func main() { is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is)) } go run 024_generic_func.go # command-line-arguments ./023_generic_func.go:23:8: invalid composite literal type ISlice 025_generic_func.go package main import "fmt" type Numeric interface { ~int | ~float32 } func Sum[T Indexable[E], E Numeric](s T) (r E) { for _, x := range s { r += x } return } type Indexable[T any] interface { ~[]T } type ISlice []int type FSlice []float32 func main() { is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", is[0], is, Sum(is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum[%T](%v) = %vn", fs[0], fs, Sum(fs)) } go run 025_generic_func.go Sum[int]([0 1 2 3 4]) = 10 Sum[float32]([0 1 2 3 4]) = 10
  • 25. USER-DEFINED COLLECTIONS 026_generic_func.go package main import "fmt" 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%vn", 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%vn", fs, fs, 6, fs2, fs2) } go run 026_generic_func.go Append[main.ISlice]([0 1 2 3 4], 5) = main.ISlice[0 1 2 3 4 5] Append[[]float32]([0 1 2 3 4], 6) = []float32[0 1 2 3 4 6]
  • 27. 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) = %vn", is, Sum(is)) } go run 027_high_order_func.go Sum([0 1 2 3 4]) = 10
  • 28. HIGHER ORDER FUNCTIONS 028_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 } func main() { f := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", f, Sum(f)) } 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: []float32 does not implement Iterable (missing Range method) 029_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 FSlice []float32 func (s FSlice) Range(f func(int, int)) { for i, v := range s { f(i, v) } } func main() { fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", 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
  • 29. HIGHER ORDER FUNCTIONS 030_high_order_func.go package main import "fmt" type Iterable interface { Range(f func(int, any)) } func Sum(s Iterable) (r any) { s.Range(func(i int, v any) { r += v }) 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) } } func main() { is := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", is, Sum(is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", fs, Sum(fs)) } go 030_high_order_func.go # command-line-arguments ./030_high_order_func.go:11:3: invalid operation: operator + not defined on r (variable of type any)
  • 30. HIGHER ORDER FUNCTIONS 031_high_order_func.go package main import "fmt" 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) = %vn", is, Sum(is)) } go 031_high_order_func.go # command-line-arguments ./031_high_order_func.go:30:39: type ISlice of is does not match Iterable[T] (cannot infer T)
  • 31. HIGHER ORDER FUNCTIONS 032_high_order_func.go package main import "fmt" 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) } } type FSlice []float32 func (s FSlice) Range(f func(int, float32)) { for i, v := range s { f(i, v) } } func main() { is := ISlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", is, Sum[int](is)) fs := FSlice{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %vn", fs, Sum[float32](fs)) } go 032_high_order_func.go Sum([0 1 2 3 4]) = 10 Sum([0 1 2 3 4]) = 10
  • 32. HIGHER ORDER FUNCTIONS 033_high_order_func.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Iterable[T Numeric] interface { Range(f func(int, T)) } func Sum[T Numeric](s any) (r any) { switch s := s.(type) { case Iterable[T]: fmt.Printf("case Iterable[%T]n", s) var x T s.Range(func(i int, v T) { x += v }) r = x case []T: fmt.Printf("case %Tn", s) var x T for _, v := range s { x += v } r = x } 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[%T]n", is, Sum[int](is), is[0]) fs := []float32{0, 1, 2, 3, 4} fmt.Printf("Sum(%v) = %v[%T]n", fs, Sum[float32](fs), fs[0]) } go 033_high_order_func.go case Iterable[main.ISlice] Sum([0 1 2 3 4]) = 10 [int] case []float32 Sum([0 1 2 3 4]) = 10 [float32]
  • 34. REDUCING COLLECTIONS 034_reduce.go package main import "fmt" 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) } go 034_reduce.go Reduce([0 1 2 3 4], f()) = 10 [int] Reduce([0 1 2 3 4], f()) = 10 [float32]
  • 35. REDUCING COLLECTIONS 035_reduce.go package main import "fmt" func Reduce(s any, f func(any, any) any) (r any) { switch s := s.(type) { case []int: var x int for _, v := range s { x = f(x, v).(int) } r = x case []float32: var x float32 for _, v := range s { x = f(x, v).(float32) } r = x } return } func main() { is := []int{0, 1, 2, 3, 4} ir := Reduce(is, func(x any, v any) any { return x.(int) + v.(int) }) fmt.Printf("Reduce(%v, f()) = %v [%T]n", is, ir, ir) fs := []float32{0, 1, 2, 3, 4} fr := Reduce(fs, func(x any, v any) any { return x.(float32) + v.(float32) }) fmt.Printf("Reduce(%v, f()) = %v [%T]n", fs, fr, fr) } go 035_reduce.go Reduce([0 1 2 3 4], f()) = 10 [int] Reduce([0 1 2 3 4], f()) = 10 [float32]
  • 36. REDUCING COLLECTIONS 036_reduce.go package main import ( "fmt" R "reflect" ) func Reduce(s any, f func(any, any) any) (r any) { if s := R.ValueOf(s); s.Kind() == R.Slice { T := s.Type().Elem() V := R.New(T) E := V.Elem() switch T.Kind() { case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: for i := 0; i < s.Len(); i++ { v := R.ValueOf(f( E.Interface(), 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 } func main() { is := []int{0, 1, 2, 3, 4} ir := Reduce(is, func(x any, v any) any { return x.(int) + v.(int) }) fmt.Printf("Reduce(%v, f()) = %v [%T]n", is, ir, ir) fs := []float32{0, 1, 2, 3, 4} fr := Reduce(fs, func(x any, v any) any { return x.(float32) + v.(float32) }) fmt.Printf("Reduce(%v, f()) = %v [%T]n", fs, fr, fr) } go 036_reduce.go Reduce([0 1 2 3 4], f()) = 10 [int] Reduce([0 1 2 3 4], f()) = 10 [float32]
  • 37. REDUCING COLLECTIONS 037_reduce.go package main import "fmt" 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) } go 037_reduce.go (main.Reducible[int])[0 1 2 3 4].Reduce(f()) = 10 [int] (main.Reducible[float32])[0 1 2 3 4].Reduce(f()) = 10 [float32]
  • 38. REDUCING COLLECTIONS 038_reduce.go package main import "fmt" 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) } go 038_reduce.go map[0:0 1:1 2:2 3:3 4:4].Reduce(f()) = 10 [int] map[0:0 1:1 2:2 3:3 4:4].Reduce(f()) = 10 [float32]
  • 39. REDUCING COLLECTIONS 039_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Reducible[T Numeric] chan T func (c Reducible[T]) Reduce(f func(T, T) T) (r T) { for x := range c { r = f(r, x) } return } func (c Reducible[T]) Pump(v ...T) { for _, v := range v { c <- v } close(c) } type IChan = Reducible[int] type FChan = Reducible[float32] func main() { ic := make(IChan) go ic.Pump(0, 1, 2, 3, 4) ir := ic.Reduce(func(x, v int) int { return x + v }) fmt.Printf("(chan ic).Reduce(f()) = %v [%T]n", ir, ir) fc := make(FChan) go fc.Pump(0, 1, 2, 3, 4) fr := fc.Reduce(func(x, v float32) float32 { return x + v }) fmt.Printf("(chan fc).Reduce(f()) = %v [%T]n", fr, fr) } go 039_reduce.go (chan ic).Reduce(f()) = 10 [int] (chan fc).Reduce(f()) = 10 [float32]
  • 40. REDUCING COLLECTIONS 040_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { switch c := c.(type) { case []T: for _, x := range c { r = f(r, x) } case map[int]T: for _, x := range c { r = f(r, x) } case chan T: for x := range c { r = f(r, x) } } return } func Pump[T Numeric](ic chan<- T, v ...T) { for _, v := range v { ic <- v } close(ic) } 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) im := map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4} ir = Reduce(im, func(x, v int) int { return x + v }) fmt.Printf("Reduce(%v, f()) = %v [%T]n", im, ir, ir) ic := make(chan int) go Pump(ic, 0, 1, 2, 3, 4) ir = Reduce(ic, func(x, v int) int { return x + v }) fmt.Printf("(chan ic).Reduce(f()) = %v [%T]n", ir, ir) } go 040_reduce.go Reduce([0 1 2 3 4], f()) = 10 [int] Reduce(map[0:0 1:1 2:2 3:3 4:4], f()) = 10 [int] (chan ic).Reduce(f()) = 10 [int]
  • 41. REDUCING COLLECTIONS 041_reduce.go package main import ( "fmt" R "reflect" ) type Numeric interface { ~int | ~float32 } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { switch c := c.(type) { case chan T: for x := range c { r = f(r, x) } case string: for _, x := range c { r = f(r, T(x)) } default: switch c := R.ValueOf(c); c.Kind() { case R.Map: for i := c.MapRange(); i.Next(); { r = f(r, i.Value().Interface().(T)) } } } return } func Pump[T Numeric](ic chan<- T, v ...T) { for _, v := range v { ic <- v } close(ic) } func DoReduce(c any) { ir := Reduce(c, func(x, v int) int { return x + v }) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, ir, ir) } func main() { ic := make(chan int) go Pump(ic, 0, 1, 2, 3, 4) DoReduce(ic) DoReduce("01234") DoReduce(map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) DoReduce(map[string]int{ "0": 0, "1": 1, "2": 2, "3": 3, "4": 4}) } go 041_reduce.go [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]
  • 42. REDUCING COLLECTIONS 042_reduce.go package main import ( "fmt" R "reflect" ) type Numeric interface { ~int | ~float32 } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { switch c := c.(type) { case [1]T: for x := range c { r = f(r, T(x)) } case [2]T: for _, x := range c { 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 } func DoReduce(c any) { ir := Reduce(c, func(x, v int) int { return x + v }) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, ir, ir) } func main() { DoReduce([0]int{}) DoReduce([1]int{0}) DoReduce([2]int{0, 1}) DoReduce([5]int{0, 1, 2, 3, 4}) } go 042_reduce.go [[0]int]Reduce([], f()) = 0[int] [[1]int]Reduce([0], f()) = 0[int] [[2]int]Reduce([0 1], f()) = 1[int] [[5]int]Reduce([0 1 2 3 4], f()) = 10[int]
  • 43. REDUCING COLLECTIONS 043_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Reducible[T Numeric] interface { Reduce(func(T, T) T) T } type ISlice []int func (s ISlice) Reduce(f func(x, v int) int) (r int) { for _, v := range s { r = f(r, v) } return } type FArray [3]float32 func (a FArray) Reduce(f func(x, v float32) float32) (r float32) { for _, v := range a { r = f(r, v) } return } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { switch c := c.(type) { case Reducible[T]: r = c.Reduce(f) } return } func DoReduce[T Numeric](c any, f func(T, T) T) { r := Reduce(c, f) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r) } func main() { DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int { return x + v }) DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 { return x + v }) } go 043_reduce.go [main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int] [main.FArray]Reduce([0 1 2], f()) = 3[float32]
  • 44. REDUCING COLLECTIONS 044_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Iterable[T Numeric] interface { Range(f func(int, T)) } type Reducible[T Numeric] interface { Reduce(func(T, T) T) T } 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++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } } return } func DoReduce[T Numeric](c any, f func(T, T) T) { r := Reduce(c, f) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r) } func Adder[T Numeric]() func(T, T) T { return func(x, v T) T { return x + v } } func main() { DoReduce(func(x int) (int, bool) { return x, (x < 5) }, Adder[int]()) DoReduce(func(x int) (float32, bool) { return float32(x), (x < 5) }, Adder[float32]()) } go 044_reduce.go [func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int] [func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
  • 45. REDUCING COLLECTIONS 045_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } type Iterable[T Numeric] interface { Range(f func(int, T)) } type Reducible[T Numeric] interface { Reduce(func(T, T) T) T } 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++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } } return } func DoReduce[T Numeric](c any, f func(T, T) T) { r := Reduce(c, f) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r) } 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 } } func main() { i := func(x int) (int, bool) { return x, (x < 5) } DoReduce(i, Adder(i)) f := func(x int) (float32, bool) { return float32(x), (x < 5) } DoReduce(f, Adder(f)) } go 045_reduce.go [func(int) (int, bool)]Reduce(0x108e700, f()) = 10[int] [func(int) (float32, bool)]Reduce(0x108e720, f()) = 10[float32]
  • 46. REDUCING COLLECTIONS 046_reduce.go package main import "fmt" type Numeric interface { ~int | ~float32 } 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++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } case NFunc[T]: r = Reduce((func(int) (T, bool))(c), f) } return } type NFunc[T Numeric] func(int) (T, bool) func DoReduce[T Numeric](c any, f func(T, T) T) { r := Reduce(c, f) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r) } func Adder[T Numeric]() func(T, T) T { return func(x, v T) T { return x + v } } func main() { DoReduce(func(x int) (int, bool) { return x, (x < 5) }, Adder[int]()) DoReduce(func(x int) (float32, bool) { return float32(x), (x < 5) }, Adder[float32]()) DoReduce(NFunc[int](func(x int) (int, bool) { return x, (x < 5) }), Adder[int]()) } go 046_reduce.go [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]
  • 47. REDUCING COLLECTIONS 047_reduce.go package main import ( "fmt" R "reflect" ) type Numeric interface { ~int | ~float32 } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { if c := R.ValueOf(c); c.Kind() == R.Func { for i := 0; ; i++ { p := []R.Value{R.ValueOf(i)} if p = c.Call(p); p[1].Interface() == true { r = f(r, p[0].Interface().(T)) } else { break } } } return } type NFunc[T Numeric] func(int) (T, bool) func DoReduce[T Numeric](c any, f func(T, T) T) { r := Reduce(c, f) fmt.Printf("[%T]Reduce(%v, f()) = %v[%T]n", c, c, r, r) } func Adder[T Numeric]() func(T, T) T { return func(x, v T) T { return x + v } } func main() { DoReduce(func(x int) (int, bool) { return x, (x < 5) }, Adder[int]()) DoReduce(func(x int) (float32, bool) { return float32(x), (x < 5) }, Adder[float32]()) DoReduce(NFunc[int](func(x int) (int, bool) { return x, (x < 5) }), Adder[int]()) } go 047_reduce.go [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]
  • 48. REDUCING COLLECTIONS 048_reduce.go package main import ( "fmt" R "reflect" ) type Numeric interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64 } type Iterable[T Numeric] interface { Range(f func(int, T)) } type Reducible[T Numeric] interface { Reduce(func(T, T) T) T } func Reduce[T Numeric](c any, f func(T, T) T) (r T) { switch c := c.(type) { case Iterable[T]: c.Range(func(i int, v T) { r = f(r, v) }) case Reducible[T]: r = c.Reduce(f) case string: for _, x := range c { r = f(r, T(x)) } case T: r = f(r, c) case []T: for _, x := range c { r = f(r, x) } case map[int]T: for _, x := range c { r = f(r, x) } case func(int) (T, bool): for i := 0; ; i++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } case chan T: for x := range c { r = f(r, x) } default: switch c := R.ValueOf(c); c.Kind() { case R.Map: for i := c.MapRange(); i.Next(); { r = f(r, i.Value().Interface().(T)) } case R.Array: for i := 0; i < c.Len(); i++ { r = f(r, c.Index(i).Interface().(T)) } case R.Func: for i := 0; ; i++ { p := []R.Value{R.ValueOf(i)} if p = c.Call(p); p[1].Interface() == true { r = f(r, p[0].Interface().(T)) } else { break } } } } return }
  • 49. REDUCING COLLECTIONS 049_reduce.go package main import R "reflect" func Reduce[T any](c any, f func(T, T) T) (r T) { switch c := c.(type) { case interface{ Range(f func(int, T)) }: c.Range(func(i int, v T) { r = f(r, v) }) case interface{ Reduce(func(T, T) T) T }: r = c.Reduce(f) case string: for _, x := range c { r = f(r, x) } case T: r = f(r, c) case []T: for _, x := range c { r = f(r, x) } case map[int]T: for _, x := range c { r = f(r, x) } case func(int) (T, bool): for i := 0; ; i++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } case chan T: for x := range c { r = f(r, x) } default: switch c := R.ValueOf(c); c.Kind() { case R.Map: for i := c.MapRange(); i.Next(); { r = f(r, i.Value().Interface().(T)) } case R.Array: for i := 0; i < c.Len(); i++ { r = f(r, c.Index(i).Interface().(T)) } case R.Func: for i := 0; ; i++ { p := []R.Value{R.ValueOf(i)} if p = c.Call(p); p[1].Interface() == true { r = f(r, p[0].Interface().(T)) } else { break } } } } return } func main() {} go 049_reduce.go # command-line-arguments ./049_reduce.go:15:13: cannot use x (variable of type rune) as type T in argument to f
  • 50. REDUCING COLLECTIONS 050_reduce.go package main import "fmt" func Reduce[T any](c any, f func(T, T) T) (r T) { switch c := c.(type) { case interface{ Range(f func(int, T)) }: c.Range(func(i int, v T) { r = f(r, v) }) case interface{ Reduce(func(T, T) T) T }: r = c.Reduce(f) } return } 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) } type ISlice []int func (s ISlice) Range(f func(int, int)) { for i, v := range s { f(i, v) } } type FArray [3]float32 func (a FArray) Reduce(f func(x, v float32) float32) (r float32) { for _, v := range a { r = f(r, v) } return } func main() { DoReduce(ISlice{0, 1, 2, 3, 4}, func(x, v int) int { return x + v }) DoReduce(FArray{0, 1, 2}, func(x, v float32) float32 { return x + v }) } go 050_reduce.go [main.ISlice]Reduce([0 1 2 3 4], f()) = 10[int] [main.FArray]Reduce([0 1 2], f()) = 3[float32]
  • 51. REDUCING COLLECTIONS 051_reduce.go package main import "fmt" func Reduce[T any](c any, f func(T, T) T) (r T) { switch c := c.(type) { case string: for _, x := range c { r = f(r, any(x).(T)) } } return } 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) } func main() { DoReduce[rune]("01234", func(r, x rune) rune { return r + x - 48 }) } go 051_reduce.go [string]Reduce(01234, f()) = 10[int32] 052_reduce.go package main import ( "fmt" R "reflect" ) func Reduce[T any](c any, f func(T, T) T) (r T) { switch c := R.ValueOf(c); c.Kind() { case R.String: for _, x := range c.Interface().(string) { r = f(r, any(x).(T)) } } return } 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) } func main() { DoReduce("01234", func(x, v rune) rune { return x + v - 48 }) } go 052_reduce.go [string]Reduce(01234, f()) = 10[int32]
  • 52. REDUCING COLLECTIONS 053_reduce.go package main import R "reflect" func Reduce[T any](c any, f func(T, T) T) (r T) { switch c := c.(type) { case interface{ Range(f func(int, T)) }: c.Range(func(i int, v T) { r = f(r, v) }) case interface{ Reduce(func(T, T) T) T }: r = c.Reduce(f) case string: for _, x := range c { r = f(r, any(x).(T)) } case T: r = f(r, c) case []T: for _, x := range c { r = f(r, x) } case map[int]T: for _, x := range c { r = f(r, x) } case func(int) (T, bool): for i := 0; ; i++ { if v, ok := c(i); ok { r = f(r, v) } else { break } } case chan T: for x := range c { r = f(r, x) } default: switch c := R.ValueOf(c); c.Kind() { case R.Map: for i := c.MapRange(); i.Next(); { r = f(r, i.Value().Interface().(T)) } case R.Array: for i := 0; i < c.Len(); i++ { r = f(r, c.Index(i).Interface().(T)) } case R.Func: for i := 0; ; i++ { p := []R.Value{R.ValueOf(i)} if p = c.Call(p); p[1].Interface() == true { r = f(r, p[0].Interface().(T)) } else { break } } } } return } func main() {}
  • 54. 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()): %vn", 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]
  • 55. MAPPING COLLECTIONS 055_high_order_func.go package main import "fmt" type Iterable[T any] interface { Range(func(int, T)) } func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case Iterable[T]: s.Range(func(i int, v T) { r = append(r, f(v)) }) case []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()): %vn", s, r) } type ISlice []int func (s ISlice) Range(f func(i, v int)) { for i, v := range s { f(i, v) } } func main() { DoMap(ISlice{0, 1, 2, 3, 4}) DoMap([]int{0, 1, 2, 3, 4}) DoMap([]float32{0, 1, 2, 3, 4}) } 055_high_order_func.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] Map([0 1 2 3 4], func()): [0 2 4 6 8]
  • 56. MAPPING COLLECTIONS 056_map.go package main import "fmt" func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case interface{ Range(func(int, T)) }: s.Range(func(i int, v T) { r = append(r, f(v)) }) } return } func DoMap[T ~int | ~float32](s any) { r := Map(s, func(v T) T { return v * 2 }) fmt.Printf("Map(%v, func()): %vn", s, r) } 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 } } } func Limit[T any](i, j int, f NFunc[T]) NFunc[T] { return func(x int) (r T, ok bool) { if i <= x && x <= j { r, ok = f(x) } return } } func main() { DoMap[int](Limit(0, 4, func(x int) (int, bool) { return x, true })) DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) } 056_map.go Map(0x108afc0, func()): [0 2 4 6 8] Map(0x108ae20, func()): []
  • 57. MAPPING COLLECTIONS 057_map.go package main import "fmt" func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case func(int) (T, bool): for i := 0; ; i++ { if v, ok := s(i); ok { r = append(r, f(v)) } else { break } } } return } 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 } } } func DoMap[T ~int | ~float32](s any) { r := Map(s, func(v T) T { return v * 2 }) fmt.Printf("Map(%v, func()): %vn", s, r) } func Limit[T any](i, j int, f NFunc[T]) NFunc[T] { return func(x int) (r T, ok bool) { if i <= x && x <= j { r, ok = f(x) } return } } func main() { DoMap[int](Limit(0, 4, func(x int) (int, bool) { return x, true })) DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) } 057_map.go Map(0x108aee0, func()): [] Map(0x108ae20, func()): [0 2 4 6 8]
  • 58. MAPPING COLLECTIONS 058_map.go package main import "fmt" func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case NFunc[T]: for i := 0; ; i++ { if v, ok := s(i); ok { r = append(r, f(v)) } else { break } } } return } 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 } } } func DoMap[T ~int | ~float32](s any) { r := Map(s, func(v T) T { return v * 2 }) fmt.Printf("Map(%v, func()): %vn", s, r) } func Limit[T any](i, j int, f NFunc[T]) NFunc[T] { return func(x int) (r T, ok bool) { if i <= x && x <= j { r, ok = f(x) } return } } func main() { DoMap[int](Limit(0, 4, func(x int) (int, bool) { return x, true })) DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) } 058_map.go Map(0x108aee0, func()): [0 2 4 6 8] Map(0x108ae20, func()): []
  • 59. MAPPING COLLECTIONS 059_map.go package main import ( "fmt" R "reflect" ) func Map[T any](s any, f func(T) T) (r []T) { if s := R.ValueOf(s); s.Kind() == R.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()): %vn", s, r) } func main() { DoMap[float32](func(x int) (float64, bool) { return float64(x), (x < 5) }) } 059_map.go panic: interface conversion: interface {} is float64, not float32 goroutine 1 [running]: main.Map[...]({0x1099520, 0x10b0678?}, 0xc000107f10?) /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/050_high_order_func.go:21 +0x325 main.DoMap[...]({0x1099520, 0x10b0678}) /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/050_high_order_func.go:31 +0x52 main.main() /Users/eleanormchugh/Documents/go/src/github.com/feyeleanor/ GoGenericsTalk/050_high_order_func.go:65 +0x79 exit status 2
  • 60. MAPPING COLLECTIONS 060_map.go package main import ( "fmt" R "reflect" ) func Map[T any](s any, f func(T) T) (r []T) { if s := R.ValueOf(s); s.Kind() == R.Func { defer func() { recover() }() 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()): %vn", s, r) } func main() { DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) DoMap[float32](func(x int) (float64, bool) { return float64(x), (x < 5) }) } 060_map.go Map(0x108f560, func()): [0 2 4 6 8] Map(0x108f580, func()): []
  • 61. MAPPING COLLECTIONS 061_map.go package main import ( "fmt" R "reflect" ) type Numeric interface { ~int | ~float32 } func Map[T Numeric](s any, f func(T) T) (r []T) { if s := R.ValueOf(s); s.Kind() == R.Func { 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 { switch V.Kind() { case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: r = append(r, f(T(p[0].Int()))) case R.Float32, R.Float64: r = append(r, f(T(p[0].Float()))) } } else { break } } } return } func DoMap[T Numeric](s any) { r := Map(s, func(v T) T { return v * 2 }) fmt.Printf("Map(%v, func()): %vn", s, r) } func main() { DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) DoMap[float32](func(x int) (float64, bool) { return float64(x), (x < 5) }) } 061_map.go Map(0x108f560, func()): [0 2 4 6 8] Map(0x108f580, func()): [0 2 4 6 8]
  • 62. MAPPING COLLECTIONS 062_map.go package main import ( "fmt" R "reflect" ) func Map[T any](s any, f func(T) T) (r []T) { if s := R.ValueOf(s); s.Kind() == R.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 | ~float64](s any) { r := Map(s, func(v T) T { return v * 2 }) fmt.Printf("Map(%v, func()): %vn", s, r) } func main() { DoMap[int](func(x int) (int, bool) { return x, (x < 5) }) DoMap[float32](func(x int) (float32, bool) { return float32(x), (x < 5) }) DoMap[float64](func(x int) (float64, bool) { return float64(x), (x < 5) }) } 062_map.go 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] Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
  • 63. MAPPING COLLECTIONS 062_map.go package main import ( "fmt" R "reflect" ) func Map[T any](s any, f func(T) T) (r []T) { switch s := R.ValueOf(s); s.Kind() { case R.Map: switch s.Type().Key().Kind() { case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: r = make([]T, s.Len()) for i := s.MapRange(); i.Next(); { x := int(i.Key().Int()) if x >= len(r) { n := make([]T, x+1) copy(n, r) r = n } r[x] = f(i.Value().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()): %vn", s, r) } func main() { DoMap[int](map[int]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) DoMap[int](map[int8]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) DoMap[int](map[int32]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) } 062_map.go 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] Map(map[0:0 1:1 2:2 3:3 4:4], func()): [0 2 4 6 8]
  • 64. MAPPING COLLECTIONS 063_map.go package main import ( "fmt" 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()): %vn", 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}) } 063_map.go Map([0 1 2], func()): [0 2 4] Map([0 1 2], func()): [0 2 4] Map([0 1 2], func()): []
  • 65. MAPPING COLLECTIONS 064_map.go package main import "fmt" func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case string: for _, x := range s { r = append(r, f(any(x).(T))) } case chan T: 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()): %vn", s, r) } func Pump[T any](ic chan<- T, v ...T) { for _, v := range v { ic <- v } close(ic) } func main() { ic := make(chan int) go Pump(ic, 0, 1, 2, 3, 4) DoMap[int](ic) DoMap[rune]("01234") } 064_map.go Map(0xc00011c000, func()): [0 2 4 6 8] Map(01234, func()): [96 98 100 102 104]
  • 66. MAPPING COLLECTIONS 065_map.go package main import R "reflect" func Map[T any](s any, f func(T) T) (r []T) { switch s := s.(type) { case interface{ Range(f func(int, T)) }: s.Range(func(i int, v T) { r = append(r, f(v)) }) case string: for _, x := range s { r = append(r, f(any(x).(T))) } case []T: for _, v := range s { r = append(r, f(v)) } case map[int]T: r = make([]T, len(s)) for i, v := range s { if i >= len(r) { n := make([]T, i-1) copy(n, r) r = n } r[i] = f(v) } case chan T: for x := range s { r = append(r, f(x)) } default: switch s := R.ValueOf(s); s.Kind() { case R.Array: for i := 0; i < s.Len(); i++ { r = append(r, f(s.Index(i).Interface().(T))) } case R.Map: switch s.Type().Key().Kind() { case R.Int, R.Int8, R.Int16, R.Int32, R.Int64: r = make([]T, s.Len()) for i := s.MapRange(); i.Next(); { x := int(i.Key().Int()) if x >= len(r) { n := make([]T, x+1) copy(n, r) r = n } r[x] = f(i.Value().Interface().(T)) } } case R.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 }
  • 67. RESOURCES ‣ github.com/feyeleanor/GoGenericsTalk ‣ slideshare.net/feyeleanor ‣ leanpub.com/GoNotebook ‣ gobyexample.com/generics ‣ go.dev/blog/intro-generics ‣ go.dev/doc/tutorial/generics ‣ bitfieldconsulting.com/golang/generics