66

初探 golang 1.18 generics 功能

 2 years ago
source link: https://blog.wu-boy.com/2022/02/introduction-to-golang-1-18-generics/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

logo

Go 語言在近期內會推出 1.18 版本,而 1.18 最重要的功能之一就是 generics,在此版本之前,最令人詬病的就是 Go 無法支援多種 Type 當參數,造成在寫 Package 時候多出很多重複性的程式碼,本篇會教大家基礎認識什麼是 generics,及怎麼使用。

影片視頻會同步放到底下課程內

安裝 1.18 及整合 Vscode 編輯器

首先要先安裝 go1.18 beta2 版本,方式很簡單,請參考底下

go install golang.org/dl/go1.18beta2@latest
go1.18beta2 download

完成後可以透過底下指令看到 go1.18beta2

$ go1.18beta2 env GOROOT
/Users/mtk10671/sdk/go1.18beta2

如果要快速嘗試用 go 指令,可以直接透過 alias 指令

alias go=go1.18beta2

該如何整合到 Vscode 內呢?請參考這篇文章,幾個步驟就可以完成。第一個步驟就是請把 go1.18beta2 變成環境變數預設值 PATH,請改成

PATH="$HOME/sdk/go1.18beta2/bin:$PATH"

打開 VSCODE 編輯器,重新安裝全部 tools,直接 cmd + shift + p 選擇 Go: Install/Update Tools,把全部 toll 打勾重新安裝。最後步驟就是打開預設的 config.json 檔案加上

"gopls": {
  "ui.semanticTokens": true
}

使用 generic

我們來寫一個 func 支援一個參數,此參數可以是 int64float64 型態,線上執行

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)
}

大家可以看到 [num int64 | float64] 定義一個新的型態,此型態可以為 int64float64,再把這型態放到後面。不過如果支援型態很多的話,可以改寫如下,線上執行

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)
}

在程式碼內定義一個新的 interface 將所有型態放入即可

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

如果要支援多個參數可以怎麼寫

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

這樣就可以同時帶入兩個一樣的參數型態。如果要帶入不同的型態,第一個參數是 int64,第二個是 float64,請改成如下

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

完整測試程式碼可以參考底下,線上執行

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)
}

最後我們來看一個例子泡沫排序 (Bubble sort)

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))
}

除了支援 int 之外,也請支援 float64。請直接看底下解答,線上執行

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))
}

終於有機會可以優化一些 Package 的寫法,不過為了向下相容,原本的 go1.17 寫法還是會保留,透過 go build tag 方式來決定不同的使用環境即可。

golang 

See also


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK