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