This is a talk about how we structure and collate information so as to effectively process it, the language tools Go provides to help us do this, and the sometimes frustrating tradeoffs we must make when marry the real world with the digital.
We'll start by looking at basic collection types in Go: array, slice, map, and channel. These will then be used as the basis for our own user defined types with methods for processing the collected items.
These methods will then be expanded to take functions as parameters (the higher order functional style popularised by languages such as Ruby) and by using Go's Reflection package we will generalise them for a variety of tasks and uses cases.
Reflection adds an interpreted element to our programs with a resulting performance cost. Careful design can often minimise this cost and it may well amortise to zero on a sufficiently large collection however there is always greater code complexity to manage. When the data to be contained in a user defined collection is homogenous we can reduce much of this complexity by using Generics and our next set of examples will demonstrate this.
At the end of this talk you should have some useful ideas for designing your own collection types in Go as well as a reasonable base from which to explore Reflection, Generics, and the Higher-Order Functional style of programming.
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
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() {}
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
}