Golang Generics

goos: darwin
goarch: amd64
pkg: MyGoNote/Golang/Generics
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
BenchmarkIntSum-8                       62395846                18.34 ns/op            0 B/op          0 allocs/op
BenchmarkIntGenericsSum-8               50608840                22.36 ns/op            0 B/op          0 allocs/op
BenchmarkFloat64Sum-8                   63748537                20.04 ns/op            0 B/op          0 allocs/op
BenchmarkFloat64GenericsSum-8           24300607                41.49 ns/op            0 B/op          0 allocs/op
BenchmarkIntMin-8                       32240342                35.07 ns/op            0 B/op          0 allocs/op
BenchmarkIntGenericsMin-8               31695579                35.66 ns/op            0 B/op          0 allocs/op
BenchmarkFloat64Min-8                   29995334                40.44 ns/op            0 B/op          0 allocs/op
BenchmarkFloat64GenericsMin-8           31469748                36.16 ns/op            0 B/op          0 allocs/op
PASS
ok      MyGoNote/Golang/Generics        9.501s
  • Float64 addition is slower than int

Example

main.go
package main

type ResponseInt struct {
    Sum int `json:"sum"`
    Min int `json:"min"`
}

func Min(vars ...int) int {
    min := vars[0]

    for _, i := range vars {
        if min > i {
            min = i
        }
    }
    return min
}

func Sum(vars ...int) int {
    var sum int
    for _, v := range vars {
        sum += v
    }
    return sum
}

func MinFloat64(vars ...float64) float64 {
    min := vars[0]

    for _, i := range vars {
        if min > i {
            min = i
        }
    }
    return min
}

func SumFloat64(vars ...float64) float64 {
    var sum float64
    for _, v := range vars {
        sum += v
    }
    return sum
}

// https://stackoverflow.com/questions/71073365/interface-contains-type-constraints-cannot-use-interface-in-conversion
type ResponseGenerics[T Number] struct {
    Sum T `json:"sum"`
    Min T `json:"min"`
}

type Number interface {
    int | int64 | float64
}

func MinGenerics[T Number](vars ...T) T {
    min := vars[0]

    for _, i := range vars {
        if min > i {
            min = i
        }
    }
    return min
}

func SumGenerics[T Number](vars ...T) T {
    var sum T
    for _, v := range vars {
        sum += v
    }
    return sum
}
main_test.go
package main

import (
    "fmt"
    "testing"
)

func TestMin(t *testing.T) {
    var tests = []struct {
        arg1 []int
        want int
    }{
        {
            []int{9, 5, 4, 3, 5, 7},
            3,
        },
    }
    for _, tt := range tests {
        if got := Min(tt.arg1...); got != tt.want {
            t.Errorf("got = %v, want = %v", got, tt.want)
        }
    }
}

func TestMinFloat64(t *testing.T) {
    var tests = []struct {
        arg1 []float64
        want float64
    }{
        {
            []float64{9.0, 5.1, 4.5, 3.1, 5.1, 7.8},
            3.1,
        },
    }
    for _, tt := range tests {
        if got := MinFloat64(tt.arg1...); got != tt.want {
            t.Errorf("got = %v, want = %v", got, tt.want)
        }
    }
}

func TestInt(t *testing.T) {
    var tests = []struct {
        arg1 []int
        want ResponseInt
    }{
        {
            []int{9, 5, 4, 3, 5, 7},
            ResponseInt{Min: 3, Sum: 33},
        },
    }
    for _, tt := range tests {
        min := Min(tt.arg1...)
        sum := Sum(tt.arg1...)
        got := ResponseInt{
            Min: min,
            Sum: sum,
        }
        if got != tt.want {
            t.Errorf("got = %v, want = %v", got, tt.want)
        } else {
            fmt.Printf("got : %+v\n", got)
        }
    }
}

func TestIntGenerics(t *testing.T) {
    var tests = []struct {
        arg1 []int
        want ResponseGenerics[int]
    }{
        {
            []int{9, 5, 4, 3, 5, 7},
            ResponseGenerics[int]{Min: 3, Sum: 33},
        },
    }
    for _, tt := range tests {
        min := MinGenerics(tt.arg1...)
        sum := Sum(tt.arg1...)
        got := ResponseGenerics[int]{
            Min: min,
            Sum: sum,
        }
        if got != tt.want {
            t.Errorf("got = %v, want = %v", got, tt.want)
        } else {
            fmt.Printf("got : %+v\n", got)
        }
    }
}

func TestFloat64Generics(t *testing.T) {
    var tests = []struct {
        arg1 []float64
        want ResponseGenerics[float64]
    }{
        {
            []float64{3.3, 3.1, 5},
            ResponseGenerics[float64]{Min: 3.1, Sum: 11.4},
        },
    }
    for _, tt := range tests {
        min := MinGenerics(tt.arg1...)
        sum := SumGenerics(tt.arg1...)
        got := ResponseGenerics[float64]{
            Min: min,
            Sum: sum,
        }
        if got != tt.want {
            t.Errorf("got = %v, want = %v", got, tt.want)
        } else {
            fmt.Printf("got : %+v\n", got)
        }
    }
}

func BenchmarkIntSum(b *testing.B) {
    b.ResetTimer()
    tests := []int{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        // Min(tests...)
        Sum(tests...)
    }
}

func BenchmarkIntGenericsSum(b *testing.B) {
    b.ResetTimer()
    tests := []int{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        // MinGenerics(tests...)
        SumGenerics(tests...)
    }
}

func BenchmarkFloat64Sum(b *testing.B) {
    b.ResetTimer()
    tests := []float64{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        // Min(tests...)
        SumFloat64(tests...)
    }
}

func BenchmarkFloat64GenericsSum(b *testing.B) {
    b.ResetTimer()
    tests := []float64{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        // MinGenerics(tests...)
        SumGenerics(tests...)
    }
}

func BenchmarkIntMin(b *testing.B) {
    b.ResetTimer()
    tests := []int{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        Min(tests...)
        // Sum(tests...)
    }
}

func BenchmarkIntGenericsMin(b *testing.B) {
    b.ResetTimer()
    tests := []int{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        MinGenerics(tests...)
        // SumGenerics(tests...)
    }
}

func BenchmarkFloat64Min(b *testing.B) {
    b.ResetTimer()
    tests := []float64{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        MinFloat64(tests...)
        // Sum(tests...)
    }
}

func BenchmarkFloat64GenericsMin(b *testing.B) {
    b.ResetTimer()
    tests := []float64{1, 2, 3, 5, 7, 5, 45, 15, 6, 8, 48, 21, 6489, 46, 1564689, 8, 21, 21, 548, 532, 45, 21, 8, 158, 76, 39, 412842, 6, 897465, 897, 46, 87, 45, 4, 716, 9, 716, 49, 235668, 4789, 458, 45, 98, 456489, 489156, 3561, 564894, 564156, 47984, 561, 3, 23156, 1564, 564, 657, 54, 3165, 4966, 48974, 4}
    for i := 0; i < b.N; i++ {
        MinGenerics(tests...)
        // SumGenerics(tests...)
    }
}

~

type Number interface {
    int | int64 | float64
}

可以改成

type Number interface {
    ~int | ~int64 | ~float64
}

~ 這這裡可以理解為泛類型, 即所有以 int, int64, float64 為基礎類型的類型都能夠被約束 譬如 宣告(declaration) 一個以 int64 為基礎類型, 命名為 testInt

type testInt int64

Reference

© Kimi Tsai all right reserved.            Updated : 2023-07-12 09:04:53

results matching ""

    No results matching ""

    results matching ""

      No results matching ""