Go has released version 1.18 not long ago. One of the most important features of 1.18 is generics. Before this release, the most criticized thing was that Go could not support multiple types as parameters, which caused a lot of repetitive code when writing packages. This article will teach you the basics of what generics are and how to use them.

Using generic

Let’s write a func to support a parameter, which can be of type int64 or float64, executed online

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import "fmt"

func show[num int64 | float64](s num) {
  fmt.Println(s)
}

func main() {
  fmt.Println("go 1.18 Generics Example")

  var sum1 int64 = 28
  var sum2 float64 = 29.5

  show(sum1)
  show(sum2)
}

As you can see [num int64 | float64] defines a new type, which can be int64 or float64, and then put this type after it. However, if there are many supported types, you can rewrite it as follows, execute online

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import "fmt"

type age interface {
  int8 | int16 | int32 | int64 | float32 | float64
}

func show[num age](s1 num) {
  val := float64(s1) + 1
  fmt.Println(val)
}

func main() {
  fmt.Println("go 1.18 Generics Example")

  var sum1 int64 = 28
  var sum2 float64 = 29.5

  show(sum1)
  show(sum2)
}

Define a new interface in the code and put all types into it

1
2
3
type age interface {
  int8 | int16 | int32 | int64 | float32 | float64
}

If you want to support multiple parameters you can write it like this

1
2
3
4
func total[num age](s1, s2 num) {
  val := float64(s1) + float64(s2)
  fmt.Println(val)
}

This way you can bring in two identical parameter types at the same time. If you want to bring in different types, the first parameter is int64 and the second is float64, please change it as follows

1
2
3
4
func summary[num1, num2 age](s1 num1, s2 num2) {
  val := float64(s1) + float64(s2)
  fmt.Println(val)
}

The full test code can be found below, Online Execution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import "fmt"

type age interface {
  int8 | int16 | int32 | int64 | float32 | float64
}

func newGenerics[num age](s1 num) {
  val := float64(s1) + 1
  fmt.Println(val)
}

func total[num age](s1, s2 num) {
  val := float64(s1) + float64(s2)
  fmt.Println(val)
}

func summary[num1, num2 age](s1 num1, s2 num2) {
  val := float64(s1) + float64(s2)
  fmt.Println(val)
}

func main() {
  fmt.Println("go 1.18 Generics Example")

  var sum1 int64 = 28
  var sum2 float64 = 29.5

  newGenerics(sum1)
  newGenerics(sum2)

  var sum3 float64 = 28
  var sum4 float64 = 29.5

  total(sum3, sum4)

  var sum5 int64 = 28
  var sum6 float64 = 29.5

  summary(sum5, sum6)
}

Finally, let’s look at an example bubble sort (Bubble sort)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

// conver to generics type to support int and float64 types
func bubbleSort(array []int) []int {
  for i := 0; i < len(array)-1; i++ {
    for j := 0; j < len(array)-i-1; j++ {
      if array[j] > array[j+1] {
        array[j], array[j+1] = array[j+1], array[j]
      }
    }
  }
  return array
}

func main() {
  array := []int{11, 14, 3, 8, 18, 17, 43}
  fmt.Println(bubbleSort(array))
}

In addition to int support, please also support float64. Please see the answer directly below, online execution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import "fmt"

// The Time Complexity of the Bubble Sort is O(n^2) since it takes two nested loops to check the adjacent element.
// For example, let’s take the following unsorted array −
// 22 15 11 45 13
// Bubble Sort Algorithm first traverses the whole array and then in another loop checks if the adjacent elements are in order or not.
// Thus, after sorting the elements will be,
// 11 13 15 22 45

// conver to generics type to support both int and float64 types

type Number interface {
  int | int32 | int64 | float32 | float64
}

func bubbleSort[n Number](array []n) []n {
  for i := 0; i < len(array)-1; i++ {
    for j := 0; j < len(array)-i-1; j++ {
      if array[j] > array[j+1] {
        array[j], array[j+1] = array[j+1], array[j]
      }
    }
  }
  return array
}

func main() {
  n1 := []int{11, 14, 3, 8, 18, 17, 43}
  fmt.Println(bubbleSort(n1))
  n2 := []float64{11.1, 14.2, 3.3, 8.4, 18.5, 17.6, 43.7}
  fmt.Println(bubbleSort(n2))

Thoughts

Finally, we have a chance to optimize some Package writing, but for backward compatibility, the original go1.17 writing will be retained, and the different environments will be determined by the go build tag method.